@projectcaluma/ember-form 10.0.2 → 11.0.0-beta.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. package/CHANGELOG.md +1112 -0
  2. package/addon/components/cf-content.hbs +36 -39
  3. package/addon/components/cf-content.js +48 -29
  4. package/addon/components/cf-field/info.hbs +1 -1
  5. package/addon/components/cf-field/input/action-button.hbs +1 -1
  6. package/addon/components/cf-field/input/action-button.js +9 -7
  7. package/addon/components/cf-field/input/checkbox.hbs +6 -2
  8. package/addon/components/cf-field/input/checkbox.js +9 -29
  9. package/addon/components/cf-field/input/file.hbs +1 -1
  10. package/addon/components/cf-field/input/file.js +8 -9
  11. package/addon/components/cf-field/input/float.hbs +4 -4
  12. package/addon/components/cf-field/input/integer.hbs +5 -5
  13. package/addon/components/cf-field/input/radio.hbs +4 -1
  14. package/addon/components/cf-field/input/table.hbs +7 -7
  15. package/addon/components/cf-field/input/table.js +12 -10
  16. package/addon/components/cf-field/input/text.hbs +5 -5
  17. package/addon/components/cf-field/input/textarea.hbs +6 -5
  18. package/addon/components/cf-field/input.hbs +10 -1
  19. package/addon/components/cf-field/input.js +1 -1
  20. package/addon/components/cf-field/label.hbs +1 -1
  21. package/addon/components/cf-field-value.hbs +1 -1
  22. package/addon/components/cf-field-value.js +8 -13
  23. package/addon/components/cf-field.hbs +2 -2
  24. package/addon/components/cf-field.js +2 -3
  25. package/addon/components/cf-navigation-item.hbs +2 -2
  26. package/addon/components/cf-navigation.hbs +4 -1
  27. package/addon/components/document-validity.js +1 -1
  28. package/addon/gql/fragments/field.graphql +22 -0
  29. package/addon/gql/mutations/save-document-table-answer.graphql +1 -1
  30. package/addon/gql/mutations/save-document.graphql +1 -0
  31. package/addon/gql/queries/{get-document-answers.graphql → document-answers.graphql} +2 -1
  32. package/addon/gql/queries/{get-document-forms.graphql → document-forms.graphql} +2 -1
  33. package/addon/gql/queries/{get-document-used-dynamic-options.graphql → document-used-dynamic-options.graphql} +2 -1
  34. package/addon/gql/queries/{get-dynamic-options.graphql → dynamic-options.graphql} +2 -1
  35. package/addon/gql/queries/{get-fileanswer-info.graphql → fileanswer-info.graphql} +2 -1
  36. package/addon/helpers/get-widget.js +50 -0
  37. package/addon/lib/answer.js +108 -72
  38. package/addon/lib/base.js +32 -23
  39. package/addon/lib/dependencies.js +36 -71
  40. package/addon/lib/document.js +92 -96
  41. package/addon/lib/field.js +334 -401
  42. package/addon/lib/fieldset.js +46 -47
  43. package/addon/lib/form.js +27 -15
  44. package/addon/lib/navigation.js +211 -192
  45. package/addon/lib/question.js +103 -94
  46. package/addon/services/caluma-store.js +10 -6
  47. package/app/helpers/get-widget.js +4 -0
  48. package/blueprints/@projectcaluma/ember-form/index.js +1 -0
  49. package/package.json +27 -23
  50. package/addon/components/cf-navigation.js +0 -9
@@ -1,11 +1,10 @@
1
1
  import { assert } from "@ember/debug";
2
- import { defineProperty, computed } from "@ember/object";
3
- import { reads, equal } from "@ember/object/computed";
4
2
  import { camelize } from "@ember/string";
5
3
  import { queryManager } from "ember-apollo-client";
6
- import { task } from "ember-concurrency";
4
+ import { dropTask, lastValue } from "ember-concurrency";
5
+ import { cached } from "tracked-toolbox";
7
6
 
