@projectcaluma/ember-form 11.0.0-beta.1 → 11.0.0-beta.10

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,41 +1,39 @@
1
- {{#if @documentId}}
2
- {{#if this.loading}}
3
- <div class="uk-text-center"><UkSpinner @ratio={{2}} /></div>
4
- {{else if this.document}}
5
- {{#let
6
- (hash
1
+ {{#if this.loading}}
2
+ <div class="uk-text-center"><UkSpinner @ratio={{2}} /></div>
3
+ {{else if this.document}}
4
+ {{#let
5
+ (hash
6
+ document=this.document
7
+ navigation=(component
8
+ "cf-navigation"
9
+ navigation=this.navigation
10
+ useAsHeading=(or @useAsHeading false)
11
+ headingBaseLevel=(or @headingBaseLevel 1)
12
+ )
13
+ pagination=(component "cf-pagination" navigation=this.navigation)
14
+ form=(component
15
+ "cf-form-wrapper"
7
16
  document=this.document
8
- navigation=(component
9
- "cf-navigation"
10
- navigation=this.navigation
11
- useAsHeading=(or @useAsHeading false)
12
- headingBaseLevel=(or @headingBaseLevel 1)
13
- )
14
- pagination=(component "cf-pagination" navigation=this.navigation)
15
- form=(component
16
- "cf-form-wrapper"
17
- document=this.document
18
- fieldset=this.fieldset
19
- context=@context
20
- disabled=@disabled
21
- )
17
+ fieldset=this.fieldset
18
+ context=@context
19
+ disabled=@disabled
22
20
  )
23
- as |content|
24
- }}
25
- {{#if (has-block)}}
26
- {{yield content}}
27
- {{else if (gt this.document.fieldsets.length 1)}}
28
- <div uk-grid>
29
- <div class="uk-width-1-1 uk-width-1-3@m"><content.navigation /></div>
30
- <div class="uk-width-1-1 uk-width-2-3@m">
31
- <content.form />
32
- <hr />
33
- <content.pagination />
34
- </div>
21
+ )
22
+ as |content|
23
+ }}
24
+ {{#if (has-block)}}
25
+ {{yield content}}
26
+ {{else if (gt this.document.fieldsets.length 1)}}
27
+ <div uk-grid>
28
+ <div class="uk-width-1-1 uk-width-1-3@m"><content.navigation /></div>
29
+ <div class="uk-width-1-1 uk-width-2-3@m">
30
+ <content.form />
31
+ <hr />
32
+ <content.pagination />
35
33
  </div>
36
- {{else}}
37
- <content.form />
38
- {{/if}}
39
- {{/let}}
40
- {{/if}}
34
+ </div>
35
+ {{else}}
36
+ <content.form />
37
+ {{/if}}
38
+ {{/let}}
41
39
  {{/if}}
@@ -120,17 +120,9 @@ export default class CfContentComponent extends Component {
120
120
  this.router.currentRoute?.queryParams.displayedForm ||
121
121
  this.document?.raw.form.slug;
122
122
 
123
- const fieldset = this.document.fieldsets.find(
123
+ return this.document.fieldsets.find(
124
124
  (fieldset) => fieldset.form.slug === slug
125
125
  );
126
-
127
- if (!fieldset) {
128
- this.router.replaceWith({
129
- queryParams: { displayedForm: "" },
130
- });
131
- }
132
-
133
- return fieldset;
134
126
  }
135
127
 
136
128
  data = useTask(this, this.fetchData, () => [this.args.documentId]);
@@ -4,7 +4,7 @@
4
4
  class="uk-icon-button"
5
5
  uk-icon="info"
6
6
  title={{t "caluma.form.info"}}
7
- {{on "click" this.showModal}}
7
+ {{on "click" (fn (mut this.modalVisible) true)}}
8
8
  >
9
9
  <span class="uk-hidden">{{t "caluma.form.info"}}</span>
10
10
  </button>
@@ -12,7 +12,7 @@
12
12
  <UkModal
13
13
  @visible={{this.modalVisible}}
14
14
  @stack={{true}}
15
- @on-hide={{this.hideModal}}
15
+ @onHide={{fn (mut this.modalVisible) false}}
16
16
  as |modal|
17
17
  >
18
18
  <modal.body>
@@ -1,21 +1,6 @@
1
- import { action } from "@ember/object";
2
1
  import Component from "@glimmer/component";
3
2
  import { tracked } from "@glimmer/tracking";
4
3
 
5
4
  export default class CfFieldInfoComponent extends Component {
6
5
  @tracked modalVisible = false;
7
-
8
- @action
9
- showModal(e) {
10
- e.preventDefault();
11
-
12
- this.modalVisible = true;
13
- }
14
-
15
- @action
16
- hideModal(e) {
17
- e.preventDefault();
18
-
19
- this.modalVisible = false;
20
- }
21
6
  }
@@ -1,19 +1,18 @@
1
- {{#unless @disabled}}
2
- <DocumentValidity
3
- @document={{@field.document}}
4
- @validateOnEnter={{this.validateOnEnter}}
5
- as |isValid validate|
6
- >
7
- <WorkItemButton
8
- @workItemId={{this.workItem}}
9
- @mutation={{this.action}}
10
- @label={{@field.question.raw.label}}
11
- @disabled={{and (not-eq isValid null) (not isValid)}}
12
- @color={{this.color}}
13
- @beforeMutate={{fn this.beforeMutate validate}}
14
- @onSuccess={{this.onSuccess}}
15
- @onError={{this.onError}}
16
- @type={{this.type}}
17
- />
18
- </DocumentValidity>
19
- {{/unless}}
1
+ <DocumentValidity
2
+ @document={{@field.document}}
3
+ @validateOnEnter={{this.validateOnEnter}}
4
+ as |isValid validate|
5
+ >
6
+ <WorkItemButton
7
+ @workItemId={{this.workItem}}
8
+ @mutation={{this.action}}
9
+ @label={{@field.question.raw.label}}
10
+ @disabled={{or (and (not-eq isValid null) (not isValid)) @disabled}}
11
+ @color={{this.color}}
12
+ @beforeMutate={{fn this.beforeMutate validate}}
13
+ @onSuccess={{this.onSuccess}}
14
+ @onError={{this.onError}}
15
+ @type={{this.type}}
16
+ class={{if @disabled "uk-hidden"}}
17
+ />
18
+ </DocumentValidity>
@@ -1,6 +1,10 @@
1
1
  {{#each @field.options as |option i|}}
2
2
  {{#if (gt i 0)}}<br />{{/if}}
3
- <label class="cf-checkbox_label {{if @field.isInvalid 'uk-form-danger'}}">
3
+ <label
4
+ class="cf-checkbox_label
5
+ {{if @field.isInvalid 'uk-form-danger'}}
6
+ {{if @field.raw.question.meta.vertical 'uk-margin-large-right'}}"
7
+ >
4
8
  <input
5
9
  class="uk-checkbox uk-margin-small-right"
6
10
  type="checkbox"
@@ -13,13 +13,16 @@
13
13
  readonly
14
14
  />
15
15
  {{else}}
16
- <PikadayInput
16
+ <input
17
17
  class="uk-input"
18
+ type="text"
18
19
  name={{@field.pk}}
19
20
  id={{@field.pk}}
20
- @format="L"
21
- @onSelection={{this.onChange}}
22
- @useUTC={{true}}
23
- @value={{@field.answer.value}}
21
+ {{pikaday
22
+ toString=this.formatDate
23
+ i18n=this.pikadayTranslations
24
+ value=@field.answer.value
25
+ onSelect=this.onChange
26
+ }}
24
27
  />
25
28
  {{/if}}
@@ -1,19 +1,37 @@
1
1
  import { action } from "@ember/object";
2
+ import { inject as service } from "@ember/service";
2
3
  import Component from "@glimmer/component";
3
- import moment from "moment";
4
+ import { DateTime, Info } from "luxon";
5
+ import { cached } from "tracked-toolbox";
4
6
 
5
7
  export default class CfFieldInputDateComponent extends Component {
8
+ @service intl;
9
+
6
10
  @action
7
11
  onChange(date) {
8
12
  // Change Javascript date to ISO string if not null.
9
- this.args.onSave(
10
- date
11
- ? moment({
12
- day: date.getUTCDate(),
13
- month: date.getUTCMonth(),
14
- year: date.getUTCFullYear(),
15
- }).format(moment.HTML5_FMT.DATE)
16
- : null
17
- );
13
+ this.args.onSave(date ? DateTime.fromJSDate(date).toISODate() : null);
14
+ }
15
+
16
+ @action
17
+ formatDate(date) {
18
+ return this.intl.formatDate(date, {
19
+ day: "2-digit",
20
+ month: "2-digit",
21
+ year: "numeric",
22
+ });
23
+ }
24
+
25
+ @cached
26
+ get pikadayTranslations() {
27
+ const locale = this.intl.primaryLocale;
28
+
29
+ return {
30
+ previousMonth: this.intl.t("caluma.form.pikaday.month-previous"),
31
+ nextMonth: this.intl.t("caluma.form.pikaday.month-next"),
32
+ months: Info.months("long", { locale }),
33
+ weekdays: Info.weekdays("long", { locale }),
34
+ weekdaysShort: Info.weekdays("short", { locale }),
35
+ };
18
36
  }
19
37
  }
@@ -8,7 +8,7 @@
8
8
  disabled={{@disabled}}
9
9
  {{on "change" this.save}}
10
10
  />
11
- <UkButton @color="primary" @disabled={{@disabled}}>
11
+ <UkButton disabled={{@disabled}}>
12
12
  {{t "caluma.form.selectFile"}}
13
13
  </UkButton>
14
14
  </div>
@@ -17,7 +17,7 @@
17
17
  <UkButton
18
18
  data-test-download-link
19
19
  @color="link"
20
- @on-click={{this.download}}
20
+ @onClick={{this.download}}
21
21
  >
22
22
  {{this.downloadName}}
23
23
  </UkButton>
@@ -22,11 +22,11 @@ export default class CfFieldInputFileComponent extends Component {
22
22
 
23
23
  @action
24
24
  async download() {
25
- const { downloadUrl } = await this.apollo.watchQuery(
25
+ const { downloadUrl } = await this.apollo.query(
26
26
  {
27
27
  query: getFileAnswerInfoQuery,
28
28
  variables: { id: this.args.field.answer.raw.id },
29
- fetchPolicy: "cache-and-network",
29
+ fetchPolicy: "network-only",
30
30
  },
31
31
  "node.fileValue"
32
32
  );
@@ -1,6 +1,9 @@
1
1
  {{#each @field.options as |option i|}}
2
2
  {{#if (gt i 0)}}<br />{{/if}}
3
- <label class={{if @field.isInvalid "uk-form-danger"}}>
3
+ <label
4
+ class="{{if @field.isInvalid 'uk-form-danger'}}
5
+ {{if @field.raw.question.meta.vertical 'uk-margin-large-right'}}"
6
+ >
4
7
  <input
5
8
  class="uk-radio uk-margin-small-right"
6
9
  type="radio"
@@ -1,4 +1,4 @@
1
1
  <MarkdownToHtml
2
- @markdown={{@field.question.staticContent}}
2
+ @markdown={{@field.question.raw.staticContent}}
3
3
  @openLinksInNewWindow={{true}}
4
4
  />
@@ -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>
@@ -9,4 +9,5 @@
9
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}}
@@ -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,50 +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
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.questionType) {
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.raw.id,
27
- label: 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 { label: field.answer.value };
38
- }
39
- }
40
-
41
10
  @action
42
11
  async download(id) {
43
12
  const { downloadUrl } = await this.apollo.query(
44
- { query: getFileAnswerInfoQuery, variables: { id } },
13
+ {
14
+ query: getFileAnswerInfoQuery,
15
+ variables: { id },
16
+ fetchPolicy: "network-only",
17
+ },
45
18
  "node.fileValue"
46
19
  );
47
20
 
48
- window.open(downloadUrl, "_blank");
21
+ if (downloadUrl) {
22
+ window.open(downloadUrl, "_blank");
23
+ }
49
24
  }
50
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}}
@@ -24,11 +32,11 @@
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,5 +1,5 @@
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
4
  import { timeout, restartableTask } from "ember-concurrency";
5
5
 
@@ -18,6 +18,16 @@ import { hasQuestionType } from "@projectcaluma/ember-core/helpers/has-question-
18
18
  * @argument {Field} field The field data model to render
19
19
  */
20
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
+
21
31
  get visible() {
22
32
  return (
23
33
  !this.args.field?.hidden &&
@@ -41,8 +51,9 @@ export default class CfFieldComponent extends Component {
41
51
  }
42
52
 
43
53
  /**
44
- * Task to save a field. This will set the passed value to the answer and
45
- * 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.
46
57
  *
47
58
  * @method save
48
59
  * @param {String|Number|String[]} value
@@ -57,14 +68,18 @@ export default class CfFieldComponent extends Component {
57
68
  yield timeout(500);
58
69
  }
59
70
 
60
- set(this.args.field.answer, "value", value);
71
+ if (this.args.field.answer) {
72
+ this.args.field.answer.value = value;
73
+ }
61
74
 
62
75
  yield this.args.field.validate.perform();
63
76
 
64
77
  try {
78
+ // Save the new field value unlinked so the fields save task is not
79
+ // aborted when this component is destroyed
65
80
  return yield this.args.field.save.unlinked().perform();
66
81
  } catch (e) {
67
- // that's ok
82
+ // The component was destroyed before the fields save task was finished
68
83
  }
69
84
  }
70
85
  }
@@ -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}}