@projectcaluma/ember-form 11.0.0-beta.3 → 11.0.0-beta.7
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 +39 -0
- package/addon/components/cf-field/info.hbs +2 -2
- package/addon/components/cf-field/info.js +0 -15
- package/addon/components/cf-field/input/static.hbs +1 -1
- package/addon/components/cf-field/input/table.hbs +19 -19
- package/addon/components/cf-field.hbs +8 -4
- package/addon/components/cf-field.js +25 -6
- package/addon/components/document-validity.js +16 -1
- package/addon/gql/fragments/field.graphql +18 -0
- package/addon/lib/field.js +46 -13
- package/package.json +11 -10
package/CHANGELOG.md
CHANGED
@@ -1,3 +1,42 @@
|
|
1
|
+
# [@projectcaluma/ember-form-v11.0.0-beta.7](https://github.com/projectcaluma/ember-caluma/compare/@projectcaluma/ember-form-v11.0.0-beta.6...@projectcaluma/ember-form-v11.0.0-beta.7) (2022-02-03)
|
2
|
+
|
3
|
+
|
4
|
+
### Bug Fixes
|
5
|
+
|
6
|
+
* **validation:** sync format validator validation with backend ([ee66968](https://github.com/projectcaluma/ember-caluma/commit/ee66968230b9f0e4c5a4df8bdb3f8e58b44b5b82))
|
7
|
+
|
8
|
+
|
9
|
+
### BREAKING CHANGES
|
10
|
+
|
11
|
+
* **validation:** Use the `formatValidators` property of the backend to store and read
|
12
|
+
format validators instead of the `meta.formatValidators` so the backend
|
13
|
+
validates as well. For more information on how to migrate check the
|
14
|
+
migration guide to v11.
|
15
|
+
|
16
|
+
# [@projectcaluma/ember-form-v11.0.0-beta.6](https://github.com/projectcaluma/ember-caluma/compare/@projectcaluma/ember-form-v11.0.0-beta.5...@projectcaluma/ember-form-v11.0.0-beta.6) (2022-02-02)
|
17
|
+
|
18
|
+
|
19
|
+
### Bug Fixes
|
20
|
+
|
21
|
+
* **action-button:** hide field wrapper if action button is not displayed ([1d4b701](https://github.com/projectcaluma/ember-caluma/commit/1d4b701af35d48d072001f3295b905b1065daffe))
|
22
|
+
* render static questions ([28fff94](https://github.com/projectcaluma/ember-caluma/commit/28fff9487e4ad3153fe267db4b66208ad858aaac))
|
23
|
+
* **table:** fix styling of table fields ([30c5903](https://github.com/projectcaluma/ember-caluma/commit/30c590389ed82c37ebf666f1484501c66ca8f0bb))
|
24
|
+
|
25
|
+
# [@projectcaluma/ember-form-v11.0.0-beta.5](https://github.com/projectcaluma/ember-caluma/compare/@projectcaluma/ember-form-v11.0.0-beta.4...@projectcaluma/ember-form-v11.0.0-beta.5) (2022-02-01)
|
26
|
+
|
27
|
+
|
28
|
+
### Bug Fixes
|
29
|
+
|
30
|
+
* **document-validity:** wait to validate until the UI has finished saving values ([9ec5330](https://github.com/projectcaluma/ember-caluma/commit/9ec5330905046604f95ab42985a29a5e0dc369a4))
|
31
|
+
* **form:** use component save task instead of field for loading indicator ([6de510d](https://github.com/projectcaluma/ember-caluma/commit/6de510d19a3608b7cd40092908d562a152ef03bd))
|
32
|
+
|
33
|
+
# [@projectcaluma/ember-form-v11.0.0-beta.4](https://github.com/projectcaluma/ember-caluma/compare/@projectcaluma/ember-form-v11.0.0-beta.3...@projectcaluma/ember-form-v11.0.0-beta.4) (2022-02-01)
|
34
|
+
|
35
|
+
|
36
|
+
### Bug Fixes
|
37
|
+
|
38
|
+
* **form:** fix closing of info modal ([b46095a](https://github.com/projectcaluma/ember-caluma/commit/b46095aa3b31bc1b2035a0818778edaa8fd9c745))
|
39
|
+
|
1
40
|
# [@projectcaluma/ember-form-v11.0.0-beta.3](https://github.com/projectcaluma/ember-caluma/compare/@projectcaluma/ember-form-v11.0.0-beta.2...@projectcaluma/ember-form-v11.0.0-beta.3) (2022-01-24)
|
2
41
|
|
3
42
|
|
@@ -4,7 +4,7 @@
|
|
4
4
|
class="uk-icon-button"
|
5
5
|
uk-icon="info"
|
6
6
|
title={{t "caluma.form.info"}}
|
7
|
-
{{on "click" this.
|
7
|
+
{{on "click" (fn (mut this.modalVisible) true)}}
|
8
8
|
>
|
9
9
|
<span class="uk-hidden">{{t "caluma.form.info"}}</span>
|
10
10
|
</button>
|
@@ -12,7 +12,7 @@
|
|
12
12
|
<UkModal
|
13
13
|
@visible={{this.modalVisible}}
|
14
14
|
@stack={{true}}
|
15
|
-
@onHide={{this.
|
15
|
+
@onHide={{fn (mut this.modalVisible) false}}
|
16
16
|
as |modal|
|
17
17
|
>
|
18
18
|
<modal.body>
|
@@ -1,21 +1,6 @@
|
|
1
|
-
import { action } from "@ember/object";
|
2
1
|
import Component from "@glimmer/component";
|
3
2
|
import { tracked } from "@glimmer/tracking";
|
4
3
|
|
5
4
|
export default class CfFieldInfoComponent extends Component {
|
6
5
|
@tracked modalVisible = false;
|
7
|
-
|
8
|
-
@action
|
9
|
-
showModal(e) {
|
10
|
-
e.preventDefault();
|
11
|
-
|
12
|
-
this.modalVisible = true;
|
13
|
-
}
|
14
|
-
|
15
|
-
@action
|
16
|
-
hideModal(e) {
|
17
|
-
e.preventDefault();
|
18
|
-
|
19
|
-
this.modalVisible = false;
|
20
|
-
}
|
21
6
|
}
|
@@ -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 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 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
|
-
@color="default"
|
60
|
+
@color="link"
|
62
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>
|
@@ -86,7 +86,7 @@
|
|
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"}}
|
@@ -1,5 +1,9 @@
|
|
1
1
|
{{#if this.visible}}
|
2
|
-
<div
|
2
|
+
<div
|
3
|
+
class="uk-margin"
|
4
|
+
{{did-insert this.registerComponent}}
|
5
|
+
{{will-destroy this.unregisterComponent}}
|
6
|
+
>
|
3
7
|
{{#if this.labelVisible}}
|
4
8
|
<CfField::label @field={{@field}} />
|
5
9
|
{{/if}}
|
@@ -24,11 +28,11 @@
|
|
24
28
|
<div
|
25
29
|
class="cf-field__icon uk-padding-remove-vertical uk-flex uk-flex-middle uk-flex-center"
|
26
30
|
>
|
27
|
-
{{#if
|
31
|
+
{{#if this.save.isRunning}}
|
28
32
|
<UkSpinner class="uk-animation-fade" />
|
29
|
-
{{else if (or
|
33
|
+
{{else if (or this.save.last.isError @field.isInvalid)}}
|
30
34
|
<UkIcon @icon="warning" class="uk-animation-fade uk-text-danger" />
|
31
|
-
{{else if
|
35
|
+
{{else if this.save.last.isSuccessful}}
|
32
36
|
<UkIcon @icon="check" class="uk-animation-fade uk-text-success" />
|
33
37
|
{{/if}}
|
34
38
|
</div>
|
@@ -1,5 +1,5 @@
|
|
1
1
|
import { getOwner } from "@ember/application";
|
2
|
-
import {
|
2
|
+
import { action } from "@ember/object";
|
3
3
|
import Component from "@glimmer/component";
|
4
4
|
import { timeout, restartableTask } from "ember-concurrency";
|
5
5
|
|
@@ -18,10 +18,24 @@ import { hasQuestionType } from "@projectcaluma/ember-core/helpers/has-question-
|
|
18
18
|
* @argument {Field} field The field data model to render
|
19
19
|
*/
|
20
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
|
+
|
21
31
|
get visible() {
|
22
32
|
return (
|
23
33
|
!this.args.field?.hidden &&
|
24
|
-
!hasQuestionType(this.args.field?.question, "form")
|
34
|
+
!hasQuestionType(this.args.field?.question, "form") &&
|
35
|
+
!(
|
36
|
+
hasQuestionType(this.args.field?.question, "action-button") &&
|
37
|
+
this.args.disabled
|
38
|
+
)
|
25
39
|
);
|
26
40
|
}
|
27
41
|
|
@@ -41,8 +55,9 @@ export default class CfFieldComponent extends Component {
|
|
41
55
|
}
|
42
56
|
|
43
57
|
/**
|
44
|
-
* Task to save a field. This will set the passed value to the answer and
|
45
|
-
*
|
58
|
+
* Task to save a field. This will set the passed value to the answer and save
|
59
|
+
* the field to the API after a timeout of 500 milliseconds which intends to
|
60
|
+
* reduce the amount of saved values when changed rapidly.
|
46
61
|
*
|
47
62
|
* @method save
|
48
63
|
* @param {String|Number|String[]} value
|
@@ -57,14 +72,18 @@ export default class CfFieldComponent extends Component {
|
|
57
72
|
yield timeout(500);
|
58
73
|
}
|
59
74
|
|
60
|
-
|
75
|
+
if (this.args.field.answer) {
|
76
|
+
this.args.field.answer.value = value;
|
77
|
+
}
|
61
78
|
|
62
79
|
yield this.args.field.validate.perform();
|
63
80
|
|
64
81
|
try {
|
82
|
+
// Save the new field value unlinked so the fields save task is not
|
83
|
+
// aborted when this component is destroyed
|
65
84
|
return yield this.args.field.save.unlinked().perform();
|
66
85
|
} catch (e) {
|
67
|
-
//
|
86
|
+
// The component was destroyed before the fields save task was finished
|
68
87
|
}
|
69
88
|
}
|
70
89
|
}
|
@@ -1,6 +1,7 @@
|
|
1
1
|
import { action } from "@ember/object";
|
2
2
|
import Component from "@glimmer/component";
|
3
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
|
}
|
@@ -19,6 +19,15 @@ fragment SimpleQuestion on Question {
|
|
19
19
|
value
|
20
20
|
}
|
21
21
|
placeholder
|
22
|
+
formatValidators {
|
23
|
+
edges {
|
24
|
+
node {
|
25
|
+
slug
|
26
|
+
regex
|
27
|
+
errorMsg
|
28
|
+
}
|
29
|
+
}
|
30
|
+
}
|
22
31
|
}
|
23
32
|
... on TextareaQuestion {
|
24
33
|
textareaMinLength: minLength
|
@@ -28,6 +37,15 @@ fragment SimpleQuestion on Question {
|
|
28
37
|
value
|
29
38
|
}
|
30
39
|
placeholder
|
40
|
+
formatValidators {
|
41
|
+
edges {
|
42
|
+
node {
|
43
|
+
slug
|
44
|
+
regex
|
45
|
+
errorMsg
|
46
|
+
}
|
47
|
+
}
|
48
|
+
}
|
31
49
|
}
|
32
50
|
... on IntegerQuestion {
|
33
51
|
integerMinValue: minValue
|
package/addon/lib/field.js
CHANGED
@@ -3,6 +3,7 @@ import { assert } from "@ember/debug";
|
|
3
3
|
import { associateDestroyableChild } from "@ember/destroyable";
|
4
4
|
import { inject as service } from "@ember/service";
|
5
5
|
import { camelize } from "@ember/string";
|
6
|
+
import { isEmpty } from "@ember/utils";
|
6
7
|
import { tracked } from "@glimmer/tracking";
|
7
8
|
import { queryManager } from "ember-apollo-client";
|
8
9
|
import { restartableTask, lastValue, dropTask } from "ember-concurrency";
|
@@ -63,7 +64,6 @@ const fieldIsHiddenOrEmpty = (field) => {
|
|
63
64
|
*/
|
64
65
|
export default class Field extends Base {
|
65
66
|
@service intl;
|
66
|
-
@service validator;
|
67
67
|
|
68
68
|
@queryManager apollo;
|
69
69
|
|
@@ -152,6 +152,16 @@ export default class Field extends Base {
|
|
152
152
|
*/
|
153
153
|
@tracked _errors = [];
|
154
154
|
|
155
|
+
/**
|
156
|
+
* Currently rendered field components that use this field. This is used in
|
157
|
+
* the document validity component to await all current save tasks before
|
158
|
+
* validating.
|
159
|
+
*
|
160
|
+
* @property {Set} _components
|
161
|
+
* @private
|
162
|
+
*/
|
163
|
+
_components = new Set();
|
164
|
+
|
155
165
|
/**
|
156
166
|
* The primary key of the field. Consists of the document and question primary
|
157
167
|
* keys.
|
@@ -618,6 +628,35 @@ export default class Field extends Base {
|
|
618
628
|
this._errors = errors;
|
619
629
|
}
|
620
630
|
|
631
|
+
/**
|
632
|
+
* Validate the value against the regexes of the given format validators.
|
633
|
+
*
|
634
|
+
* @method _validateFormatValidators
|
635
|
+
* @return {Array<Boolean|Object>} An array of error objects or `true`
|
636
|
+
* @private
|
637
|
+
*/
|
638
|
+
_validateFormatValidators() {
|
639
|
+
const validators =
|
640
|
+
this.question.raw.formatValidators?.edges.map((edge) => edge.node) ?? [];
|
641
|
+
const value = this.answer.value;
|
642
|
+
|
643
|
+
if (isEmpty(value)) {
|
644
|
+
// empty values should not be validated since they are handled by the
|
645
|
+
// requiredness validation
|
646
|
+
return validators.map(() => true);
|
647
|
+
}
|
648
|
+
|
649
|
+
return validators.map((validator) => {
|
650
|
+
return (
|
651
|
+
new RegExp(validator.regex).test(value) || {
|
652
|
+
type: "format",
|
653
|
+
context: { errorMsg: validator.errorMsg },
|
654
|
+
value,
|
655
|
+
}
|
656
|
+
);
|
657
|
+
});
|
658
|
+
}
|
659
|
+
|
621
660
|
/**
|
622
661
|
* Method to validate if a question is required or not.
|
623
662
|
*
|
@@ -637,15 +676,12 @@ export default class Field extends Base {
|
|
637
676
|
* predefined by the question.
|
638
677
|
*
|
639
678
|
* @method _validateTextQuestion
|
640
|
-
* @return {
|
679
|
+
* @return {Array<Boolean|Object>} An array of error objects or `true`
|
641
680
|
* @private
|
642
681
|
*/
|
643
|
-
|
682
|
+
_validateTextQuestion() {
|
644
683
|
return [
|
645
|
-
...
|
646
|
-
this.answer.value,
|
647
|
-
this.question.raw.meta.formatValidators ?? []
|
648
|
-
)),
|
684
|
+
...this._validateFormatValidators(),
|
649
685
|
validate("length", this.answer.value, {
|
650
686
|
min: this.question.raw.textMinLength || 0,
|
651
687
|
max: this.question.raw.textMaxLength || Number.POSITIVE_INFINITY,
|
@@ -658,15 +694,12 @@ export default class Field extends Base {
|
|
658
694
|
* than predefined by the question.
|
659
695
|
*
|
660
696
|
* @method _validateTextareaQuestion
|
661
|
-
* @return {
|
697
|
+
* @return {Array<Boolean|Object>} An array of error objects or `true`
|
662
698
|
* @private
|
663
699
|
*/
|
664
|
-
|
700
|
+
_validateTextareaQuestion() {
|
665
701
|
return [
|
666
|
-
...
|
667
|
-
this.answer.value,
|
668
|
-
this.question.raw.meta.formatValidators ?? []
|
669
|
-
)),
|
702
|
+
...this._validateFormatValidators(),
|
670
703
|
validate("length", this.answer.value, {
|
671
704
|
min: this.question.raw.textareaMinLength || 0,
|
672
705
|
max: this.question.raw.textareaMaxLength || Number.POSITIVE_INFINITY,
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@projectcaluma/ember-form",
|
3
|
-
"version": "11.0.0-beta.
|
3
|
+
"version": "11.0.0-beta.7",
|
4
4
|
"description": "Ember addon for rendering Caluma forms.",
|
5
5
|
"keywords": [
|
6
6
|
"ember-addon"
|
@@ -16,7 +16,7 @@
|
|
16
16
|
"dependencies": {
|
17
17
|
"@glimmer/component": "^1.0.4",
|
18
18
|
"@glimmer/tracking": "^1.0.4",
|
19
|
-
"@projectcaluma/ember-core": "^11.0.0-beta.
|
19
|
+
"@projectcaluma/ember-core": "^11.0.0-beta.3",
|
20
20
|
"ember-apollo-client": "^3.2.0",
|
21
21
|
"ember-auto-import": "^2.4.0",
|
22
22
|
"ember-autoresize-modifier": "^0.5.0",
|
@@ -24,15 +24,16 @@
|
|
24
24
|
"ember-cli-htmlbars": "^6.0.1",
|
25
25
|
"ember-cli-showdown": "^6.0.1",
|
26
26
|
"ember-composable-helpers": "^5.0.0",
|
27
|
+
"ember-concurrency": "^2.2.0",
|
27
28
|
"ember-fetch": "^8.1.1",
|
28
29
|
"ember-in-viewport": "^4.0.0",
|
29
30
|
"ember-intl": "^5.7.2",
|
30
|
-
"ember-math-helpers": "^2.18.
|
31
|
+
"ember-math-helpers": "^2.18.1",
|
31
32
|
"ember-pikaday": "^3.0.0",
|
32
33
|
"ember-power-select": "^5.0.3",
|
33
|
-
"ember-resources": "^4.
|
34
|
-
"ember-uikit": "^5.0.0-beta.
|
35
|
-
"ember-validators": "^4.0
|
34
|
+
"ember-resources": "^4.2.0",
|
35
|
+
"ember-uikit": "^5.0.0-beta.11",
|
36
|
+
"ember-validators": "^4.1.0",
|
36
37
|
"graphql": "^15.8.0",
|
37
38
|
"jexl": "^2.3.0",
|
38
39
|
"lodash.isequal": "^4.5.0",
|
@@ -43,9 +44,9 @@
|
|
43
44
|
"@ember/optional-features": "2.0.0",
|
44
45
|
"@ember/test-helpers": "2.6.0",
|
45
46
|
"@embroider/test-setup": "1.0.0",
|
46
|
-
"@faker-js/faker": "6.0.0-alpha.
|
47
|
-
"@projectcaluma/ember-testing": "
|
48
|
-
"@projectcaluma/ember-workflow": "11.0.0-beta.
|
47
|
+
"@faker-js/faker": "6.0.0-alpha.5",
|
48
|
+
"@projectcaluma/ember-testing": "11.0.0-beta.1",
|
49
|
+
"@projectcaluma/ember-workflow": "11.0.0-beta.3",
|
49
50
|
"broccoli-asset-rev": "3.0.0",
|
50
51
|
"ember-cli": "3.28.5",
|
51
52
|
"ember-cli-code-coverage": "1.0.3",
|
@@ -69,7 +70,7 @@
|
|
69
70
|
"qunit": "2.17.2",
|
70
71
|
"qunit-dom": "2.0.0",
|
71
72
|
"uuid": "8.3.2",
|
72
|
-
"webpack": "5.
|
73
|
+
"webpack": "5.68.0"
|
73
74
|
},
|
74
75
|
"engines": {
|
75
76
|
"node": "12.* || 14.* || >= 16"
|