@projectcaluma/ember-form-builder 11.0.0-beta.1 → 11.0.0-beta.12

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 (57) hide show
  1. package/CHANGELOG.md +1181 -0
  2. package/addon/components/cfb-code-editor.hbs +2 -1
  3. package/addon/components/cfb-code-editor.js +59 -11
  4. package/addon/components/cfb-form-editor/general.hbs +2 -4
  5. package/addon/components/cfb-form-editor/general.js +5 -7
  6. package/addon/components/cfb-form-editor/question/options.hbs +1 -1
  7. package/addon/components/cfb-form-editor/question/validation.hbs +3 -2
  8. package/addon/components/cfb-form-editor/question/validation.js +17 -13
  9. package/addon/components/cfb-form-editor/question-list/item.hbs +4 -4
  10. package/addon/components/cfb-form-editor/question-list/item.js +2 -2
  11. package/addon/components/cfb-form-editor/question-list.hbs +6 -6
  12. package/addon/components/cfb-form-editor/question-list.js +11 -6
  13. package/addon/components/cfb-form-editor/question.hbs +31 -15
  14. package/addon/components/cfb-form-editor/question.js +44 -20
  15. package/addon/components/cfb-form-editor.hbs +5 -5
  16. package/addon/components/cfb-form-list/item.hbs +1 -1
  17. package/addon/components/cfb-form-list.hbs +9 -9
  18. package/addon/components/cfb-form-list.js +44 -11
  19. package/addon/components/cfb-toggle-switch.hbs +1 -1
  20. package/addon/controllers/index.js +6 -0
  21. package/addon/engine.js +8 -11
  22. package/addon/gql/fragments/field.graphql +12 -0
  23. package/addon/gql/mutations/save-calculated-float-question.graphql +1 -0
  24. package/addon/gql/mutations/save-choice-question.graphql +1 -0
  25. package/addon/gql/mutations/save-date-question.graphql +3 -0
  26. package/addon/gql/mutations/save-dynamic-choice-question.graphql +1 -0
  27. package/addon/gql/mutations/save-dynamic-multiple-choice-question.graphql +1 -0
  28. package/addon/gql/mutations/save-file-question.graphql +3 -0
  29. package/addon/gql/mutations/save-float-question.graphql +1 -0
  30. package/addon/gql/mutations/save-integer-question.graphql +1 -0
  31. package/addon/gql/mutations/save-multiple-choice-question.graphql +1 -0
  32. package/addon/gql/mutations/save-table-question.graphql +1 -0
  33. package/addon/gql/mutations/save-text-question.graphql +1 -0
  34. package/addon/gql/mutations/save-textarea-question.graphql +1 -0
  35. package/addon/gql/queries/all-format-validators.graphql +10 -0
  36. package/addon/gql/queries/form-editor-question.graphql +28 -0
  37. package/addon/instance-initializers/form-builder-widget-overrides.js +15 -0
  38. package/addon/modifiers/pikaday.js +2 -0
  39. package/addon/templates/edit/questions/edit.hbs +1 -1
  40. package/addon/templates/edit/questions/new.hbs +1 -4
  41. package/addon/templates/edit.hbs +5 -5
  42. package/addon/templates/index.hbs +8 -1
  43. package/addon/templates/new.hbs +1 -1
  44. package/addon/utils/and.js +47 -0
  45. package/addon/utils/or.js +40 -0
  46. package/addon/validations/option.js +1 -1
  47. package/addon/validations/question.js +8 -2
  48. package/addon/validators/slug.js +1 -1
  49. package/app/instance-initializers/form-builder-widget-overrides.js +4 -0
  50. package/app/styles/@projectcaluma/ember-form-builder.scss +1 -1
  51. package/app/utils/and.js +1 -0
  52. package/app/utils/or.js +1 -0
  53. package/index.js +4 -8
  54. package/package.json +39 -30
  55. package/translations/de.yaml +6 -5
  56. package/translations/en.yaml +3 -2
  57. package/translations/fr.yaml +154 -1
@@ -2,9 +2,10 @@
2
2
 
3
3
  <div
4
4
  name={{@name}}
