@projectcaluma/ember-form 11.0.0-beta.2 → 11.0.0-beta.20
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.
- package/CHANGELOG.md +190 -0
- package/addon/components/cf-content.hbs +37 -37
- package/addon/components/cf-content.js +2 -2
- package/addon/components/cf-field/hint.hbs +5 -0
- package/addon/components/cf-field/info.hbs +2 -2
- package/addon/components/cf-field/info.js +0 -15
- package/addon/components/cf-field/input/action-button.hbs +8 -4
- package/addon/components/cf-field/input/action-button.js +60 -59
- package/addon/components/cf-field/input/checkbox.hbs +3 -4
- package/addon/components/cf-field/input/date.hbs +10 -5
- package/addon/components/cf-field/input/date.js +40 -10
- package/addon/components/cf-field/input/file.hbs +2 -2
- package/addon/components/cf-field/input/file.js +2 -2
- package/addon/components/cf-field/input/powerselect.hbs +27 -29
- package/addon/components/cf-field/input/powerselect.js +8 -2
- package/addon/components/cf-field/input/radio.hbs +2 -2
- package/addon/components/cf-field/input/static.hbs +1 -1
- package/addon/components/cf-field/input/table.hbs +25 -24
- package/addon/components/cf-field/input/table.js +1 -11
- package/addon/components/cf-field/input.hbs +8 -21
- package/addon/components/cf-field/input.js +32 -14
- package/addon/components/cf-field/label.hbs +4 -2
- package/addon/components/cf-field-value.hbs +22 -7
- package/addon/components/cf-field-value.js +8 -33
- package/addon/components/cf-field.hbs +39 -6
- package/addon/components/cf-field.js +37 -17
- package/addon/components/cf-form-wrapper.hbs +3 -1
- package/addon/components/document-validity.js +16 -1
- package/addon/gql/fragments/field.graphql +30 -0
- package/addon/helpers/format-graphql-error.js +21 -0
- package/addon/helpers/get-widget.js +16 -2
- package/addon/instance-initializers/form-widget-overrides.js +52 -0
- package/addon/lib/field.js +73 -46
- package/addon/lib/navigation.js +3 -1
- package/addon/lib/question.js +12 -4
- package/addon/modifiers/autoresize.js +16 -0
- package/app/components/cf-field/hint.js +1 -0
- package/app/helpers/format-graphql-error.js +1 -0
- package/app/helpers/get-widget.js +1 -4
- package/app/instance-initializers/form-widget-overrides.js +4 -0
- package/app/modifiers/autoresize.js +1 -0
- package/app/styles/@projectcaluma/ember-form.scss +3 -15
- package/package.json +37 -25
- package/translations/de.yaml +6 -2
- package/translations/en.yaml +6 -2
- package/translations/fr.yaml +6 -2
- package/addon/components/cf-field/label.js +0 -11
- package/addon/instance-initializers/setup-pikaday-i18n.js +0 -35
@@ -1,29 +1,27 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
{{
|
26
|
-
|
27
|
-
|
28
|
-
</DynamicSelect>
|
29
|
-
{{/let}}
|
1
|
+
<this.selectComponent
|
2
|
+
@options={{@field.options}}
|
3
|
+
@selected={{@field.selected}}
|
4
|
+
@disabled={{@disabled}}
|
5
|
+
@allowClear={{true}}
|
6
|
+
@preventScroll={{true}}
|
7
|
+
@searchEnabled={{this.searchEnabled}}
|
8
|
+
@searchField="label"
|
9
|
+
@triggerId={{@field.pk}}
|
10
|
+
@renderInPlace={{true}}
|
11
|
+
@placeholder={{this.placeholder}}
|
12
|
+
@loadingMessage={{t "caluma.form.power-select.options-loading"}}
|
13
|
+
@searchMessage={{t "caluma.form.power-select.options-empty"}}
|
14
|
+
@searchPlaceholder={{t "caluma.form.power-select.search-placeholder"}}
|
15
|
+
@noMatchesMessage={{t "caluma.form.power-select.search-empty"}}
|
16
|
+
@onChange={{this.change}}
|
17
|
+
as |option|
|
18
|
+
>
|
19
|
+
{{#if (and option.disabled (not @disabled))}}
|
20
|
+
<del
|
21
|
+
class="uk-text-muted"
|
22
|
+
title={{t "caluma.form.optionNotAvailable"}}
|
23
|
+
>{{option.label}}</del>
|
24
|
+
{{else}}
|
25
|
+
{{option.label}}
|
26
|
+
{{/if}}
|
27
|
+
</this.selectComponent>
|
@@ -1,7 +1,10 @@
|
|
1
1
|
import { getOwner } from "@ember/application";
|
2
2
|
import { action } from "@ember/object";
|
3
3
|
import { inject as service } from "@ember/service";
|
4
|
+
import { ensureSafeComponent } from "@embroider/util";
|
4
5
|
import Component from "@glimmer/component";
|
6
|
+
import PowerSelectComponent from "ember-power-select/components/power-select";
|
7
|
+
import PowerSelectMultipleComponent from "ember-power-select/components/power-select-multiple";
|
5
8
|
|
6
9
|
/**
|
7
10
|
* Dropdown component for the single and multiple choice question type
|
@@ -16,8 +19,11 @@ export default class CfFieldInputPowerselectComponent extends Component {
|
|
16
19
|
return this.args.field?.question.isMultipleChoice;
|
17
20
|
}
|
18
21
|
|
19
|
-
get
|
20
|
-
return
|
22
|
+
get selectComponent() {
|
23
|
+
return ensureSafeComponent(
|
24
|
+
this.multiple ? PowerSelectMultipleComponent : PowerSelectComponent,
|
25
|
+
this
|
26
|
+
);
|
21
27
|
}
|
22
28
|
|
23
29
|
get searchEnabled() {
|
@@ -1,5 +1,5 @@
|
|
1
1
|
{{#each @field.options as |option i|}}
|
2
|
-
{{#if (gt i 0)}}<br />{{/if}}
|
2
|
+
{{#if (and (gt i 0) (not @field.raw.question.meta.vertical))}}<br />{{/if}}
|
3
3
|
<label
|
4
4
|
class="{{if @field.isInvalid 'uk-form-danger'}}
|
5
5
|
{{if @field.raw.question.meta.vertical 'uk-margin-large-right'}}"
|
@@ -10,7 +10,7 @@
|
|
10
10
|
name={{@field.pk}}
|
11
11
|
value={{option.slug}}
|
12
12
|
checked={{eq option.slug @field.answer.value}}
|
13
|
-
disabled={{@disabled}}
|
13
|
+
disabled={{or option.disabled @disabled}}
|
14
14
|
{{on "change" (fn @onSave option.slug)}}
|
15
15
|
/>
|
16
16
|
{{#if (and option.disabled (not @disabled))}}
|
@@ -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
|
-
<
|
29
|
-
|
30
|
-
|
31
|
-
class="uk-button 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
|
-
|
32
|
+
class="uk-flex-inline uk-margin-small-left table-controls"
|
33
|
+
data-test-edit-row
|
34
34
|
>
|
35
35
|
<UkIcon @icon="pencil" />
|
36
|
-
<span
|
37
|
-
</
|
36
|
+
<span hidden>{{t "caluma.form.edit"}}</span>
|
37
|
+
</UkButton>
|
38
38
|
{{#unless @disabled}}
|
39
|
-
<
|
40
|
-
|
41
|
-
|
42
|
-
class="uk-button 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
|
-
|
43
|
+
class="uk-flex-inline uk-margin-small-left table-controls"
|
44
|
+
data-test-delete-row
|
45
45
|
>
|
46
46
|
<UkIcon @icon="trash" />
|
47
|
-
<span
|
48
|
-
</
|
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
|
-
@
|
61
|
-
@
|
62
|
-
|
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
|
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
|
-
@
|
77
|
+
@onHide={{perform this.close}}
|
78
78
|
@bgClose={{false}}
|
79
79
|
as |modal|
|
80
80
|
>
|
@@ -83,15 +83,16 @@
|
|
83
83
|
@document={{this.documentToEdit}}
|
84
84
|
@fieldset={{object-at 0 this.documentToEdit.fieldsets}}
|
85
85
|
@disabled={{@disabled}}
|
86
|
+
@context={{@context}}
|
86
87
|
/>
|
87
88
|
</modal.body>
|
88
89
|
|
89
|
-
<modal.footer
|
90
|
+
<modal.footer class="uk-text-right">
|
90
91
|
{{#if @disabled}}
|
91
92
|
<UkButton
|
92
93
|
@label={{t "caluma.form.close"}}
|
93
94
|
@color="primary"
|
94
|
-
@
|
95
|
+
@onClick={{perform this.close}}
|
95
96
|
@disabled={{this.close.isRunning}}
|
96
97
|
@loading={{this.close.isRunning}}
|
97
98
|
data-test-close
|
@@ -99,7 +100,7 @@
|
|
99
100
|
{{else}}
|
100
101
|
<UkButton
|
101
102
|
@label={{t "caluma.form.cancel"}}
|
102
|
-
@
|
103
|
+
@onClick={{perform this.close}}
|
103
104
|
@disabled={{this.close.isRunning}}
|
104
105
|
@loading={{this.close.isRunning}}
|
105
106
|
data-test-cancel
|
@@ -114,7 +115,7 @@
|
|
114
115
|
@type="submit"
|
115
116
|
@disabled={{or this.save.isRunning (not isValid)}}
|
116
117
|
@loading={{this.save.isRunning}}
|
117
|
-
@
|
118
|
+
@onClick={{fn (perform this.save) validate}}
|
118
119
|
data-test-save
|
119
120
|
/>
|
120
121
|
</DocumentValidity>
|
@@ -5,22 +5,12 @@ import Component from "@glimmer/component";
|
|
5
5
|
import { tracked } from "@glimmer/tracking";
|
6
6
|
import { queryManager } from "ember-apollo-client";
|
7
7
|
import { dropTask } from "ember-concurrency";
|
8
|
-
import
|
8
|
+
import { confirm } from "ember-uikit";
|
9
9
|
|
10
10
|
import removeDocumentMutation from "@projectcaluma/ember-form/gql/mutations/remove-document.graphql";
|
11
11
|
import saveDocumentMutation from "@projectcaluma/ember-form/gql/mutations/save-document.graphql";
|
12
12
|
import { parseDocument } from "@projectcaluma/ember-form/lib/parsers";
|
13
13
|
|
14
|
-
async function confirm(text) {
|
15
|
-
try {
|
16
|
-
await UIkit.modal.confirm(text);
|
17
|
-
|
18
|
-
return true;
|
19
|
-
} catch (error) {
|
20
|
-
return false;
|
21
|
-
}
|
22
|
-
}
|
23
|
-
|
24
14
|
export default class CfFieldInputTableComponent extends Component {
|
25
15
|
@service notification;
|
26
16
|
@service intl;
|
@@ -1,21 +1,8 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
)
|
10
|
-
'uk-flex'
|
11
|
-
}}"
|
12
|
-
>
|
13
|
-
<InputComponent
|
14
|
-
@field={{@field}}
|
15
|
-
@disabled={{@disabled}}
|
16
|
-
@onSave={{@onSave}}
|
17
|
-
@context={{@context}}
|
18
|
-
/>
|
19
|
-
</div>
|
20
|
-
{{/let}}
|
21
|
-
{{/if}}
|
1
|
+
<div class="uk-form-controls">
|
2
|
+
<this.inputComponent
|
3
|
+
@field={{@field}}
|
4
|
+
@disabled={{@disabled}}
|
5
|
+
@onSave={{@onSave}}
|
6
|
+
@context={{@context}}
|
7
|
+
/>
|
8
|
+
</div>
|
@@ -1,12 +1,33 @@
|
|
1
|
-
import {
|
1
|
+
import { ensureSafeComponent } from "@embroider/util";
|
2
2
|
import Component from "@glimmer/component";
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
4
|
+
import ActionButtonComponent from "@projectcaluma/ember-form/components/cf-field/input/action-button";
|
5
|
+
import CheckboxComponent from "@projectcaluma/ember-form/components/cf-field/input/checkbox";
|
6
|
+
import DateComponent from "@projectcaluma/ember-form/components/cf-field/input/date";
|
7
|
+
import FileComponent from "@projectcaluma/ember-form/components/cf-field/input/file";
|
8
|
+
import FloatComponent from "@projectcaluma/ember-form/components/cf-field/input/float";
|
9
|
+
import IntegerComponent from "@projectcaluma/ember-form/components/cf-field/input/integer";
|
10
|
+
import RadioComponent from "@projectcaluma/ember-form/components/cf-field/input/radio";
|
11
|
+
import StaticComponent from "@projectcaluma/ember-form/components/cf-field/input/static";
|
12
|
+
import TableComponent from "@projectcaluma/ember-form/components/cf-field/input/table";
|
13
|
+
import TextComponent from "@projectcaluma/ember-form/components/cf-field/input/text";
|
14
|
+
import TextareaComponent from "@projectcaluma/ember-form/components/cf-field/input/textarea";
|
15
|
+
|
16
|
+
const COMPONENT_MAPPING = {
|
17
|
+
ActionButtonQuestion: ActionButtonComponent,
|
18
|
+
CalculatedFloatQuestion: FloatComponent,
|
19
|
+
ChoiceQuestion: RadioComponent,
|
20
|
+
DateQuestion: DateComponent,
|
21
|
+
DynamicChoiceQuestion: RadioComponent,
|
22
|
+
DynamicMultipleChoiceQuestion: CheckboxComponent,
|
23
|
+
FileQuestion: FileComponent,
|
24
|
+
FloatQuestion: FloatComponent,
|
25
|
+
IntegerQuestion: IntegerComponent,
|
26
|
+
MultipleChoiceQuestion: CheckboxComponent,
|
27
|
+
StaticQuestion: StaticComponent,
|
28
|
+
TableQuestion: TableComponent,
|
29
|
+
TextareaQuestion: TextareaComponent,
|
30
|
+
TextQuestion: TextComponent,
|
10
31
|
};
|
11
32
|
|
12
33
|
/**
|
@@ -16,17 +37,14 @@ const mapping = {
|
|
16
37
|
*/
|
17
38
|
export default class CfFieldInputComponent extends Component {
|
18
39
|
/**
|
19
|
-
* The input component
|
40
|
+
* The input component
|
20
41
|
*
|
21
|
-
* @property {
|
42
|
+
* @property {Component} inputComponent
|
22
43
|
* @accessor
|
23
44
|
*/
|
24
|
-
get
|
45
|
+
get inputComponent() {
|
25
46
|
const typename = this.args.field?.question.raw.__typename;
|
26
47
|
|
27
|
-
return (
|
28
|
-
typename &&
|
29
|
-
(mapping[typename] || dasherize(typename.replace(/Question$/, "")))
|
30
|
-
);
|
48
|
+
return ensureSafeComponent(COMPONENT_MAPPING[typename], this);
|
31
49
|
}
|
32
50
|
}
|
@@ -1,11 +1,13 @@
|
|
1
|
-
<label class="uk-form-label" for={{@field.pk}}>
|
1
|
+
<label class="uk-form-label" for={{@field.pk}} ...attributes>
|
2
2
|
<span class="uk-text-bold">
|
3
3
|
{{@field.question.raw.label}}
|
4
4
|
</span>
|
5
5
|
|
6
|
-
{{#if
|
6
|
+
{{#if (and (not @field.question.isCalculated) @field.optional)}}
|
7
7
|
<span
|
8
8
|
class="uk-margin-small-left uk-text-muted uk-text-lowercase uk-text-normal"
|
9
9
|
>({{t "caluma.form.optional"}})</span>
|
10
10
|
{{/if}}
|
11
|
+
|
12
|
+
{{yield}}
|
11
13
|
</label>
|
@@ -1,9 +1,24 @@
|
|
1
|
-
{{#if
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
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
|
-
{{
|
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
|
-
{
|
13
|
+
{
|
14
|
+
query: getFileAnswerInfoQuery,
|
15
|
+
variables: { id },
|
16
|
+
fetchPolicy: "network-only",
|
17
|
+
},
|
45
18
|
"node.fileValue"
|
46
19
|
);
|
47
20
|
|
48
|
-
|
21
|
+
if (downloadUrl) {
|
22
|
+
window.open(downloadUrl, "_blank");
|
23
|
+
}
|
49
24
|
}
|
50
25
|
}
|
@@ -1,12 +1,23 @@
|
|
1
1
|
{{#if this.visible}}
|
2
|
-
<div
|
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}}
|
6
14
|
|
7
15
|
<div class="uk-flex">
|
8
16
|
<div class="uk-width-expand">
|
9
|
-
{{#let
|
17
|
+
{{#let
|
18
|
+
(component (ensure-safe-component (get-widget @field.question)))
|
19
|
+
as |FieldComponent|
|
20
|
+
}}
|
10
21
|
<FieldComponent
|
11
22
|
@field={{@field}}
|
12
23
|
@disabled={{@disabled}}
|
@@ -24,17 +35,39 @@
|
|
24
35
|
<div
|
25
36
|
class="cf-field__icon uk-padding-remove-vertical uk-flex uk-flex-middle uk-flex-center"
|
26
37
|
>
|
27
|
-
{{#if
|
38
|
+
{{#if this.save.isRunning}}
|
28
39
|
<UkSpinner class="uk-animation-fade" />
|
29
|
-
{{else if (or
|
30
|
-
<
|
31
|
-
|
40
|
+
{{else if (or this.save.last.isError @field.isInvalid)}}
|
41
|
+
<div class="uk-flex-inline">
|
42
|
+
<UkIcon
|
43
|
+
@icon="warning"
|
44
|
+
class="uk-animation-fade uk-text-danger"
|
45
|
+
/>
|
46
|
+
{{#if this.save.last.error}}
|
47
|
+
<div uk-dropdown="pos: bottom-left" class="uk-padding-small">
|
48
|
+
<div class="uk-alert uk-alert-danger uk-margin-small">
|
49
|
+
{{t "caluma.form.error.intro"}}
|
50
|
+
</div>
|
51
|
+
<p class="uk-text-meta uk-margin-small">
|
52
|
+
{{t "caluma.form.error.details"}}
|
53
|
+
</p>
|
54
|
+
<pre class="uk-margin-remove">
|
55
|
+
{{~format-graphql-error this.save.last.error~}}
|
56
|
+
</pre>
|
57
|
+
</div>
|
58
|
+
{{/if}}
|
59
|
+
</div>
|
60
|
+
{{else if this.save.last.isSuccessful}}
|
32
61
|
<UkIcon @icon="check" class="uk-animation-fade uk-text-success" />
|
33
62
|
{{/if}}
|
34
63
|
</div>
|
35
64
|
{{/if}}
|
36
65
|
</div>
|
37
66
|
|
67
|
+
{{#if (and @field.question.raw.hintText this.hintTextVisible)}}
|
68
|
+
<CfField::hint @field={{@field}} />
|
69
|
+
{{/if}}
|
70
|
+
|
38
71
|
{{#if @field.errors.length}}
|
39
72
|
<CfField::errors @field={{@field}} />
|
40
73
|
{{/if}}
|
@@ -1,5 +1,5 @@
|
|
1
|
-
import {
|
2
|
-
import {
|
1
|
+
import { action } from "@ember/object";
|
2
|
+
import { macroCondition, isTesting } from "@embroider/macros";
|
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 &&
|
@@ -36,35 +46,45 @@ export default class CfFieldComponent extends Component {
|
|
36
46
|
return !hasQuestionType(this.args.field?.question, "action-button");
|
37
47
|
}
|
38
48
|
|
49
|
+
get hintTextVisible() {
|
50
|
+
return !hasQuestionType(
|
51
|
+
this.args.field?.question,
|
52
|
+
"action-button",
|
53
|
+
"static",
|
54
|
+
"form"
|
55
|
+
);
|
56
|
+
}
|
57
|
+
|
39
58
|
get saveIndicatorVisible() {
|
40
59
|
return !hasQuestionType(this.args.field?.question, "action-button");
|
41
60
|
}
|
42
61
|
|
43
62
|
/**
|
44
|
-
* Task to save a field. This will set the passed value to the answer and
|
45
|
-
*
|
63
|
+
* Task to save a field. This will set the passed value to the answer and save
|
64
|
+
* the field to the API after a timeout of 500 milliseconds which intends to
|
65
|
+
* reduce the amount of saved values when changed rapidly.
|
46
66
|
*
|
47
67
|
* @method save
|
48
|
-
* @param {String|Number|String[]} value
|
68
|
+
* @param {String|Number|String[]} value The new value to save to the field
|
69
|
+
* @param {Boolean} bypassTimeout Whether to bypass the timeout
|
49
70
|
*/
|
50
71
|
@restartableTask
|
51
|
-
*save(value) {
|
52
|
-
const { environment } =
|
53
|
-
getOwner(this).resolveRegistration("config:environment");
|
54
|
-
|
72
|
+
*save(value, bypassTimeout = false) {
|
55
73
|
/* istanbul ignore next */
|
56
|
-
if (
|
57
|
-
|
74
|
+
if (macroCondition(isTesting())) {
|
75
|
+
// no timeout
|
76
|
+
} else {
|
77
|
+
if (!bypassTimeout) {
|
78
|
+
yield timeout(500);
|
79
|
+
}
|
58
80
|
}
|
59
81
|
|
60
|
-
|
82
|
+
if (this.args.field.answer) {
|
83
|
+
this.args.field.answer.value = value;
|
84
|
+
}
|
61
85
|
|
62
86
|
yield this.args.field.validate.perform();
|
63
87
|
|
64
|
-
|
65
|
-
return yield this.args.field.save.unlinked().perform();
|
66
|
-
} catch (e) {
|
67
|
-
// that's ok
|
68
|
-
}
|
88
|
+
return yield this.args.field.save.unlinked().perform();
|
69
89
|
}
|
70
90
|
}
|
@@ -1,6 +1,7 @@
|
|
1
1
|
import { action } from "@ember/object";
|
2
2
|
import Component from "@glimmer/component";
|
3
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
|
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
|
}
|