8
- import getDynamicOptions from "@projectcaluma/ember-form/gql/queries/get-dynamic-options.graphql";
7
+ import getDynamicOptions from "@projectcaluma/ember-form/gql/queries/dynamic-options.graphql";
9
8
  import Base from "@projectcaluma/ember-form/lib/base";
10
9
 
11
10
  const getValue = (answer) => {
@@ -17,24 +16,39 @@ const getValue = (answer) => {
17
16
  *
18
17
  * @class Question
19
18
  */
20
- export default Base.extend({
21
- apollo: queryManager(),
19
+ export default class Question extends Base {
20
+ @queryManager apollo;
22
21
 
23
- init(...args) {
22
+ constructor({ raw, ...args }) {
24
23
  assert(
25
24
  "A graphql question `raw` must be passed",
26
- this.raw && /Question$/.test(this.raw.__typename)
25
+ /Question$/.test(raw?.__typename)
27
26
  );
28
27
 
29
- defineProperty(this, "pk", {
30
- writable: false,
31
- value: `Question:${this.raw.slug}`,
32
- });
28
+ super({ raw, ...args });
33
29
 
34
- this._super(...args);
30
+ this.pushIntoStore();
31
+ }
35
32
 
36
- this.setProperties(this.raw);
37
- },
33
+ /**
34
+ * The primary key of the question.
35
+ *
36
+ * @property {String} pk
37
+ */
38
+ @cached
39
+ get pk() {
40
+ return `Question:${this.slug}`;
41
+ }
42
+
43
+ /**
44
+ * The slug of the question.
45
+ *
46
+ * @property {String} slug
47
+ */
48
+ @cached
49
+ get slug() {
50
+ return this.raw.slug;
51
+ }
38
52
 
39
53
  /**
40
54
  * Load all dynamic options for this question
@@ -43,7 +57,8 @@ export default Base.extend({
43
57
  * @return {Object[]} The dynamic options
44
58
  * @public
45
59
  */
46
- loadDynamicOptions: task(function* () {
60
+ @dropTask
61
+ *loadDynamicOptions() {
47
62
  if (!this.isDynamic) return;
48
63
 
49
64
  const [question] = yield this.apollo.query(
@@ -59,108 +74,102 @@ export default Base.extend({
59
74
  question.node.dynamicChoiceOptions ||
60
75
  question.node.dynamicMultipleChoiceOptions
61
76
  );
62
- }),
77
+ }
63
78
 
64
- dynamicChoiceOptions: reads("loadDynamicOptions.lastSuccessful.value"),
65
- dynamicMultipleChoiceOptions: reads(
66
- "loadDynamicOptions.lastSuccessful.value"
67
- ),
79
+ @lastValue("loadDynamicOptions") dynamicChoiceOptions;
80
+ @lastValue("loadDynamicOptions") dynamicMultipleChoiceOptions;
68
81
 
69
82
  /**
70
83
  * Whether the question is a single choice question
71
84
  *
72
85
  * @property {Boolean} isChoice
73
- * @accessor
74
86
  */
75
- isChoice: computed("__typename", function () {
76
- return /(Dynamic)?ChoiceQuestion/.test(this.__typename);
77
- }),
87
+ get isChoice() {
88
+ return /(Dynamic)?ChoiceQuestion/.test(this.raw.__typename);
89
+ }
78
90
 
79
91
  /**
80
92
  * Whether the question is a multiple choice question
81
93
  *
82
94
  * @property {Boolean} isMultipleChoice
83
- * @accessor
84
95
  */
85
- isMultipleChoice: computed("__typename", function () {
86
- return /(Dynamic)?MultipleChoiceQuestion/.test(this.__typename);
87
- }),
96
+ get isMultipleChoice() {
97
+ return /(Dynamic)?MultipleChoiceQuestion/.test(this.raw.__typename);
98
+ }
88
99
 
89
100
  /**
90
101
  * Whether the question is a dynamic single or multiple choice question
91
102
  *
92
103
  * @property {Boolean} isDynamic
93
- * @accessor
94
104
  */
95
- isDynamic: computed("__typename", function () {
96
- return /Dynamic(Multiple)?ChoiceQuestion/.test(this.__typename);
97
- }),
105
+ get isDynamic() {
106
+ return /Dynamic(Multiple)?ChoiceQuestion/.test(this.raw.__typename);
107
+ }
108
+
109
+ /**
110
+ * Whether the question is a table question
111
+ *
112
+ * @property {Boolean} isTable
113
+ */
114
+ get isTable() {
115
+ return this.raw.__typename === "TableQuestion";
116
+ }
98
117
 
99
- isTable: equal("__typename", "TableQuestion"),
100
- isCalculated: equal("__typename", "CalculatedFloatQuestion"),
118
+ /**
119
+ * Whether the question is a calculated question
120
+ *
121
+ * @property {Boolean} isCalculated
122
+ */
123
+ get isCalculated() {
124
+ return this.raw.__typename === "CalculatedFloatQuestion";
125
+ }
101
126
 
102
127
  /**
103
128
  * All valid options for this question
104
129
  *
105
130
  * @property {Object[]} options
106
- * @accessor
107
131
  */
108
- options: computed(
109
- "__typename",
110
- "choiceOptions.edges.[]",
111
- "dynamicChoiceOptions.edges.[]",
112
- "dynamicMultipleChoiceOptions.edges.[]",
113
- "isChoice",
114
- "isMultipleChoice",
115
- "multipleChoiceOptions.edges.[]",
116
- function () {
117
- if (!this.isChoice && !this.isMultipleChoice) return null;
118
-
119
- const key = camelize(this.__typename.replace(/Question$/, "Options"));
120
-
121
- return (this.get(`${key}.edges`) || []).map(
122
- ({ node: { label, slug, isArchived } }) => ({
123
- label,
124
- slug,
125
- disabled: isArchived || false,
126
- })
127
- );
128
- }
129
- ),
130
-
131
- defaultValue: computed(
132
- "__typename",
133
- "isTable",
134
- "textDefaultAnswer",
135
- "textareaDefaultAnswer",
136
- "integerDefaultAnswer",
137
- "floatDefaultAnswer",
138
- "choiceDefaultAnswer",
139
- "multipleChoiceDefaultAnswer.[]",
140
- "dateDefaultAnswer",
141
- "tableDefaultAnswer.[]",
142
- function () {
143
- const key = camelize(
144
- this.__typename.replace(/Question$/, "DefaultAnswer")
145
- );
146
-
147
- const value = this[key] && this[key].value;
148
-
149
- if (this.isTable && value) {
150
- return value.map((defaultDocument) => {
151
- return defaultDocument.answers.edges.reduce(
152
- (defaultMap, { node: answer }) => {
153
- return {
154
- ...defaultMap,
155
- [answer.question.slug]: getValue(answer),
156
- };
157
- },
158
- {}
159
- );
160
- });
161
- }
162
-
163
- return value;
132
+ @cached
133
+ get options() {
134
+ if (!this.isChoice && !this.isMultipleChoice) return null;
135
+
136
+ const key = camelize(this.raw.__typename.replace(/Question$/, "Options"));
137
+ const raw = this.isDynamic ? this[key] : this.raw[key];
138
+
139
+ return (raw?.edges || []).map(({ node: { label, slug, isArchived } }) => ({
140
+ label,
141
+ slug,
142
+ disabled: isArchived || false,
143
+ }));
144
+ }
145
+
146
+ /**
147
+ * The default value of the question
148
+ *
149
+ * @property {String|Number|String[]|Object[]} defaultValue
150
+ */
151
+ @cached
152
+ get defaultValue() {
153
+ const key = camelize(
154
+ this.raw.__typename.replace(/Question$/, "DefaultAnswer")
155
+ );
156
+
157
+ const value = this.raw[key]?.value;
158
+
159
+ if (this.isTable && value) {
160
+ return value.map((defaultDocument) => {
161
+ return defaultDocument.answers.edges.reduce(
162
+ (defaultMap, { node: answer }) => {
163
+ return {
164
+ ...defaultMap,
165
+ [answer.question.slug]: getValue(answer),
166
+ };
167
+ },
168
+ {}
169
+ );
170
+ });
164
171
  }
165
- ),
166
- });
172
+
173
+ return value;
174
+ }
175
+ }
@@ -3,7 +3,11 @@ import { set } from "@ember/object";
3
3
  import Service from "@ember/service";
4
4
 
5
5
  export default class CalumaStoreService extends Service {
6
- _store = [];
6
+ constructor(...args) {
7
+ super(...args);
8
+
9
+ this._store = new Map();
10
+ }
7
11
 
8
12
  push(obj) {
9
13
  assert(
@@ -11,7 +15,7 @@ export default class CalumaStoreService extends Service {
11
15
  obj.pk
12
16
  );
13
17
 
14
- const existing = this._store.find((i) => i.pk === obj.pk);
18
+ const existing = this._store.get(obj.pk);
15
19
 
16
20
  if (existing) {
17
21
  debug(
@@ -23,22 +27,22 @@ export default class CalumaStoreService extends Service {
23
27
  return existing;
24
28
  }
25
29
 
26
- this._store = [...this._store.filter((i) => i.pk !== obj.pk), obj];
30
+ this._store.set(obj.pk, obj);
27
31
 
28
32
  return obj;
29
33
  }
30
34
 
31
35
  find(pk) {
32
- return this._store.find((i) => i.pk === pk) || null;
36
+ return this._store.get(pk) || null;
33
37
  }
34
38
 
35
39
  delete(pk) {
36
- this._store = this._store.filter((i) => i.pk !== pk);
40
+ this._store.delete(pk);
37
41
  }
38
42
 
39
43
  clear() {
40
44
  this._store.forEach((obj) => obj.destroy());
41
45
 
42
- this._store = [];
46
+ this._store.clear();
43
47
  }
44
48
  }
@@ -0,0 +1,4 @@
1
+ export {
2
+ default,
3
+ getWidget,
4
+ } from "@projectcaluma/ember-form/helpers/get-widget";
@@ -12,6 +12,7 @@ module.exports = {
12
12
  { name: "ember-math-helpers" },
13
13
  { name: "ember-pikaday" },
14
14
  { name: "ember-power-select" },
15
+ { name: "ember-autoresize-modifier" },
15
16
  ],
16
17
  });
17
18
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@projectcaluma/ember-form",
3
- "version": "10.0.2",
3
+ "version": "11.0.0-beta.3",
4
4
  "description": "Ember addon for rendering Caluma forms.",
5
5
  "keywords": [
6
6
  "ember-addon"
@@ -16,38 +16,42 @@
16
16
  "dependencies": {
17
17
  "@glimmer/component": "^1.0.4",
18
18
  "@glimmer/tracking": "^1.0.4",
19
- "@projectcaluma/ember-core": "^10.0.2",
19
+ "@projectcaluma/ember-core": "^11.0.0-beta.2",
20
20
  "ember-apollo-client": "^3.2.0",
21
- "ember-auto-import": "^2.2.3",
22
- "ember-cli-babel": "^7.26.6",
23
- "ember-cli-htmlbars": "^6.0.0",
24
- "ember-cli-showdown": "^6.0.0",
25
- "ember-composable-helpers": "^4.5.0",
26
- "ember-fetch": "^8.0.4",
27
- "ember-in-viewport": "^3.10.3",
28
- "ember-intl": "^5.7.0",
21
+ "ember-auto-import": "^2.4.0",
22
+ "ember-autoresize-modifier": "^0.5.0",
23
+ "ember-cli-babel": "^7.26.11",
24
+ "ember-cli-htmlbars": "^6.0.1",
25
+ "ember-cli-showdown": "^6.0.1",
26
+ "ember-composable-helpers": "^5.0.0",
27
+ "ember-fetch": "^8.1.1",
28
+ "ember-in-viewport": "^4.0.0",
29
+ "ember-intl": "^5.7.2",
29
30
  "ember-math-helpers": "^2.18.0",
30
31
  "ember-pikaday": "^3.0.0",
31
- "ember-power-select": "^4.1.7",
32
- "ember-uikit": "^4.0.0",
33
- "graphql": "^15.6.1",
32
+ "ember-power-select": "^5.0.3",
33
+ "ember-resources": "^4.1.3",
34
+ "ember-uikit": "^5.0.0-beta.3",
35
+ "ember-validators": "^4.0.1",
36
+ "graphql": "^15.8.0",
34
37
  "jexl": "^2.3.0",
35
- "lodash.clonedeep": "^4.5.0",
36
38
  "lodash.isequal": "^4.5.0",
37
- "moment": "^2.29.1"
39
+ "moment": "^2.29.1",
40
+ "tracked-toolbox": "^1.2.3"
38
41
  },
39
42
  "devDependencies": {
40
43
  "@ember/optional-features": "2.0.0",
41
44
  "@ember/test-helpers": "2.6.0",
42
- "@embroider/test-setup": "0.47.2",
43
- "@projectcaluma/ember-testing": "10.0.0",
44
- "@projectcaluma/ember-workflow": "10.0.1",
45
+ "@embroider/test-setup": "1.0.0",
46
+ "@faker-js/faker": "6.0.0-alpha.3",
47
+ "@projectcaluma/ember-testing": "10.2.0-beta.2",
48
+ "@projectcaluma/ember-workflow": "11.0.0-beta.1",
45
49
  "broccoli-asset-rev": "3.0.0",
46
- "ember-cli": "3.28.4",
50
+ "ember-cli": "3.28.5",
47
51
  "ember-cli-code-coverage": "1.0.3",
48
52
  "ember-cli-dependency-checker": "3.2.0",
49
53
  "ember-cli-inject-live-reload": "2.1.0",
50
- "ember-cli-mirage": "2.2.0",
54
+ "ember-cli-mirage": "2.4.0",
51
55
  "ember-cli-sri": "2.1.1",
52
56
  "ember-cli-terser": "4.0.2",
53
57
  "ember-disable-prototype-extensions": "1.1.3",
@@ -56,16 +60,16 @@
56
60
  "ember-maybe-import-regenerator": "1.0.0",
57
61
  "ember-qunit": "5.1.5",
58
62
  "ember-resolver": "8.0.3",
59
- "ember-source": "3.28.6",
63
+ "ember-source": "3.28.8",
60
64
  "ember-source-channel-url": "3.0.0",
61
65
  "ember-try": "2.0.0",
62
- "faker": "5.5.3",
63
66
  "loader.js": "4.7.0",
67
+ "miragejs": "0.1.43",
64
68
  "npm-run-all": "4.1.5",
65
69
  "qunit": "2.17.2",
66
70
  "qunit-dom": "2.0.0",
67
71
  "uuid": "8.3.2",
68
- "webpack": "5.64.1"
72
+ "webpack": "5.67.0"
69
73
  },
70
74
  "engines": {
71
75
  "node": "12.* || 14.* || >= 16"
@@ -1,9 +0,0 @@
1
- import { action } from "@ember/object";
2
- import Component from "@glimmer/component";
3
-
4
- export default class CfNavigationComponent extends Component {
5
- @action
6
- goToNextItem() {
7
- this.args.navigation.goToNextItem();
8
- }
9
- }