5
- class={{concat "uk-textarea cfb-code-editor language-" @language}}
5
+ class="uk-textarea cfb-code-editor {{concat 'language-' @language}}"
6
6
  {{did-insert this.didInsertNode}}
7
7
  {{will-destroy this.willDestroyNode}}
8
+ {{autoresize mode="height"}}
8
9
  ></div>
9
10
 
10
11
  {{component @hintComponent}}
@@ -1,25 +1,73 @@
1
1
  import { action } from "@ember/object";
2
+ import { addObserver } from "@ember/object/observers";
2
3
  import Component from "@glimmer/component";
3
- import { tracked } from "@glimmer/tracking";
4
4
  import { CodeJar } from "codejar";
5
- import Prism from "prismjs";
6
- import "prismjs/components/prism-jexl.js";
7
- import "prismjs/components/prism-markdown.js";
5
+ import hljs from "highlight.js/lib/core";
6
+ import json from "highlight.js/lib/languages/json";
7
+ import markdown from "highlight.js/lib/languages/markdown";
8
+ import jexl from "highlightjs-jexl/src/languages/jexl";
9
+
10
+ hljs.registerLanguage("json", json);
11
+ hljs.registerLanguage("markdown", markdown);
12
+ hljs.registerLanguage("jexl", jexl);
8
13
 
9
14
  export default class CfbCodeEditorComponent extends Component {
10
- editor;
11
- @tracked show = false;
15
+ _editor = null;
16
+ _cursor = null;
17
+ _lastValue = null;
18
+
19
+ get value() {
20
+ const value = this.args.value;
21
+
22
+ if (this.args.language === "json" && typeof value === "object") {
23
+ return JSON.stringify(value?.unwrap?.() ?? value, null, 2);
24
+ }
25
+
26
+ return this.args.value;
27
+ }
28
+
29
+ @action
30
+ onUpdate(value) {
31
+ if (this._lastValue === value) return;
32
+
33
+ this._cursor = this._editor.save();
34
+
35
+ if (this.args.language === "json") {
36
+ try {
37
+ value = JSON.parse(value);
38
+ } catch {
39
+ // update value directly
40
+ }
41
+ }
42
+
43
+ this._lastValue = value;
44
+ this.args.update(value);
45
+ this.args.setDirty();
46
+ }
47
+
48
+ @action
49
+ updateCode() {
50
+ this._editor.updateCode(this.value);
51
+
52
+ if (this._cursor) {
53
+ this._editor.restore(this._cursor);
54
+ this._cursor = null;
55
+ }
56
+ }
12
57
 
13
58
  @action
14
59
  didInsertNode(element) {
15
- const highlight = (editor) => Prism.highlightElement(editor);
16
- this.editor = CodeJar(element, highlight);
17
- this.editor.updateCode(this.args.value);
18
- this.editor.onUpdate(this.args.update);
60
+ this._editor = CodeJar(element, (editor) => hljs.highlightElement(editor));
61
+ this._editor.onUpdate(this.onUpdate);
62
+
63
+ this.updateCode();
64
+
65
+ // eslint-disable-next-line ember/no-observers
66
+ addObserver(this.args, "value", this, "updateCode");
19
67
  }
20
68
 
21
69
  @action
22
70
  willDestroyNode() {
23
- this.editor.destroy();
71
+ this._editor.destroy();
24
72
  }
25
73
  }
@@ -55,11 +55,10 @@
55
55
  @name="description"
56
56
  @type="textarea"
57
57
  @label={{t "caluma.form-builder.form.description"}}
58
- @rows="4"
58
+ {{autoresize mode="height"}}
59
59
  />
60
60
 
61
61
  <f.input
62
- class="uk-flex uk-flex-between uk-flex-column"
63
62
  @name="isArchived"
64
63
  @label={{t "caluma.form-builder.form.isArchived"}}
65
64
  @required={{true}}
@@ -67,7 +66,6 @@
67
66
  />
68
67
 
69
68
  <f.input
70
- class="uk-flex uk-flex-between uk-flex-column"
71
69
  @name="isPublished"
72
70
  @label={{t "caluma.form-builder.form.isPublished"}}
73
71
  @required={{true}}
@@ -85,7 +83,7 @@
85
83
  <div
