@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.
Files changed (55) hide show
  1. package/CHANGELOG.md +1181 -0
  2. package/addon/components/cf-content.hbs +36 -41
  3. package/addon/components/cf-content.js +48 -29
  4. package/addon/components/cf-field/info.hbs +2 -2
  5. package/addon/components/cf-field/info.js +0 -15
  6. package/addon/components/cf-field/input/action-button.hbs +18 -19
  7. package/addon/components/cf-field/input/action-button.js +9 -7
  8. package/addon/components/cf-field/input/checkbox.hbs +6 -2
  9. package/addon/components/cf-field/input/checkbox.js +9 -29
  10. package/addon/components/cf-field/input/date.hbs +8 -5
  11. package/addon/components/cf-field/input/date.js +28 -10
  12. package/addon/components/cf-field/input/file.hbs +2 -2
  13. package/addon/components/cf-field/input/file.js +10 -11
  14. package/addon/components/cf-field/input/float.hbs +4 -4
  15. package/addon/components/cf-field/input/integer.hbs +5 -5
  16. package/addon/components/cf-field/input/radio.hbs +4 -1
  17. package/addon/components/cf-field/input/static.hbs +1 -1
  18. package/addon/components/cf-field/input/table.hbs +24 -24
  19. package/addon/components/cf-field/input/table.js +12 -10
  20. package/addon/components/cf-field/input/text.hbs +5 -5
  21. package/addon/components/cf-field/input/textarea.hbs +6 -5
  22. package/addon/components/cf-field/input.hbs +10 -1
  23. package/addon/components/cf-field/input.js +1 -1
  24. package/addon/components/cf-field/label.hbs +1 -1
  25. package/addon/components/cf-field-value.hbs +22 -7
  26. package/addon/components/cf-field-value.js +8 -38
  27. package/addon/components/cf-field.hbs +14 -6
  28. package/addon/components/cf-field.js +22 -8
  29. package/addon/components/cf-navigation-item.hbs +2 -2
  30. package/addon/components/cf-navigation.hbs +4 -1
  31. package/addon/components/document-validity.js +17 -2
  32. package/addon/gql/fragments/field.graphql +45 -0
  33. package/addon/gql/mutations/save-document-table-answer.graphql +1 -1
  34. package/addon/gql/mutations/save-document.graphql +1 -0
  35. package/addon/gql/queries/{get-document-answers.graphql → document-answers.graphql} +2 -1
  36. package/addon/gql/queries/{get-document-forms.graphql → document-forms.graphql} +2 -1
  37. package/addon/gql/queries/{get-document-used-dynamic-options.graphql → document-used-dynamic-options.graphql} +2 -1
  38. package/addon/gql/queries/{get-dynamic-options.graphql → dynamic-options.graphql} +2 -1
  39. package/addon/gql/queries/{get-fileanswer-info.graphql → fileanswer-info.graphql} +2 -1
  40. package/addon/helpers/get-widget.js +50 -0
  41. package/addon/lib/answer.js +108 -72
  42. package/addon/lib/base.js +32 -23
  43. package/addon/lib/dependencies.js +36 -71
  44. package/addon/lib/document.js +92 -96
  45. package/addon/lib/field.js +374 -407
  46. package/addon/lib/fieldset.js +46 -47
  47. package/addon/lib/form.js +27 -15
  48. package/addon/lib/navigation.js +211 -192
  49. package/addon/lib/question.js +103 -94
  50. package/addon/services/caluma-store.js +10 -6
  51. package/app/helpers/get-widget.js +4 -0
  52. package/blueprints/@projectcaluma/ember-form/index.js +1 -0
  53. package/package.json +30 -25
  54. package/addon/components/cf-navigation.js +0 -9
  55. 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
- <button
29
- data-test-edit-row
30
- type="button"
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
- {{on "click" (fn this.edit document)}}
32
+ class="uk-flex-inline uk-margin-small-left"
33
+ data-test-edit-row
34
34
  >
