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

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