86
84
  class="uk-text-center uk-text-muted uk-padding uk-padding-remove-horizontal"
87
85
  >
88
- {{uk-icon "bolt" ratio=5}}
86
+ <UkIcon @icon="bolt" @ratio={{5}} />
89
87
  <p>{{t "caluma.form-builder.form.not-found" slug=@slug}}</p>
90
88
  </div>
91
89
  {{/if}}
@@ -1,9 +1,8 @@
1
- import { getOwner } from "@ember/application";
2
1
  import { action } from "@ember/object";
3
2
  import { inject as service } from "@ember/service";
3
+ import { macroCondition, isTesting } from "@embroider/macros";
4
4
  import Component from "@glimmer/component";
5
5
  import { queryManager } from "ember-apollo-client";
6
- import { optional } from "ember-composable-helpers/helpers/optional";
7
6
  import { timeout, restartableTask, dropTask } from "ember-concurrency";
8
7
  import { useTask } from "ember-resources";
9
8
 
@@ -89,7 +88,7 @@ export default class CfbFormEditorGeneral extends Component {
89
88
  )
90
89
  );
91
90
 
92
- optional([this.args["on-after-submit"]])(form);
91
+ this.args.onAfterSubmit?.(form);
93
92
  } catch (e) {
94
93
  this.notification.danger(
95
94
  this.intl.t(
@@ -104,10 +103,9 @@ export default class CfbFormEditorGeneral extends Component {
104
103
  @restartableTask
105
104
  *validateSlug(slug, changeset) {
106
105
  /* istanbul ignore next */
107
- if (
108
- getOwner(this).resolveRegistration("config:environment").environment !==
109
- "test"
110
- ) {
106
+ if (macroCondition(isTesting())) {
107
+ // no timeout
108
+ } else {
111
109
  yield timeout(500);
112
110
  }
113
111
 
@@ -3,7 +3,7 @@
3
3
 
4
4
  <UkSortable
5
5
  @handle=".uk-sortable-handle"
6
- @on-moved={{this._handleMoved}}
6
+ @onMoved={{this._handleMoved}}
7
7
  @tagName="ul"
8
8
  class="uk-list uk-list-divider uk-margin-remove-bottom uk-margin-small-top"
9
9
  >
@@ -1,11 +1,12 @@
1
- <div class="uk-margin" {{did-insert (perform this.availableFormatValidators)}}>
1
+ <div class="uk-margin">
2
2
  {{component @labelComponent}}
3
3
 
4
4
  <PowerSelectMultiple
5
5
  @selected={{this.selected}}
6
- @placeholder={{this.placeholder}}
6
+ @placeholder={{@placeholder}}
7
7
  @options={{this.validators}}
8
8
  @onChange={{this.updateValidators}}
9
+ @renderInPlace={{true}}
9
10
  as |item|
10
11
  >
11
12
  {{item.name}}
@@ -2,34 +2,38 @@ import { action } from "@ember/object";
2
2
  import Component from "@glimmer/component";
3
3
  import { queryManager } from "ember-apollo-client";
4
4
  import { dropTask } from "ember-concurrency";
5
+ import { useTask } from "ember-resources";
5
6
 
6
- import allFormatValidatorsQuery from "@projectcaluma/ember-core/gql/queries/all-format-validators.graphql";
7
+ import allFormatValidatorsQuery from "@projectcaluma/ember-form-builder/gql/queries/all-format-validators.graphql";
7
8
 
8
9
  export default class CfbFormEditorQuestionValidation extends Component {
9
10
  @queryManager apollo;
10
11
 
11
- @dropTask
12
- *availableFormatValidators() {
13
- const formatValidators = yield this.apollo.watchQuery(
14
- { query: allFormatValidatorsQuery, fetchPolicy: "cache-and-network" },
15
- "allFormatValidators.edges"
16
- );
17
- return formatValidators.map((edge) => edge.node);
18
- }
19
-
20
12
  get validators() {
21
- return this.availableFormatValidators?.lastSuccessful?.value || [];
13
+ return this._validators.value?.map((edge) => edge.node) ?? [];
22
14
  }
23
15
 
24
16
  get selected() {
25
17
  return this.validators.filter((validator) =>
26
- (this.args.value || []).includes(validator.slug)
18
+ (this.args.value?.edges.map((edge) => edge.node.slug) || []).includes(
19
+ validator.slug
20
+ )
21
+ );
22
+ }
23
+
24
+ _validators = useTask(this, this.fetchFormatValidators, () => []);
25
+
26
+ @dropTask
27
+ *fetchFormatValidators() {
28
+ return yield this.apollo.watchQuery(
29
+ { query: allFormatValidatorsQuery, fetchPolicy: "cache-and-network" },
30
+ "allFormatValidators.edges"
27
31
  );
28
32
  }
29
33
 
30
34
  @action
31
35
  updateValidators(value) {
32
- this.args.update(value.map((validator) => validator.slug));
36
+ this.args.update({ edges: value.map(({ slug }) => ({ node: { slug } })) });
33
37
  this.args.setDirty();
34
38
  }
35
39
  }
@@ -4,8 +4,8 @@
4
4
  @question.isArchived
5
5
  "cfb-form-editor__question-list__item__archived"
6
6
  }}
7
- {{did-insert (fn (optional @on-register) this.elementId @question.slug)}}
8
- {{will-destroy (fn (optional @on-unregister) this.elementId @question.slug)}}
7
+ {{did-insert (fn (optional @onRegister) this.elementId @question.slug)}}
8
+ {{will-destroy (fn (optional @onUnregister) this.elementId @question.slug)}}
9
9
  ...attributes
10
10
  >
11
11
  <div class="uk-flex uk-flex-middle">
@@ -24,7 +24,7 @@
24
24
  data-test-remove-item
25
25
  uk-icon="minus"
26
26
  class="cfb-pointer uk-text-danger"
27
- {{on "click" (fn (optional @on-remove-question) @question)}}
27
+ {{on "click" (fn (optional @onRemoveQuestion) @question)}}
28
28
  >
29
29
  </i>
30
30
  {{else if (eq @mode "add")}}
@@ -33,7 +33,7 @@
33
33
  data-test-add-item
34
34
  uk-icon="plus"
35
35
  class="cfb-pointer uk-text-success"
36
- {{on "click" (fn (optional @on-add-question) @question)}}
36
+ {{on "click" (fn (optional @onAddQuestion) @question)}}
37
37
  >
38
38
  </i>
39
39
  {{/if}}
@@ -51,12 +51,12 @@ export default class CfbFormEditorQuestionListItem extends Component {
51
51
  @action
52
52
  editQuestion(question, e) {
53
53
  e.preventDefault();
54
- this.args["on-edit-question"]?.(question);
54
+ this.args.onEditQuestion?.(question);
55
55
  }
56
56
 
57
57
  @action
58
58
  clickForm(form, e) {
59
59
  e.preventDefault();
60
- this.args["on-click-form"]?.(form);
60
+ this.args.onClickForm?.(form);
61
61
  }
62
62
  }
@@ -76,12 +76,12 @@
76
76
  data-test-question-list-item={{item.node.slug}}
77
77
  @mode={{this.mode}}
78
78
  @question={{item.node}}
79
- @on-edit-question={{@on-edit-question}}
80
- @on-remove-question={{perform this.removeQuestion}}
81
- @on-add-question={{perform this.addQuestion}}
82
- @on-click-form={{@on-click-form}}
83
- @on-register={{this.registerChild}}
84
- @on-unregister={{this.unregisterChild}}
79
+ @onEditQuestion={{@onEditQuestion}}
80
+ @onRemoveQuestion={{perform this.removeQuestion}}
81
+ @onAddQuestion={{perform this.addQuestion}}
82
+ @onClickForm={{@onClickForm}}
83
+ @onRegister={{this.registerChild}}
84
+ @onUnregister={{this.unregisterChild}}
85
85
  />
86
86
  {{else}}
87
87
  <li
@@ -1,10 +1,10 @@
1
1
  import { action } from "@ember/object";
2
2
  import { run } from "@ember/runloop";
3
3
  import { inject as service } from "@ember/service";
4
+ import { macroCondition, isTesting } from "@embroider/macros";
4
5
  import Component from "@glimmer/component";
5
6
  import { tracked } from "@glimmer/tracking";
6
7
  import { queryManager } from "ember-apollo-client";
7
- import { optional } from "ember-composable-helpers/helpers/optional";
8
8
  import {
9
9
  timeout,
10
10
  enqueueTask,
@@ -56,8 +56,13 @@ export default class ComponentsCfbFormEditorQuestionList extends Component {
56
56
  const mode = this.mode;
57
57
  const search = mode !== "reorder" ? this.search : "";
58
58
 
59
- if (search) {
60
- yield timeout(500);
59
+ /* istanbul ignore next */
60
+ if (macroCondition(isTesting())) {
61
+ // no timeout
62
+ } else {
63
+ if (search) {
64
+ yield timeout(500);
65
+ }
61
66
  }
62
67
 
63
68
  if (mode === "add" && this.hasNextPage) {
@@ -148,7 +153,7 @@ export default class ComponentsCfbFormEditorQuestionList extends Component {
148
153
 
149
154
  this.questionTask.perform();
150
155
 
151
- optional([this.args["on-after-add-question"]])(question);
156
+ this.args.onAfterAddQuestion?.(question);
152
157
  } catch (e) {
153
158
  this.notification.danger(
154
159
  this.intl.t("caluma.form-builder.notification.form.add-question.error")
@@ -176,7 +181,7 @@ export default class ComponentsCfbFormEditorQuestionList extends Component {
176
181
  )
177
182
  );
178
183
 
179
- optional([this.args["on-after-remove-question"]])(question);
184
+ this.args.onAfterRemoveQuestion?.(question);
180
185
  } catch (e) {
181
186
  this.notification.danger(
182
187
  this.intl.t(
@@ -238,7 +243,7 @@ export default class ComponentsCfbFormEditorQuestionList extends Component {
238
243
  createNewQuestion(e) {
239
244
  e.preventDefault();
240
245
 
241
- this.args["on-create-question"]?.();
246
+ this.args.onCreateQuestion?.();
242
247
  this.setMode("reorder");
243
248
  }
244
249
  }
@@ -140,6 +140,7 @@
140
140
  @label={{t "caluma.form-builder.question.confirmationText"}}
141
141
  @name="infoText"
142
142
  @type="textarea"
143
+ {{autoresize mode="height"}}
143
144
  />
144
145
  {{else}}
145
146
  <div class="uk-margin">
@@ -163,6 +164,13 @@
163
164
  </div>
164
165
  {{/if}}
165
166
 
167
+ {{#if (not (has-question-type f.model "action-button" "static" "form"))}}
168
+ <f.input
169
+ @name="hintText"
170
+ @label={{t "caluma.form-builder.question.hintText"}}
171
+ />
172
+ {{/if}}
173
+
166
174
  {{#if (has-question-type f.model "text" "textarea" "integer" "float")}}
167
175
  <f.input
168
176
  @name="placeholder"
@@ -207,13 +215,13 @@
207
215
  />
208
216
 
209
217
  <f.input
210
- @name="meta.formatValidators"
218
+ @name="formatValidators"
211
219
  @label={{t "caluma.form-builder.question.formatValidators"}}
212
- @placeholder={{t "caluma.form-builder.question.choose"}}
220
+ @placeholder={{t "caluma.form-builder.question.no-selection"}}
213
221
  @required={{false}}
214
222
  @renderComponent={{component "cfb-form-editor/question/validation"}}
215
- @on-update={{changeset-set f.model "meta.formatValidators"}}
216
- @value={{changeset-get f.model "meta.formatValidators"}}
223
+ @on-update={{changeset-set f.model "formatValidators"}}
224
+ @value={{changeset-get f.model "formatValidators"}}
217
225
  />
218
226
  {{/if}}
219
227
 
@@ -295,10 +303,10 @@
295
303
  @type="select"
296
304
  @required={{true}}
297
305
  @label={{t "caluma.form-builder.question.dataSource"}}
298
- @options={{or this.availableDataSources.lastSuccessful.value array}}
306
+ @options={{or this.availableDataSources.lastSuccessful.value (array)}}
299
307
  @optionTargetPath="name"
300
308
  @optionLabelPath="info"
301
- @includeBlank={{t "caluma.form-builder.question.choose"}}
309
+ @prompt={{t "caluma.form-builder.question.no-selection"}}
302
310
  />
303
311
  {{/if}}
304
312
 
@@ -328,9 +336,9 @@
328
336
  as |fi|
329
337
  >
330
338
  <PowerSelect
331
- @options={{or this.availableForms.lastSuccessful.value array}}
339
+ @options={{or this.availableForms.lastSuccessful.value (array)}}
332
340
  @selected={{fi.value}}
333
- @placeholder={{t "caluma.form-builder.question.choose"}}
341
+ @placeholder={{t "caluma.form-builder.question.no-selection"}}
334
342
  @onBlur={{fi.setDirty}}
335
343
  @onChange={{fi.update}}
336
344
  @searchField="slug"
@@ -341,6 +349,7 @@
341
349
  @noMatchesMessage={{t
342
350
  "caluma.form-builder.question.search-empty"
343
351
  }}
352
+ @renderInPlace={{true}}
344
353
  as |form|
345
354
  >
346
355
  <span
@@ -365,7 +374,7 @@
365
374
  >
366
375
  {{#each this.model.rowForm.questions.edges as |rowEdge|}}
367
376
  {{#let rowEdge.node as |row|}}
368
- <label class="cf-checkbox_label">
377
+ <label>
369
378
  <input
370
379
  type="checkbox"
371
380
  value={{row.slug}}
@@ -402,9 +411,9 @@
402
411
  as |fi|
403
412
  >
404
413
  <PowerSelect
405
- @options={{or this.availableForms.lastSuccessful.value array}}
414
+ @options={{or this.availableForms.lastSuccessful.value (array)}}
406
415
  @selected={{fi.value}}
407
- @placeholder={{t "caluma.form-builder.question.choose"}}
416
+ @placeholder={{t "caluma.form-builder.question.no-selection"}}
408
417
  @onBlur={{fi.setDirty}}
409
418
  @onChange={{fi.update}}
410
419
  @searchField="slug"
@@ -413,6 +422,7 @@
413
422
  "caluma.form-builder.question.search-placeholder"
414
423
  }}
415
424
  @noMatchesMessage={{t "caluma.form-builder.question.search-empty"}}
425
+ @renderInPlace={{true}}
416
426
  as |form|
417
427
  >
418
428
  <span class="uk-width-auto uk-margin-small-right uk-text-truncate">
@@ -435,7 +445,7 @@
435
445
  @optionTargetPath="component"
436
446
  @optionLabelPath="label"
437
447
  @options={{this.availableOverrides}}
438
- class="uk-flex uk-flex-between uk-flex-column"
448
+ @prompt={{t "caluma.form-builder.question.no-selection"}}
439
449
  />
440
450
 
441
451
  <f.input
@@ -443,12 +453,11 @@
443
453
  @label={{t "caluma.form-builder.question.isArchived"}}
444
454
  @required={{true}}
445
455
  @renderComponent={{component "cfb-toggle-switch" size="small"}}
446
- class="uk-flex uk-flex-between uk-flex-column"
447
456
  />
448
457
 
449
458
  <UkButton
450
459
  @color="link"
451
- @on-click={{toggle-action "showAdvanced" this}}
460
+ @onClick={{toggle-action "showAdvanced" this}}
452
461
  class="uk-flex uk-flex-middle uk-margin"
453
462
  >
454
463
  {{#if this.showAdvanced}}
@@ -466,7 +475,6 @@
466
475
  @required={{true}}
467
476
  @label={{t "caluma.form-builder.question.validateOnEnter"}}
468
477
  @renderComponent={{component "cfb-toggle-switch" size="small"}}
469
- class="uk-flex uk-flex-between uk-flex-column"
470
478
  />
471
479
  {{/if}}
472
480
 
@@ -493,6 +501,14 @@
493
501
  />
494
502
  </div>
495
503
  {{/if}}
504
+
505
+ <div class="uk-margin">
506
+ <f.input
507
+ @label={{t "caluma.form-builder.question.meta"}}
508
+ @name="meta"
509
+ @renderComponent={{component "cfb-code-editor" language="json"}}
510
+ />
511
+ </div>
496
512
  {{/if}}
497
513
 
498
514
  <div class="uk-text-right">