35
35
  <UkIcon @icon="pencil" />
36
- <span class="uk-hidden">{{t "caluma.form.edit"}}</span>
37
- </button>
36
+ <span hidden>{{t "caluma.form.edit"}}</span>
37
+ </UkButton>
38
38
  {{#unless @disabled}}
39
- <button
40
- data-test-delete-row
41
- type="button"
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
- {{on "click" (fn (perform this.delete) document)}}
43
+ class="uk-flex-inline uk-margin-small-left"
44
+ data-test-delete-row
45
45
  >
46
46
  <UkIcon @icon="trash" />
47
- <span class="uk-hidden">{{t "caluma.form.delete"}}</span>
48
- </button>
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
- @size="small"
61
- @color="default"
62
- @on-click={{perform this.add}}
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 class="uk-hidden">{{t "caluma.form.addRow"}}</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
- @on-hide={{perform this.closeModal}}
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 @class="uk-text-right">
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
- @on-click={{perform this.close}}
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
- @on-click={{perform this.close}}
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
- @on-click={{fn (perform this.save) validate}}
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-decorators";
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: { input: { form: this.args.field.question.rowForm.slug } },
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 newDocument = getOwner(this)
68
- .factoryFor("caluma-model:document")
69
- .create({
70
- raw: this.parseDocument(raw),
71
- parentDocument: this.args.field.document,
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 "uk-form-danger"}}
5
- {{if @disabled "uk-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 "uk-form-danger"}}
4
- {{if @disabled "uk-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 class="uk-form-controls">
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}}
@@ -22,7 +22,7 @@ export default class CfFieldInputComponent extends Component {
22
22
  * @accessor
23
23
  */
24
24
  get type() {
25
- const typename = this.args.field?.question.__typename;
25
+ const typename = this.args.field?.question.raw.__typename;
26
26
 
27
27
  return (
28
28
  typename &&
@@ -1,6 +1,6 @@
1
1
  <label class="uk-form-label" for={{@field.pk}}>
2
2
  <span class="uk-text-bold">
3
- {{@field.question.label}}
3
+ {{@field.question.raw.label}}
4
4
  </span>
5
5
 
6
6
  {{#if this.optional}}
@@ -1,9 +1,24 @@
1
- {{#if this.value.fileAnswerId}}
2
- <UkButton
3
- @color="link"
4
- @label={{this.value.label}}
5
- @on-click={{fn this.download this.value.fileAnswerId}}
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
- {{this.value.label}}
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/get-fileanswer-info.graphql";
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(fileAnswerId) {
11
+ async download(id) {
45
12
  const { downloadUrl } = await this.apollo.query(
46
13
  {
47
14
  query: getFileAnswerInfoQuery,
48
- variables: { id: fileAnswerId },
49
- fetchPolicy: "cache-and-network",
15
+ variables: { id },
16
+ fetchPolicy: "network-only",
50
17
  },
51
18
  "node.fileValue"
52
19
  );
53
- window.open(downloadUrl, "_blank");
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 class="uk-margin">
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 @field.save.isRunning}}
35
+ {{#if this.save.isRunning}}
28
36
  <UkSpinner class="uk-animation-fade" />
29
- {{else if (or @field.save.last.isError @field.isInvalid)}}
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 @field.save.last.isSuccessful}}
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 { set } from "@ember/object";
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
- * save the field to the API after a timeout off 500 milliseconds.
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
- set(this.args.field.answer, "value", value);
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
- // that's ok
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) "uk-active"}}"
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 "cf-navigation__item__icon--dirty"}}"
22
+ {{if @item.dirty 'cf-navigation__item__icon--dirty'}}"
23
23
  ></span>
24
24
  </LinkTo>
25
25
 
@@ -1,4 +1,7 @@
1
- <ul class="uk-tab uk-tab-left uk-width-auto" {{did-insert this.goToNextItem}}>
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-decorators";
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.every((f) => f.isValid);
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 {