@projectcaluma/ember-form 14.7.0 → 14.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.
|
@@ -3,7 +3,7 @@ import { destroy, registerDestructor } from "@ember/destroyable";
|
|
|
3
3
|
import { inject as service } from "@ember/service";
|
|
4
4
|
import Component from "@glimmer/component";
|
|
5
5
|
import { queryManager } from "ember-apollo-client";
|
|
6
|
-
import {
|
|
6
|
+
import { task } from "ember-concurrency";
|
|
7
7
|
import { trackedTask } from "reactiveweb/ember-concurrency";
|
|
8
8
|
|
|
9
9
|
import getDocumentAnswersQuery from "@projectcaluma/ember-form/gql/queries/document-answers.graphql";
|
|
@@ -125,32 +125,33 @@ export default class CfContentComponent extends Component {
|
|
|
125
125
|
);
|
|
126
126
|
}
|
|
127
127
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
@dropTask
|
|
131
|
-
*fetchData() {
|
|
128
|
+
fetchData = task({ drop: true }, async () => {
|
|
132
129
|
if (this.document) destroy(this.document);
|
|
133
130
|
if (this.navigation) destroy(this.navigation);
|
|
134
131
|
|
|
135
132
|
if (!this.args.documentId) return;
|
|
136
133
|
|
|
137
|
-
const [answerDocument] = (
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
134
|
+
const [answerDocument] = (
|
|
135
|
+
await this.apollo.query(
|
|
136
|
+
{
|
|
137
|
+
query: getDocumentAnswersQuery,
|
|
138
|
+
fetchPolicy: "network-only",
|
|
139
|
+
variables: { id: this.args.documentId },
|
|
140
|
+
},
|
|
141
|
+
"allDocuments.edges",
|
|
142
|
+
)
|
|
143
|
+
).map(({ node }) => node);
|
|
144
|
+
|
|
145
|
+
const [form] = (
|
|
146
|
+
await this.apollo.query(
|
|
147
|
+
{
|
|
148
|
+
query: getDocumentFormsQuery,
|
|
149
|
+
fetchPolicy: "cache-first",
|
|
150
|
+
variables: { slug: answerDocument.form.slug },
|
|
151
|
+
},
|
|
152
|
+
"allForms.edges",
|
|
153
|
+
)
|
|
154
|
+
).map(({ node }) => node);
|
|
154
155
|
|
|
155
156
|
const owner = getOwner(this);
|
|
156
157
|
const Document = owner.factoryFor("caluma-model:document").class;
|
|
@@ -171,5 +172,7 @@ export default class CfContentComponent extends Component {
|
|
|
171
172
|
});
|
|
172
173
|
|
|
173
174
|
return { document, navigation };
|
|
174
|
-
}
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
data = trackedTask(this, this.fetchData, () => [this.args.documentId]);
|
|
175
178
|
}
|
|
@@ -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 {
|
|
7
|
+
import { task } from "ember-concurrency";
|
|
8
8
|
import { confirm } from "ember-uikit";
|
|
9
9
|
|
|
10
10
|
import removeDocumentMutation from "@projectcaluma/ember-form/gql/mutations/remove-document.graphql";
|
|
@@ -44,9 +44,8 @@ export default class CfFieldInputTableComponent extends Component {
|
|
|
44
44
|
return this.questions.slice(0, 4);
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
const raw = yield this.apollo.mutate(
|
|
47
|
+
add = task({ drop: true }, async () => {
|
|
48
|
+
const raw = await this.apollo.mutate(
|
|
50
49
|
{
|
|
51
50
|
mutation: saveDocumentMutation,
|
|
52
51
|
variables: {
|
|
@@ -66,11 +65,10 @@ export default class CfFieldInputTableComponent extends Component {
|
|
|
66
65
|
this.documentToEditIsNew = true;
|
|
67
66
|
this.documentToEdit = newDocument;
|
|
68
67
|
this.showAddModal = true;
|
|
69
|
-
}
|
|
68
|
+
});
|
|
70
69
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
if (!(yield confirm(this.intl.t("caluma.form.deleteRow")))) {
|
|
70
|
+
delete = task({ drop: true }, async (document) => {
|
|
71
|
+
if (!(await confirm(this.intl.t("caluma.form.deleteRow")))) {
|
|
74
72
|
return;
|
|
75
73
|
}
|
|
76
74
|
|
|
@@ -78,20 +76,19 @@ export default class CfFieldInputTableComponent extends Component {
|
|
|
78
76
|
(doc) => doc.pk !== document.pk,
|
|
79
77
|
);
|
|
80
78
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
}
|
|
79
|
+
await this.args.onSave(remainingDocuments);
|
|
80
|
+
await this.removeOrphan(document);
|
|
81
|
+
});
|
|
84
82
|
|
|
85
|
-
|
|
86
|
-
*save(validate) {
|
|
83
|
+
save = task({ drop: true }, async (validate) => {
|
|
87
84
|
try {
|
|
88
|
-
if (!(
|
|
85
|
+
if (!(await validate())) {
|
|
89
86
|
return;
|
|
90
87
|
}
|
|
91
88
|
|
|
92
89
|
const newDocument = this.documentToEdit;
|
|
93
90
|
|
|
94
|
-
|
|
91
|
+
await Promise.all(newDocument.fields.map((f) => f.validate.perform()));
|
|
95
92
|
|
|
96
93
|
if (newDocument.fields.some((field) => field.isInvalid)) {
|
|
97
94
|
return;
|
|
@@ -101,7 +98,7 @@ export default class CfFieldInputTableComponent extends Component {
|
|
|
101
98
|
|
|
102
99
|
if (!rows.find((doc) => doc.pk === newDocument.pk)) {
|
|
103
100
|
// add document to table
|
|
104
|
-
|
|
101
|
+
await this.args.onSave([...rows, newDocument]);
|
|
105
102
|
|
|
106
103
|
this.notification.success(
|
|
107
104
|
this.intl.t("caluma.form.notification.table.add.success"),
|
|
@@ -110,29 +107,28 @@ export default class CfFieldInputTableComponent extends Component {
|
|
|
110
107
|
|
|
111
108
|
this.documentToEditIsNew = false;
|
|
112
109
|
|
|
113
|
-
|
|
110
|
+
await this.close.perform();
|
|
114
111
|
} catch {
|
|
115
112
|
this.notification.danger(
|
|
116
113
|
this.intl.t("caluma.form.notification.table.add.error"),
|
|
117
114
|
);
|
|
118
115
|
}
|
|
119
|
-
}
|
|
116
|
+
});
|
|
120
117
|
|
|
121
|
-
|
|
122
|
-
*close() {
|
|
118
|
+
close = task({ drop: true }, async () => {
|
|
123
119
|
if (this.documentToEditIsNew) {
|
|
124
|
-
|
|
120
|
+
await this.removeOrphan(this.documentToEdit);
|
|
125
121
|
|
|
126
122
|
this.documentToEditIsNew = false;
|
|
127
123
|
}
|
|
128
124
|
|
|
129
125
|
if (!this.args.disabled) {
|
|
130
|
-
|
|
126
|
+
await this.args.field.validate.perform();
|
|
131
127
|
}
|
|
132
128
|
|
|
133
129
|
this.showAddModal = false;
|
|
134
130
|
this.documentToEdit = null;
|
|
135
|
-
}
|
|
131
|
+
});
|
|
136
132
|
|
|
137
133
|
async removeOrphan(calumaDocument) {
|
|
138
134
|
// Remove orphaned document from database.
|
|
@@ -2,7 +2,7 @@ import { action } from "@ember/object";
|
|
|
2
2
|
import { service } from "@ember/service";
|
|
3
3
|
import { macroCondition, isTesting } from "@embroider/macros";
|
|
4
4
|
import Component from "@glimmer/component";
|
|
5
|
-
import { timeout,
|
|
5
|
+
import { timeout, task } from "ember-concurrency";
|
|
6
6
|
|
|
7
7
|
import { hasQuestionType } from "@projectcaluma/ember-core/helpers/has-question-type";
|
|
8
8
|
|
|
@@ -88,22 +88,21 @@ export default class CfFieldComponent extends Component {
|
|
|
88
88
|
* @method save
|
|
89
89
|
* @param {String|Number|String[]} value The new value to save to the field
|
|
90
90
|
*/
|
|
91
|
-
|
|
92
|
-
*save(value) {
|
|
91
|
+
save = task({ restartable: true }, async (value) => {
|
|
93
92
|
if (typeof this.args.onSave === "function") {
|
|
94
|
-
return
|
|
93
|
+
return await this.args.onSave(this.args.field, value);
|
|
95
94
|
}
|
|
96
95
|
|
|
97
96
|
/* istanbul ignore next */
|
|
98
97
|
if (macroCondition(!isTesting())) {
|
|
99
|
-
|
|
98
|
+
await timeout(500);
|
|
100
99
|
}
|
|
101
100
|
|
|
102
101
|
if (this.args.field.answer) {
|
|
103
102
|
this.args.field.answer.value = value;
|
|
104
103
|
}
|
|
105
104
|
|
|
106
|
-
|
|
105
|
+
await this.args.field.validate.perform();
|
|
107
106
|
|
|
108
107
|
if (this.args.field.isInvalid) {
|
|
109
108
|
// If the frontend validation fails, we don't need to try saving the value
|
|
@@ -111,8 +110,8 @@ export default class CfFieldComponent extends Component {
|
|
|
111
110
|
return;
|
|
112
111
|
}
|
|
113
112
|
|
|
114
|
-
return
|
|
115
|
-
}
|
|
113
|
+
return await this.args.field.save.unlinked().perform();
|
|
114
|
+
});
|
|
116
115
|
|
|
117
116
|
@action
|
|
118
117
|
refreshDynamicOptions() {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { action } from "@ember/object";
|
|
2
2
|
import Component from "@glimmer/component";
|
|
3
|
-
import {
|
|
3
|
+
import { task } from "ember-concurrency";
|
|
4
4
|
import { cached } from "tracked-toolbox";
|
|
5
5
|
|
|
6
6
|
/**
|
|
@@ -43,8 +43,15 @@ export default class DocumentValidity extends Component {
|
|
|
43
43
|
return this._validate.isRunning;
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
-
|
|
47
|
-
|
|
46
|
+
_validateField = task(async (field) => {
|
|
47
|
+
await field.validate.linked().perform();
|
|
48
|
+
|
|
49
|
+
if (field.question.hasFormatValidators) {
|
|
50
|
+
await field.save.linked().perform();
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
_validate = task({ restartable: true }, async () => {
|
|
48
55
|
const saveTasks = this.args.document.fields
|
|
49
56
|
.flatMap((field) => [
|
|
50
57
|
...[...(field._components ?? [])].map((c) => c.save.last),
|
|
@@ -54,16 +61,12 @@ export default class DocumentValidity extends Component {
|
|
|
54
61
|
|
|
55
62
|
// Wait until all currently running save tasks in the UI and in the field
|
|
56
63
|
// itself are finished
|
|
57
|
-
|
|
64
|
+
await Promise.all(saveTasks);
|
|
58
65
|
|
|
59
|
-
|
|
60
|
-
this.args.document.fields.map(
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
if (field.question.hasFormatValidators) {
|
|
64
|
-
await field.save.linked().perform();
|
|
65
|
-
}
|
|
66
|
-
}),
|
|
66
|
+
await Promise.all(
|
|
67
|
+
this.args.document.fields.map((field) =>
|
|
68
|
+
this._validateField.perform(field),
|
|
69
|
+
),
|
|
67
70
|
);
|
|
68
71
|
|
|
69
72
|
if (this.isValid) {
|
|
@@ -73,7 +76,7 @@ export default class DocumentValidity extends Component {
|
|
|
73
76
|
}
|
|
74
77
|
|
|
75
78
|
return this.isValid;
|
|
76
|
-
}
|
|
79
|
+
});
|
|
77
80
|
|
|
78
81
|
@action
|
|
79
82
|
validate() {
|
package/addon/lib/field.js
CHANGED
|
@@ -5,7 +5,7 @@ import { inject as service } from "@ember/service";
|
|
|
5
5
|
import { camelize } from "@ember/string";
|
|
6
6
|
import { tracked } from "@glimmer/tracking";
|
|
7
7
|
import { queryManager } from "ember-apollo-client";
|
|
8
|
-
import {
|
|
8
|
+
import { task } from "ember-concurrency";
|
|
9
9
|
import { validate } from "ember-validators";
|
|
10
10
|
import isEqual from "lodash.isequal";
|
|
11
11
|
import { cached } from "tracked-toolbox";
|
|
@@ -325,11 +325,10 @@ export default class Field extends Base {
|
|
|
325
325
|
* @return {Object[]} Formerly used dynamic options
|
|
326
326
|
* @private
|
|
327
327
|
*/
|
|
328
|
-
|
|
329
|
-
*_fetchUsedDynamicOptions() {
|
|
328
|
+
_fetchUsedDynamicOptions = task({ drop: true }, async () => {
|
|
330
329
|
if (!this.question.isDynamic) return null;
|
|
331
330
|
|
|
332
|
-
const edges =
|
|
331
|
+
const edges = await this.apollo.query(
|
|
333
332
|
{
|
|
334
333
|
query: getDocumentUsedDynamicOptionsQuery,
|
|
335
334
|
fetchPolicy: "cache-first",
|
|
@@ -345,15 +344,16 @@ export default class Field extends Base {
|
|
|
345
344
|
slug,
|
|
346
345
|
label,
|
|
347
346
|
}));
|
|
348
|
-
}
|
|
347
|
+
});
|
|
349
348
|
|
|
350
349
|
/**
|
|
351
350
|
* The formerly used dynamic options for this question.
|
|
352
351
|
*
|
|
353
352
|
* @property {Object[]} usedDynamicOptions
|
|
354
353
|
*/
|
|
355
|
-
|
|
356
|
-
|
|
354
|
+
get usedDynamicOptions() {
|
|
355
|
+
return this._fetchUsedDynamicOptions.lastSuccessful?.value;
|
|
356
|
+
}
|
|
357
357
|
|
|
358
358
|
/**
|
|
359
359
|
* The available options for choice questions. This only works for the
|
|
@@ -606,8 +606,7 @@ export default class Field extends Base {
|
|
|
606
606
|
* @method save
|
|
607
607
|
* @return {Object} The response from the server
|
|
608
608
|
*/
|
|
609
|
-
|
|
610
|
-
*save() {
|
|
609
|
+
save = task({ restartable: true }, async () => {
|
|
611
610
|
if (this.question.isCalculated) {
|
|
612
611
|
return;
|
|
613
612
|
}
|
|
@@ -629,7 +628,7 @@ export default class Field extends Base {
|
|
|
629
628
|
}
|
|
630
629
|
|
|
631
630
|
try {
|
|
632
|
-
const response =
|
|
631
|
+
const response = await this.apollo.mutate(
|
|
633
632
|
{
|
|
634
633
|
mutation: MUTATION_MAP[type],
|
|
635
634
|
variables: { input },
|
|
@@ -672,7 +671,7 @@ export default class Field extends Base {
|
|
|
672
671
|
throw e;
|
|
673
672
|
}
|
|
674
673
|
}
|
|
675
|
-
}
|
|
674
|
+
});
|
|
676
675
|
|
|
677
676
|
/**
|
|
678
677
|
* The translated error messages
|
|
@@ -696,8 +695,7 @@ export default class Field extends Base {
|
|
|
696
695
|
*
|
|
697
696
|
* @method validate
|
|
698
697
|
*/
|
|
699
|
-
|
|
700
|
-
*validate() {
|
|
698
|
+
validate = task({ restartable: true }, async () => {
|
|
701
699
|
const specificValidation = this[`_validate${this.questionType}`];
|
|
702
700
|
|
|
703
701
|
assert(
|
|
@@ -710,22 +708,23 @@ export default class Field extends Base {
|
|
|
710
708
|
specificValidation,
|
|
711
709
|
];
|
|
712
710
|
|
|
713
|
-
const errors = (
|
|
714
|
-
|
|
715
|
-
|
|
711
|
+
const errors = (
|
|
712
|
+
await Promise.all(
|
|
713
|
+
validationFns.map(async (fn) => {
|
|
714
|
+
const res = await fn.call(this);
|
|
716
715
|
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
716
|
+
return Array.isArray(res) ? res : [res];
|
|
717
|
+
}),
|
|
718
|
+
)
|
|
719
|
+
)
|
|
720
720
|
.reduce((arr, e) => [...arr, ...e], []) // flatten the array
|
|
721
721
|
.filter((e) => typeof e === "object");
|
|
722
722
|
|
|
723
723
|
this._errors = errors;
|
|
724
|
-
}
|
|
724
|
+
});
|
|
725
725
|
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
const response = yield this.apollo.query(
|
|
726
|
+
refreshAnswer = task({ drop: true }, async () => {
|
|
727
|
+
const response = await this.apollo.query(
|
|
729
728
|
{
|
|
730
729
|
query: refreshAnswerQuery,
|
|
731
730
|
fetchPolicy: "network-only",
|
|
@@ -744,9 +743,9 @@ export default class Field extends Base {
|
|
|
744
743
|
this.answer.raw[key] = value;
|
|
745
744
|
});
|
|
746
745
|
|
|
747
|
-
|
|
746
|
+
await this.validate.linked().perform();
|
|
748
747
|
}
|
|
749
|
-
}
|
|
748
|
+
});
|
|
750
749
|
|
|
751
750
|
/**
|
|
752
751
|
* Method to validate if a question is required or not.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@projectcaluma/ember-form",
|
|
3
|
-
"version": "14.7.
|
|
3
|
+
"version": "14.7.1",
|
|
4
4
|
"description": "Ember addon for rendering Caluma forms.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ember-addon"
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"ember-cli-htmlbars": "^6.3.0",
|
|
23
23
|
"ember-cli-showdown": "^9.0.1",
|
|
24
24
|
"ember-composable-helpers": "^5.0.0",
|
|
25
|
-
"ember-concurrency": "^4.0.2",
|
|
25
|
+
"ember-concurrency": "^4.0.2 || ^5.1.0",
|
|
26
26
|
"ember-flatpickr": "^8.0.1",
|
|
27
27
|
"ember-in-viewport": "^4.1.0",
|
|
28
28
|
"ember-intl": "^7.1.1",
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"luxon": "^3.5.0",
|
|
40
40
|
"reactiveweb": "^1.3.0",
|
|
41
41
|
"tracked-toolbox": "^2.0.0",
|
|
42
|
-
"@projectcaluma/ember-core": "^14.7.
|
|
42
|
+
"@projectcaluma/ember-core": "^14.7.1"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
45
|
"@ember/optional-features": "2.3.0",
|
|
@@ -74,12 +74,12 @@
|
|
|
74
74
|
"uikit": "3.25.6",
|
|
75
75
|
"uuid": "13.0.0",
|
|
76
76
|
"webpack": "5.104.1",
|
|
77
|
-
"@projectcaluma/ember-testing": "14.7.
|
|
78
|
-
"@projectcaluma/ember-workflow": "14.7.
|
|
77
|
+
"@projectcaluma/ember-testing": "14.7.1",
|
|
78
|
+
"@projectcaluma/ember-workflow": "14.7.1"
|
|
79
79
|
},
|
|
80
80
|
"peerDependencies": {
|
|
81
81
|
"ember-source": ">= 4.0.0",
|
|
82
|
-
"@projectcaluma/ember-workflow": "^14.7.
|
|
82
|
+
"@projectcaluma/ember-workflow": "^14.7.1"
|
|
83
83
|
},
|
|
84
84
|
"dependenciesMeta": {
|
|
85
85
|
"@projectcaluma/ember-core": {
|