@projectcaluma/ember-form 10.0.1 → 11.0.0-beta.10
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 +1181 -0
- package/addon/components/cf-content.hbs +36 -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 +18 -19
- package/addon/components/cf-field/input/action-button.js +9 -7
- 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 +8 -5
- package/addon/components/cf-field/input/date.js +28 -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 +45 -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
|
}
|
@@ -1,4 +1,10 @@
|
|
1
|
+
# We can not symlink this file so an exact copy exists in another package:
|
2
|
+
# packages/form-builder/addon/gql/fragments/field.graphql
|
3
|
+
#
|
4
|
+
# When changing this file the other must also receive the same changes.
|
5
|
+
|
1
6
|
fragment SimpleQuestion on Question {
|
7
|
+
id
|
2
8
|
slug
|
3
9
|
label
|
4
10
|
isRequired
|
@@ -9,22 +15,43 @@ fragment SimpleQuestion on Question {
|
|
9
15
|
textMinLength: minLength
|
10
16
|
textMaxLength: maxLength
|
11
17
|
textDefaultAnswer: defaultAnswer {
|
18
|
+
id
|
12
19
|
value
|
13
20
|
}
|
14
21
|
placeholder
|
22
|
+
formatValidators {
|
23
|
+
edges {
|
24
|
+
node {
|
25
|
+
slug
|
26
|
+
regex
|
27
|
+
errorMsg
|
28
|
+
}
|
29
|
+
}
|
30
|
+
}
|
15
31
|
}
|
16
32
|
... on TextareaQuestion {
|
17
33
|
textareaMinLength: minLength
|
18
34
|
textareaMaxLength: maxLength
|
19
35
|
textareaDefaultAnswer: defaultAnswer {
|
36
|
+
id
|
20
37
|
value
|
21
38
|
}
|
22
39
|
placeholder
|
40
|
+
formatValidators {
|
41
|
+
edges {
|
42
|
+
node {
|
43
|
+
slug
|
44
|
+
regex
|
45
|
+
errorMsg
|
46
|
+
}
|
47
|
+
}
|
48
|
+
}
|
23
49
|
}
|
24
50
|
... on IntegerQuestion {
|
25
51
|
integerMinValue: minValue
|
26
52
|
integerMaxValue: maxValue
|
27
53
|
integerDefaultAnswer: defaultAnswer {
|
54
|
+
id
|
28
55
|
value
|
29
56
|
}
|
30
57
|
placeholder
|
@@ -33,6 +60,7 @@ fragment SimpleQuestion on Question {
|
|
33
60
|
floatMinValue: minValue
|
34
61
|
floatMaxValue: maxValue
|
35
62
|
floatDefaultAnswer: defaultAnswer {
|
63
|
+
id
|
36
64
|
value
|
37
65
|
}
|
38
66
|
placeholder
|
@@ -41,6 +69,7 @@ fragment SimpleQuestion on Question {
|
|
41
69
|
choiceOptions: options {
|
42
70
|
edges {
|
43
71
|
node {
|
72
|
+
id
|
44
73
|
slug
|
45
74
|
label
|
46
75
|
isArchived
|
@@ -48,6 +77,7 @@ fragment SimpleQuestion on Question {
|
|
48
77
|
}
|
49
78
|
}
|
50
79
|
choiceDefaultAnswer: defaultAnswer {
|
80
|
+
id
|
51
81
|
value
|
52
82
|
}
|
53
83
|
}
|
@@ -55,6 +85,7 @@ fragment SimpleQuestion on Question {
|
|
55
85
|
multipleChoiceOptions: options {
|
56
86
|
edges {
|
57
87
|
node {
|
88
|
+
id
|
58
89
|
slug
|
59
90
|
label
|
60
91
|
isArchived
|
@@ -62,11 +93,13 @@ fragment SimpleQuestion on Question {
|
|
62
93
|
}
|
63
94
|
}
|
64
95
|
multipleChoiceDefaultAnswer: defaultAnswer {
|
96
|
+
id
|
65
97
|
value
|
66
98
|
}
|
67
99
|
}
|
68
100
|
... on DateQuestion {
|
69
101
|
dateDefaultAnswer: defaultAnswer {
|
102
|
+
id
|
70
103
|
value
|
71
104
|
}
|
72
105
|
}
|
@@ -84,8 +117,10 @@ fragment SimpleQuestion on Question {
|
|
84
117
|
}
|
85
118
|
|
86
119
|
fragment FieldTableQuestion on Question {
|
120
|
+
id
|
87
121
|
... on TableQuestion {
|
88
122
|
rowForm {
|
123
|
+
id
|
89
124
|
slug
|
90
125
|
questions {
|
91
126
|
edges {
|
@@ -96,6 +131,7 @@ fragment FieldTableQuestion on Question {
|
|
96
131
|
}
|
97
132
|
}
|
98
133
|
tableDefaultAnswer: defaultAnswer {
|
134
|
+
id
|
99
135
|
value {
|
100
136
|
id
|
101
137
|
answers {
|
@@ -103,6 +139,7 @@ fragment FieldTableQuestion on Question {
|
|
103
139
|
node {
|
104
140
|
id
|
105
141
|
question {
|
142
|
+
id
|
106
143
|
slug
|
107
144
|
}
|
108
145
|
... on StringAnswer {
|
@@ -129,10 +166,12 @@ fragment FieldTableQuestion on Question {
|
|
129
166
|
}
|
130
167
|
|
131
168
|
fragment FieldQuestion on Question {
|
169
|
+
id
|
132
170
|
...SimpleQuestion
|
133
171
|
...FieldTableQuestion
|
134
172
|
... on FormQuestion {
|
135
173
|
subForm {
|
174
|
+
id
|
136
175
|
slug
|
137
176
|
name
|
138
177
|
questions {
|
@@ -140,10 +179,12 @@ fragment FieldQuestion on Question {
|
|
140
179
|
node {
|
141
180
|
# This part here limits our query to 2 level deep nested forms. This
|
142
181
|
# has to be solved in another way!
|
182
|
+
id
|
143
183
|
...SimpleQuestion
|
144
184
|
...FieldTableQuestion
|
145
185
|
... on FormQuestion {
|
146
186
|
subForm {
|
187
|
+
id
|
147
188
|
slug
|
148
189
|
name
|
149
190
|
questions {
|
@@ -166,6 +207,7 @@ fragment FieldQuestion on Question {
|
|
166
207
|
fragment SimpleAnswer on Answer {
|
167
208
|
id
|
168
209
|
question {
|
210
|
+
id
|
169
211
|
slug
|
170
212
|
}
|
171
213
|
... on StringAnswer {
|
@@ -182,6 +224,7 @@ fragment SimpleAnswer on Answer {
|
|
182
224
|
}
|
183
225
|
... on FileAnswer {
|
184
226
|
fileValue: value {
|
227
|
+
id
|
185
228
|
uploadUrl
|
186
229
|
downloadUrl
|
187
230
|
metadata
|
@@ -194,11 +237,13 @@ fragment SimpleAnswer on Answer {
|
|
194
237
|
}
|
195
238
|
|
196
239
|
fragment FieldAnswer on Answer {
|
240
|
+
id
|
197
241
|
...SimpleAnswer
|
198
242
|
... on TableAnswer {
|
199
243
|
tableValue: value {
|
200
244
|
id
|
201
245
|
form {
|
246
|
+
id
|
202
247
|
slug
|
203
248
|
questions {
|
204
249
|
edges {
|