@projectcaluma/ember-form 10.0.2 → 11.0.0-beta.11
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/CHANGELOG.md +1194 -0
- package/addon/components/cf-content.hbs +38 -41
- package/addon/components/cf-content.js +48 -29
- package/addon/components/cf-field/info.hbs +2 -2
- package/addon/components/cf-field/info.js +0 -15
- package/addon/components/cf-field/input/action-button.hbs +17 -19
- package/addon/components/cf-field/input/action-button.js +6 -10
- package/addon/components/cf-field/input/checkbox.hbs +6 -2
- package/addon/components/cf-field/input/checkbox.js +9 -29
- package/addon/components/cf-field/input/date.hbs +9 -5
- package/addon/components/cf-field/input/date.js +31 -10
- package/addon/components/cf-field/input/file.hbs +2 -2
- package/addon/components/cf-field/input/file.js +10 -11
- package/addon/components/cf-field/input/float.hbs +4 -4
- package/addon/components/cf-field/input/integer.hbs +5 -5
- package/addon/components/cf-field/input/radio.hbs +4 -1
- package/addon/components/cf-field/input/static.hbs +1 -1
- package/addon/components/cf-field/input/table.hbs +24 -24
- package/addon/components/cf-field/input/table.js +12 -10
- package/addon/components/cf-field/input/text.hbs +5 -5
- package/addon/components/cf-field/input/textarea.hbs +6 -5
- package/addon/components/cf-field/input.hbs +10 -1
- package/addon/components/cf-field/input.js +1 -1
- package/addon/components/cf-field/label.hbs +1 -1
- package/addon/components/cf-field-value.hbs +22 -7
- package/addon/components/cf-field-value.js +8 -38
- package/addon/components/cf-field.hbs +14 -6
- package/addon/components/cf-field.js +22 -8
- package/addon/components/cf-navigation-item.hbs +2 -2
- package/addon/components/cf-navigation.hbs +4 -1
- package/addon/components/document-validity.js +17 -2
- package/addon/gql/fragments/field.graphql +40 -0
- package/addon/gql/mutations/save-document-table-answer.graphql +1 -1
- package/addon/gql/mutations/save-document.graphql +1 -0
- package/addon/gql/queries/{get-document-answers.graphql → document-answers.graphql} +2 -1
- package/addon/gql/queries/{get-document-forms.graphql → document-forms.graphql} +2 -1
- package/addon/gql/queries/{get-document-used-dynamic-options.graphql → document-used-dynamic-options.graphql} +2 -1
- package/addon/gql/queries/{get-dynamic-options.graphql → dynamic-options.graphql} +2 -1
- package/addon/gql/queries/{get-fileanswer-info.graphql → fileanswer-info.graphql} +2 -1
- package/addon/helpers/get-widget.js +50 -0
- package/addon/lib/answer.js +108 -72
- package/addon/lib/base.js +32 -23
- package/addon/lib/dependencies.js +36 -71
- package/addon/lib/document.js +92 -96
- package/addon/lib/field.js +374 -407
- package/addon/lib/fieldset.js +46 -47
- package/addon/lib/form.js +27 -15
- package/addon/lib/navigation.js +211 -192
- package/addon/lib/question.js +103 -94
- package/addon/services/caluma-store.js +10 -6
- package/app/helpers/get-widget.js +4 -0
- package/blueprints/@projectcaluma/ember-form/index.js +1 -0
- package/package.json +30 -25
- package/addon/components/cf-navigation.js +0 -9
- package/addon/instance-initializers/setup-pikaday-i18n.js +0 -35
@@ -1,4 +1,4 @@
|
|
1
|
-
<table class="uk-table uk-table-divider">
|
1
|
+
<table class="uk-table uk-table-divider uk-margin-remove-vertical">
|
2
2
|
<thead>
|
3
3
|
<tr>
|
4
4
|
{{#each this.columns as |column|}}
|
@@ -25,27 +25,27 @@
|
|
25
25
|
class="uk-animation-fade uk-text-danger"
|
26
26
|
/>
|
27
27
|
{{/if}}
|
28
|
-
<
|
29
|
-
|
30
|
-
|
31
|
-
class="uk-button-link uk-flex-inline uk-margin-small-left"
|
28
|
+
<UkButton
|
29
|
+
@color="link"
|
30
|
+
@onClick={{fn this.edit document}}
|
32
31
|
title={{t "caluma.form.edit"}}
|
33
|
-
|
32
|
+
class="uk-flex-inline uk-margin-small-left"
|
33
|
+
data-test-edit-row
|
34
34
|
>
|
35
35
|
<UkIcon @icon="pencil" />
|
36
|
-
<span
|
37
|
-
</
|
36
|
+
<span hidden>{{t "caluma.form.edit"}}</span>
|
37
|
+
</UkButton>
|
38
38
|
{{#unless @disabled}}
|
39
|
-
<
|
40
|
-
|
41
|
-
|
42
|
-
class="uk-button-link uk-flex-inline uk-margin-small-left"
|
39
|
+
<UkButton
|
40
|
+
@color="link"
|
41
|
+
@onClick={{fn (perform this.delete) document}}
|
43
42
|
title={{t "caluma.form.delete"}}
|
44
|
-
|
43
|
+
class="uk-flex-inline uk-margin-small-left"
|
44
|
+
data-test-delete-row
|
45
45
|
>
|
46
46
|
<UkIcon @icon="trash" />
|
47
|
-
<span
|
48
|
-
</
|
47
|
+
<span hidden>{{t "caluma.form.delete"}}</span>
|
48
|
+
</UkButton>
|
49
49
|
{{/unless}}
|
50
50
|
</div>
|
51
51
|
</td>
|
@@ -57,13 +57,13 @@
|
|
57
57
|
<tr>
|
58
58
|
<td colspan={{add this.columns.length 1}} class="uk-text-center">
|
59
59
|
<UkButton
|
60
|
-
@
|
61
|
-
@
|
62
|
-
|
60
|
+
@color="link"
|
61
|
+
@onClick={{perform this.add}}
|
62
|
+
title={{t "caluma.form.addRow"}}
|
63
63
|
data-test-add-row
|
64
64
|
>
|
65
65
|
<UkIcon @icon="plus" />
|
66
|
-
<span
|
66
|
+
<span hidden>{{t "caluma.form.addRow"}}</span>
|
67
67
|
</UkButton>
|
68
68
|
</td>
|
69
69
|
</tr>
|
@@ -74,7 +74,7 @@
|
|
74
74
|
{{#if this.documentToEdit}}
|
75
75
|
<UkModal
|
76
76
|
@visible={{this.showAddModal}}
|
77
|
-
@
|
77
|
+
@onHide={{perform this.close}}
|
78
78
|
@bgClose={{false}}
|
79
79
|
as |modal|
|
80
80
|
>
|
@@ -86,12 +86,12 @@
|
|
86
86
|
/>
|
87
87
|
</modal.body>
|
88
88
|
|
89
|
-
<modal.footer
|
89
|
+
<modal.footer class="uk-text-right">
|
90
90
|
{{#if @disabled}}
|
91
91
|
<UkButton
|
92
92
|
@label={{t "caluma.form.close"}}
|
93
93
|
@color="primary"
|
94
|
-
@
|
94
|
+
@onClick={{perform this.close}}
|
95
95
|
@disabled={{this.close.isRunning}}
|
96
96
|
@loading={{this.close.isRunning}}
|
97
97
|
data-test-close
|
@@ -99,7 +99,7 @@
|
|
99
99
|
{{else}}
|
100
100
|
<UkButton
|
101
101
|
@label={{t "caluma.form.cancel"}}
|
102
|
-
@
|
102
|
+
@onClick={{perform this.close}}
|
103
103
|
@disabled={{this.close.isRunning}}
|
104
104
|
@loading={{this.close.isRunning}}
|
105
105
|
data-test-cancel
|
@@ -114,7 +114,7 @@
|
|
114
114
|
@type="submit"
|
115
115
|
@disabled={{or this.save.isRunning (not isValid)}}
|
116
116
|
@loading={{this.save.isRunning}}
|
117
|
-
@
|
117
|
+
@onClick={{fn (perform this.save) validate}}
|
118
118
|
data-test-save
|
119
119
|
/>
|
120
120
|
</DocumentValidity>
|
@@ -4,7 +4,7 @@ import { inject as service } from "@ember/service";
|
|
4
4
|
import Component from "@glimmer/component";
|
5
5
|
import { tracked } from "@glimmer/tracking";
|
6
6
|
import { queryManager } from "ember-apollo-client";
|
7
|
-
import { dropTask } from "ember-concurrency
|
7
|
+
import { dropTask } from "ember-concurrency";
|
8
8
|
import UIkit from "uikit";
|
9
9
|
|
10
10
|
import removeDocumentMutation from "@projectcaluma/ember-form/gql/mutations/remove-document.graphql";
|
@@ -37,13 +37,13 @@ export default class CfFieldInputTableComponent extends Component {
|
|
37
37
|
}
|
38
38
|
|
39
39
|
get questions() {
|
40
|
-
return this.args.field.question.rowForm.questions.edges.map(
|
40
|
+
return this.args.field.question.raw.rowForm.questions.edges.map(
|
41
41
|
(edge) => edge.node
|
42
42
|
);
|
43
43
|
}
|
44
44
|
|
45
45
|
get columns() {
|
46
|
-
const config = this.args.field.question.meta.columnsToDisplay;
|
46
|
+
const config = this.args.field.question.raw.meta.columnsToDisplay;
|
47
47
|
|
48
48
|
if (config?.length) {
|
49
49
|
return this.questions.filter((question) =>
|
@@ -59,17 +59,19 @@ export default class CfFieldInputTableComponent extends Component {
|
|
59
59
|
const raw = yield this.apollo.mutate(
|
60
60
|
{
|
61
61
|
mutation: saveDocumentMutation,
|
62
|
-
variables: {
|
62
|
+
variables: {
|
63
|
+
input: { form: this.args.field.question.raw.rowForm.slug },
|
64
|
+
},
|
63
65
|
},
|
64
66
|
"saveDocument.document"
|
65
67
|
);
|
66
68
|
|
67
|
-
const
|
68
|
-
|
69
|
-
.
|
70
|
-
|
71
|
-
|
72
|
-
|
69
|
+
const owner = getOwner(this);
|
70
|
+
const newDocument = new (owner.factoryFor("caluma-model:document").class)({
|
71
|
+
raw: this.parseDocument(raw),
|
72
|
+
parentDocument: this.args.field.document,
|
73
|
+
owner,
|
74
|
+
});
|
73
75
|
|
74
76
|
this.documentToEditIsNew = true;
|
75
77
|
this.documentToEdit = newDocument;
|
@@ -1,14 +1,14 @@
|
|
1
1
|
<input
|
2
2
|
type="text"
|
3
3
|
class="uk-input
|
4
|
-
{{if @field.isInvalid
|
5
|
-
{{if @disabled
|
4
|
+
{{if @field.isInvalid 'uk-form-danger'}}
|
5
|
+
{{if @disabled 'uk-disabled'}}"
|
6
6
|
name={{@field.pk}}
|
7
7
|
id={{@field.pk}}
|
8
8
|
value={{@field.answer.value}}
|
9
|
-
placeholder={{@field.question.placeholder}}
|
9
|
+
placeholder={{@field.question.raw.placeholder}}
|
10
10
|
readonly={{@disabled}}
|
11
|
-
minlength={{@field.question.textMinLength}}
|
12
|
-
maxlength={{@field.question.textMaxLength}}
|
11
|
+
minlength={{@field.question.raw.textMinLength}}
|
12
|
+
maxlength={{@field.question.raw.textMaxLength}}
|
13
13
|
{{on "input" this.input}}
|
14
14
|
/>
|
@@ -1,12 +1,13 @@
|
|
1
1
|
<textarea
|
2
2
|
class="uk-textarea
|
3
|
-
{{if @field.isInvalid
|
4
|
-
{{if @disabled
|
3
|
+
{{if @field.isInvalid 'uk-form-danger'}}
|
4
|
+
{{if @disabled 'uk-disabled'}}"
|
5
5
|
name={{@field.pk}}
|
6
6
|
id={{@field.pk}}
|
7
|
-
placeholder={{@field.question.placeholder}}
|
8
|
-
minlength={{@field.question.textareaMinLength}}
|
9
|
-
maxlength={{@field.question.textareaMaxLength}}
|
7
|
+
placeholder={{@field.question.raw.placeholder}}
|
8
|
+
minlength={{@field.question.raw.textareaMinLength}}
|
9
|
+
maxlength={{@field.question.raw.textareaMaxLength}}
|
10
10
|
readonly={{@disabled}}
|
11
11
|
{{on "input" this.input}}
|
12
|
+
{{autoresize mode="height"}}
|
12
13
|
>{{@field.answer.value}}</textarea>
|
@@ -1,6 +1,15 @@
|
|
1
1
|
{{#if this.type}}
|
2
2
|
{{#let (component (concat "cf-field/input/" this.type)) as |InputComponent|}}
|
3
|
-
<div
|
3
|
+
<div
|
4
|
+
class="uk-form-controls
|
5
|
+
{{if
|
6
|
+
(and
|
7
|
+
(has-question-type @field.question 'multiple-choice' 'choice')
|
8
|
+
@field.question.raw.meta.vertical
|
9
|
+
)
|
10
|
+
'uk-flex'
|
11
|
+
}}"
|
12
|
+
>
|
4
13
|
<InputComponent
|
5
14
|
@field={{@field}}
|
6
15
|
@disabled={{@disabled}}
|
@@ -1,9 +1,24 @@
|
|
1
|
-
{{#if
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
1
|
+
{{#if (has-question-type @field.question "choice" "dynamic-choice")}}
|
2
|
+
{{@field.selected.label}}
|
3
|
+
{{else if (has-question-type
|
4
|
+
@field.question "multiple-choice" "multiple-dynamic-choice"
|
5
|
+
)}}
|
6
|
+
{{#each @field.selected as |opt i|}}{{if (gt i 0) ", "}}{{opt.label}}{{/each}}
|
7
|
+
{{else if (has-question-type @field.question "date")}}
|
8
|
+
{{format-date
|
9
|
+
@field.answer.value
|
10
|
+
day="2-digit"
|
11
|
+
month="2-digit"
|
12
|
+
year="numeric"
|
13
|
+
}}
|
14
|
+
{{else if (has-question-type @field.question "file")}}
|
15
|
+
{{#if @field.answer.value}}
|
16
|
+
<UkButton
|
17
|
+
@color="link"
|
18
|
+
@label={{@field.answer.value.name}}
|
19
|
+
@onClick={{fn this.download @field.answer.raw.id}}
|
20
|
+
/>
|
21
|
+
{{/if}}
|
7
22
|
{{else}}
|
8
|
-
{{
|
23
|
+
{{@field.answer.value}}
|
9
24
|
{{/if}}
|
@@ -1,55 +1,25 @@
|
|
1
1
|
import { action } from "@ember/object";
|
2
2
|
import Component from "@glimmer/component";
|
3
3
|
import { queryManager } from "ember-apollo-client";
|
4
|
-
import moment from "moment";
|
5
4
|
|
6
|
-
import getFileAnswerInfoQuery from "@projectcaluma/ember-form/gql/queries/
|
5
|
+
import getFileAnswerInfoQuery from "@projectcaluma/ember-form/gql/queries/fileanswer-info.graphql";
|
7
6
|
|
8
7
|
export default class CfFieldValueComponent extends Component {
|
9
8
|
@queryManager apollo;
|
10
9
|
|
11
|
-
get value() {
|
12
|
-
const field = this.args.field;
|
13
|
-
|
14
|
-
switch (field.question.__typename) {
|
15
|
-
case "ChoiceQuestion":
|
16
|
-
case "DynamicChoiceQuestion": {
|
17
|
-
return field.selected;
|
18
|
-
}
|
19
|
-
case "MultipleChoiceQuestion":
|
20
|
-
case "DynamicMultipleChoiceQuestion": {
|
21
|
-
return { label: field.selected.map(({ label }) => label).join(", ") };
|
22
|
-
}
|
23
|
-
case "FileQuestion": {
|
24
|
-
const answerValue = field.answer.value;
|
25
|
-
return {
|
26
|
-
fileAnswerId: answerValue && field.answer.id,
|
27
|
-
label: answerValue && answerValue.name,
|
28
|
-
};
|
29
|
-
}
|
30
|
-
case "DateQuestion": {
|
31
|
-
return {
|
32
|
-
label: field.answer.value && moment(field.answer.value).format("L"),
|
33
|
-
};
|
34
|
-
}
|
35
|
-
|
36
|
-
default:
|
37
|
-
return {
|
38
|
-
label: field.answer.value,
|
39
|
-
};
|
40
|
-
}
|
41
|
-
}
|
42
|
-
|
43
10
|
@action
|
44
|
-
async download(
|
11
|
+
async download(id) {
|
45
12
|
const { downloadUrl } = await this.apollo.query(
|
46
13
|
{
|
47
14
|
query: getFileAnswerInfoQuery,
|
48
|
-
variables: { id
|
49
|
-
fetchPolicy: "
|
15
|
+
variables: { id },
|
16
|
+
fetchPolicy: "network-only",
|
50
17
|
},
|
51
18
|
"node.fileValue"
|
52
19
|
);
|
53
|
-
|
20
|
+
|
21
|
+
if (downloadUrl) {
|
22
|
+
window.open(downloadUrl, "_blank");
|
23
|
+
}
|
54
24
|
}
|
55
25
|
}
|
@@ -1,5 +1,13 @@
|
|
1
1
|
{{#if this.visible}}
|
2
|
-
<div
|
2
|
+
<div
|
3
|
+
class="uk-margin
|
4
|
+
{{if
|
5
|
+
(and @disabled (has-question-type @field.question 'action-button'))
|
6
|
+
'uk-hidden'
|
7
|
+
}}"
|
8
|
+
{{did-insert this.registerComponent}}
|
9
|
+
{{will-destroy this.unregisterComponent}}
|
10
|
+
>
|
3
11
|
{{#if this.labelVisible}}
|
4
12
|
<CfField::label @field={{@field}} />
|
5
13
|
{{/if}}
|
@@ -16,19 +24,19 @@
|
|
16
24
|
{{/let}}
|
17
25
|
</div>
|
18
26
|
|
19
|
-
{{#if (and @field.question.infoText this.infoTextVisible)}}
|
20
|
-
<CfField::info @text={{@field.question.infoText}} />
|
27
|
+
{{#if (and @field.question.raw.infoText this.infoTextVisible)}}
|
28
|
+
<CfField::info @text={{@field.question.raw.infoText}} />
|
21
29
|
{{/if}}
|
22
30
|
|
23
31
|
{{#if this.saveIndicatorVisible}}
|
24
32
|
<div
|
25
33
|
class="cf-field__icon uk-padding-remove-vertical uk-flex uk-flex-middle uk-flex-center"
|
26
34
|
>
|
27
|
-
{{#if
|
35
|
+
{{#if this.save.isRunning}}
|
28
36
|
<UkSpinner class="uk-animation-fade" />
|
29
|
-
{{else if (or
|
37
|
+
{{else if (or this.save.last.isError @field.isInvalid)}}
|
30
38
|
<UkIcon @icon="warning" class="uk-animation-fade uk-text-danger" />
|
31
|
-
{{else if
|
39
|
+
{{else if this.save.last.isSuccessful}}
|
32
40
|
<UkIcon @icon="check" class="uk-animation-fade uk-text-success" />
|
33
41
|
{{/if}}
|
34
42
|
</div>
|
@@ -1,8 +1,7 @@
|
|
1
1
|
import { getOwner } from "@ember/application";
|
2
|
-
import {
|
2
|
+
import { action } from "@ember/object";
|
3
3
|
import Component from "@glimmer/component";
|
4
|
-
import { timeout } from "ember-concurrency";
|
5
|
-
import { restartableTask } from "ember-concurrency-decorators";
|
4
|
+
import { timeout, restartableTask } from "ember-concurrency";
|
6
5
|
|
7
6
|
import { hasQuestionType } from "@projectcaluma/ember-core/helpers/has-question-type";
|
8
7
|
|
@@ -19,6 +18,16 @@ import { hasQuestionType } from "@projectcaluma/ember-core/helpers/has-question-
|
|
19
18
|
* @argument {Field} field The field data model to render
|
20
19
|
*/
|
21
20
|
export default class CfFieldComponent extends Component {
|
21
|
+
@action
|
22
|
+
registerComponent() {
|
23
|
+
this.args.field._components.add(this);
|
24
|
+
}
|
25
|
+
|
26
|
+
@action
|
27
|
+
unregisterComponent() {
|
28
|
+
this.args.field._components.delete(this);
|
29
|
+
}
|
30
|
+
|
22
31
|
get visible() {
|
23
32
|
return (
|
24
33
|
!this.args.field?.hidden &&
|
@@ -28,7 +37,7 @@ export default class CfFieldComponent extends Component {
|
|
28
37
|
|
29
38
|
get labelVisible() {
|
30
39
|
return (
|
31
|
-
!this.args.field?.question.meta.hideLabel &&
|
40
|
+
!this.args.field?.question.raw.meta.hideLabel &&
|
32
41
|
!hasQuestionType(this.args.field?.question, "static", "action-button")
|
33
42
|
);
|
34
43
|
}
|
@@ -42,8 +51,9 @@ export default class CfFieldComponent extends Component {
|
|
42
51
|
}
|
43
52
|
|
44
53
|
/**
|
45
|
-
* Task to save a field. This will set the passed value to the answer and
|
46
|
-
*
|
54
|
+
* Task to save a field. This will set the passed value to the answer and save
|
55
|
+
* the field to the API after a timeout of 500 milliseconds which intends to
|
56
|
+
* reduce the amount of saved values when changed rapidly.
|
47
57
|
*
|
48
58
|
* @method save
|
49
59
|
* @param {String|Number|String[]} value
|
@@ -58,14 +68,18 @@ export default class CfFieldComponent extends Component {
|
|
58
68
|
yield timeout(500);
|
59
69
|
}
|
60
70
|
|
61
|
-
|
71
|
+
if (this.args.field.answer) {
|
72
|
+
this.args.field.answer.value = value;
|
73
|
+
}
|
62
74
|
|
63
75
|
yield this.args.field.validate.perform();
|
64
76
|
|
65
77
|
try {
|
78
|
+
// Save the new field value unlinked so the fields save task is not
|
79
|
+
// aborted when this component is destroyed
|
66
80
|
return yield this.args.field.save.unlinked().perform();
|
67
81
|
} catch (e) {
|
68
|
-
//
|
82
|
+
// The component was destroyed before the fields save task was finished
|
69
83
|
}
|
70
84
|
}
|
71
85
|
}
|
@@ -1,6 +1,6 @@
|
|
1
1
|
<li
|
2
2
|
class="cf-navigation__item uk-width-auto
|
3
|
-
{{if (or @item.active @item.childrenActive)
|
3
|
+
{{if (or @item.active @item.childrenActive) 'uk-active'}}"
|
4
4
|
>
|
5
5
|
<LinkTo @query={{hash displayedForm=@item.slug}}>
|
6
6
|
{{#if (and @useAsHeading this.active)}}
|
@@ -19,7 +19,7 @@
|
|
19
19
|
{{/if}}
|
20
20
|
<span
|
21
21
|
class="cf-navigation__item__icon cf-navigation__item__icon--{{@item.state}}
|
22
|
-
{{if @item.dirty
|
22
|
+
{{if @item.dirty 'cf-navigation__item__icon--dirty'}}"
|
23
23
|
></span>
|
24
24
|
</LinkTo>
|
25
25
|
|
@@ -1,4 +1,7 @@
|
|
1
|
-
<ul
|
1
|
+
<ul
|
2
|
+
class="uk-tab uk-tab-left uk-width-auto"
|
3
|
+
{{did-insert @navigation.goToNextItemIfNonNavigable}}
|
4
|
+
>
|
2
5
|
{{#each @navigation.rootItems as |item|}}
|
3
6
|
<CfNavigationItem
|
4
7
|
@item={{item}}
|
@@ -1,6 +1,7 @@
|
|
1
1
|
import { action } from "@ember/object";
|
2
2
|
import Component from "@glimmer/component";
|
3
|
-
import { restartableTask } from "ember-concurrency
|
3
|
+
import { restartableTask } from "ember-concurrency";
|
4
|
+
import { cached } from "tracked-toolbox";
|
4
5
|
|
5
6
|
/**
|
6
7
|
* Component to check the validity of a document
|
@@ -31,12 +32,26 @@ export default class DocumentValidity extends Component {
|
|
31
32
|
* @argument {Boolean} validateOnEnter
|
32
33
|
*/
|
33
34
|
|
35
|
+
@cached
|
34
36
|
get isValid() {
|
35
|
-
return this.args.document.fields
|
37
|
+
return this.args.document.fields
|
38
|
+
.filter((f) => !f.hidden)
|
39
|
+
.every((f) => f.isValid);
|
36
40
|
}
|
37
41
|
|
38
42
|
@restartableTask
|
39
43
|
*_validate() {
|
44
|
+
const saveTasks = this.args.document.fields
|
45
|
+
.flatMap((field) => [
|
46
|
+
...[...(field._components ?? [])].map((c) => c.save.last),
|
47
|
+
field.save?.last,
|
48
|
+
])
|
49
|
+
.filter(Boolean);
|
50
|
+
|
51
|
+
// Wait until all currently running save tasks in the UI and in the field
|
52
|
+
// itself are finished
|
53
|
+
yield Promise.all(saveTasks);
|
54
|
+
|
40
55
|
for (const field of this.args.document.fields) {
|
41
56
|
yield field.validate.linked().perform();
|
42
57
|
}
|
@@ -4,6 +4,7 @@
|
|
4
4
|
# When changing this file the other must also receive the same changes.
|
5
5
|
|
6
6
|
fragment SimpleQuestion on Question {
|
7
|
+
id
|
7
8
|
slug
|
8
9
|
label
|
9
10
|
isRequired
|
@@ -14,22 +15,43 @@ fragment SimpleQuestion on Question {
|
|
14
15
|
textMinLength: minLength
|
15
16
|
textMaxLength: maxLength
|
16
17
|
textDefaultAnswer: defaultAnswer {
|
18
|
+
id
|
17
19
|
value
|
18
20
|
}
|
19
21
|
placeholder
|
22
|
+
formatValidators {
|
23
|
+
edges {
|
24
|
+
node {
|
25
|
+
slug
|
26
|
+
regex
|
27
|
+
errorMsg
|
28
|
+
}
|
29
|
+
}
|
30
|
+
}
|
20
31
|
}
|
21
32
|
... on TextareaQuestion {
|
22
33
|
textareaMinLength: minLength
|
23
34
|
textareaMaxLength: maxLength
|
24
35
|
textareaDefaultAnswer: defaultAnswer {
|
36
|
+
id
|
25
37
|
value
|
26
38
|
}
|
27
39
|
placeholder
|
40
|
+
formatValidators {
|
41
|
+
edges {
|
42
|
+
node {
|
43
|
+
slug
|
44
|
+
regex
|
45
|
+
errorMsg
|
46
|
+
}
|
47
|
+
}
|
48
|
+
}
|
28
49
|
}
|
29
50
|
... on IntegerQuestion {
|
30
51
|
integerMinValue: minValue
|
31
52
|
integerMaxValue: maxValue
|
32
53
|
integerDefaultAnswer: defaultAnswer {
|
54
|
+
id
|
33
55
|
value
|
34
56
|
}
|
35
57
|
placeholder
|
@@ -38,6 +60,7 @@ fragment SimpleQuestion on Question {
|
|
38
60
|
floatMinValue: minValue
|
39
61
|
floatMaxValue: maxValue
|
40
62
|
floatDefaultAnswer: defaultAnswer {
|
63
|
+
id
|
41
64
|
value
|
42
65
|
}
|
43
66
|
placeholder
|
@@ -46,6 +69,7 @@ fragment SimpleQuestion on Question {
|
|
46
69
|
choiceOptions: options {
|
47
70
|
edges {
|
48
71
|
node {
|
72
|
+
id
|
49
73
|
slug
|
50
74
|
label
|
51
75
|
isArchived
|
@@ -53,6 +77,7 @@ fragment SimpleQuestion on Question {
|
|
53
77
|
}
|
54
78
|
}
|
55
79
|
choiceDefaultAnswer: defaultAnswer {
|
80
|
+
id
|
56
81
|
value
|
57
82
|
}
|
58
83
|
}
|
@@ -60,6 +85,7 @@ fragment SimpleQuestion on Question {
|
|
60
85
|
multipleChoiceOptions: options {
|
61
86
|
edges {
|
62
87
|
node {
|
88
|
+
id
|
63
89
|
slug
|
64
90
|
label
|
65
91
|
isArchived
|
@@ -67,11 +93,13 @@ fragment SimpleQuestion on Question {
|
|
67
93
|
}
|
68
94
|
}
|
69
95
|
multipleChoiceDefaultAnswer: defaultAnswer {
|
96
|
+
id
|
70
97
|
value
|
71
98
|
}
|
72
99
|
}
|
73
100
|
... on DateQuestion {
|
74
101
|
dateDefaultAnswer: defaultAnswer {
|
102
|
+
id
|
75
103
|
value
|
76
104
|
}
|
77
105
|
}
|
@@ -89,8 +117,10 @@ fragment SimpleQuestion on Question {
|
|
89
117
|
}
|
90
118
|
|
91
119
|
fragment FieldTableQuestion on Question {
|
120
|
+
id
|
92
121
|
... on TableQuestion {
|
93
122
|
rowForm {
|
123
|
+
id
|
94
124
|
slug
|
95
125
|
questions {
|
96
126
|
edges {
|
@@ -101,6 +131,7 @@ fragment FieldTableQuestion on Question {
|
|
101
131
|
}
|
102
132
|
}
|
103
133
|
tableDefaultAnswer: defaultAnswer {
|
134
|
+
id
|
104
135
|
value {
|
105
136
|
id
|
106
137
|
answers {
|
@@ -108,6 +139,7 @@ fragment FieldTableQuestion on Question {
|
|
108
139
|
node {
|
109
140
|
id
|
110
141
|
question {
|
142
|
+
id
|
111
143
|
slug
|
112
144
|
}
|
113
145
|
... on StringAnswer {
|
@@ -134,10 +166,12 @@ fragment FieldTableQuestion on Question {
|
|
134
166
|
}
|
135
167
|
|
136
168
|
fragment FieldQuestion on Question {
|
169
|
+
id
|
137
170
|
...SimpleQuestion
|
138
171
|
...FieldTableQuestion
|
139
172
|
... on FormQuestion {
|
140
173
|
subForm {
|
174
|
+
id
|
141
175
|
slug
|
142
176
|
name
|
143
177
|
questions {
|
@@ -145,10 +179,12 @@ fragment FieldQuestion on Question {
|
|
145
179
|
node {
|
146
180
|
# This part here limits our query to 2 level deep nested forms. This
|
147
181
|
# has to be solved in another way!
|
182
|
+
id
|
148
183
|
...SimpleQuestion
|
149
184
|
...FieldTableQuestion
|
150
185
|
... on FormQuestion {
|
151
186
|
subForm {
|
187
|
+
id
|
152
188
|
slug
|
153
189
|
name
|
154
190
|
questions {
|
@@ -171,6 +207,7 @@ fragment FieldQuestion on Question {
|
|
171
207
|
fragment SimpleAnswer on Answer {
|
172
208
|
id
|
173
209
|
question {
|
210
|
+
id
|
174
211
|
slug
|
175
212
|
}
|
176
213
|
... on StringAnswer {
|
@@ -187,6 +224,7 @@ fragment SimpleAnswer on Answer {
|
|
187
224
|
}
|
188
225
|
... on FileAnswer {
|
189
226
|
fileValue: value {
|
227
|
+
id
|
190
228
|
uploadUrl
|
191
229
|
downloadUrl
|
192
230
|
metadata
|
@@ -199,11 +237,13 @@ fragment SimpleAnswer on Answer {
|
|
199
237
|
}
|
200
238
|
|
201
239
|
fragment FieldAnswer on Answer {
|
240
|
+
id
|
202
241
|
...SimpleAnswer
|
203
242
|
... on TableAnswer {
|
204
243
|
tableValue: value {
|
205
244
|
id
|
206
245
|
form {
|
246
|
+
id
|
207
247
|
slug
|
208
248
|
questions {
|
209
249
|
edges {
|