@projectcaluma/ember-form 14.13.0 → 14.14.0

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.
@@ -70,6 +70,7 @@
70
70
  <UkButton
71
71
  @color="link"
72
72
  @onClick={{fn this.edit document}}
73
+ @disabled={{or this.add.isRunning this.delete.isRunning}}
73
74
  title={{t "caluma.form.edit"}}
74
75
  class="uk-flex-inline uk-margin-small-left table-controls"
75
76
  data-test-edit-row
@@ -80,6 +81,7 @@
80
81
  <UkButton
81
82
  @color="link"
82
83
  @onClick={{fn this.delete.perform document}}
84
+ @disabled={{or this.add.isRunning this.delete.isRunning}}
83
85
  title={{t "caluma.form.delete"}}
84
86
  class="uk-flex-inline uk-margin-small-left table-controls"
85
87
  data-test-delete-row
@@ -100,6 +102,8 @@
100
102
  <UkButton
101
103
  @color="link"
102
104
  @onClick={{this.add.perform}}
105
+ @disabled={{this.add.isRunning}}
106
+ @loading={{this.add.isRunning}}
103
107
  title={{t "caluma.form.addRow"}}
104
108
  data-test-add-row
105
109
  >
@@ -123,7 +127,7 @@
123
127
  <CfFormWrapper
124
128
  @document={{this.documentToEdit}}
125
129
  @fieldset={{object-at 0 this.documentToEdit.fieldsets}}
126
- @disabled={{@disabled}}
130
+ @disabled={{or @disabled this.add.isRunning}}
127
131
  @context={{@context}}
128
132
  @compare={{@compare}}
129
133
  />
@@ -143,7 +147,7 @@
143
147
  <UkButton
144
148
  @label={{t "caluma.form.cancel"}}
145
149
  @onClick={{this.close.perform}}
146
- @disabled={{this.close.isRunning}}
150
+ @disabled={{or this.close.isRunning this.add.isRunning}}
147
151
  @loading={{this.close.isRunning}}
148
152
  data-test-cancel
149
153
  />
@@ -74,22 +74,68 @@ export default class CfFieldInputTableComponent extends Component {
74
74
  owner,
75
75
  });
76
76
 
77
+ // Open the modal immediately - attaching the row to the table (below) is
78
+ // debounced and would otherwise noticeably delay opening the modal. While
79
+ // this task runs, the row's fields and the cancel button are disabled in
80
+ // the modal, so no answer can be saved to (and validated by) the backend
81
+ // and the row cannot be removed again before it is attached to the table.
77
82
  this.documentToEditIsNew = true;
78
83
  this.documentToEdit = newDocument;
79
84
  this.showAddModal = true;
80
- });
81
85
 
82
- delete = task({ drop: true }, async (document) => {
83
- if (!(await confirm(this.intl.t("caluma.form.deleteRow")))) {
84
- return;
86
+ // Attach the row document to the table answer, so the backend has the
87
+ // full context to validate and evaluate the row's fields while editing.
88
+ // `documentToEditIsNew` marks the row as preliminary, so it will be
89
+ // removed again if the edit dialog is cancelled.
90
+ try {
91
+ const rows = this.args.field.answer.value ?? [];
92
+ await this.args.onSave([...rows, newDocument]);
93
+ } catch {
94
+ this.notification.danger(
95
+ this.intl.t("caluma.form.notification.table.add.error"),
96
+ );
97
+
98
+ // Attaching failed - remove the preliminary row and close the modal.
99
+ // `close` cannot be performed here, as it waits for this task to finish.
100
+ await this.deleteRow(this.documentToEdit);
101
+ this.documentToEditIsNew = false;
102
+ this.showAddModal = false;
103
+ this.documentToEdit = null;
85
104
  }
105
+ });
86
106
 
87
- const remainingDocuments = this.args.field.answer.value.filter(
107
+ /**
108
+ * Delete row without asking. Remove from the table, then remove row document
109
+ *
110
+ * @async
111
+ * @method deleteRow
112
+ * @param {Document} document The row document to delete
113
+ * @return {Promise<Void>}
114
+ */
115
+ async deleteRow(document) {
116
+ const remainingDocuments = (this.args.field.answer.value ?? []).filter(
88
117
  (doc) => doc.pk !== document.pk,
89
118
  );
90
119
 
120
+ // remove row from table
91
121
  await this.args.onSave(remainingDocuments);
92
- await this.removeOrphan(document);
122
+
123
+ // delete row document
124
+ await this.apollo.mutate({
125
+ mutation: removeDocumentMutation,
126
+ variables: { input: { document: document.uuid } },
127
+ });
128
+
129
+ // Remove orphaned document from Caluma store.
130
+ this.calumaStore.delete(document.pk);
131
+ }
132
+
133
+ delete = task({ drop: true }, async (document) => {
134
+ if (!(await confirm(this.intl.t("caluma.form.deleteRow")))) {
135
+ return;
136
+ }
137
+
138
+ await this.deleteRow(document);
93
139
  });
94
140
 
95
141
  save = task({ drop: true }, async (validate) => {
@@ -106,19 +152,13 @@ export default class CfFieldInputTableComponent extends Component {
106
152
  return;
107
153
  }
108
154
 
109
- const rows = this.args.field.answer.value ?? [];
110
-
111
- if (!rows.find((doc) => doc.pk === newDocument.pk)) {
112
- // add document to table
113
- await this.args.onSave([...rows, newDocument]);
114
-
155
+ if (this.documentToEditIsNew) {
115
156
  this.notification.success(
116
157
  this.intl.t("caluma.form.notification.table.add.success"),
117
158
  );
159
+ this.documentToEditIsNew = false;
118
160
  }
119
161
 
120
- this.documentToEditIsNew = false;
121
-
122
162
  await this.close.perform();
123
163
  } catch {
124
164
  this.notification.danger(
@@ -128,10 +168,20 @@ export default class CfFieldInputTableComponent extends Component {
128
168
  });
129
169
 
130
170
  close = task({ drop: true }, async () => {
131
- if (this.documentToEditIsNew) {
132
- await this.removeOrphan(this.documentToEdit);
171
+ // Wait for a pending "add" to finish attaching the new row to the table
172
+ // before closing - otherwise removing or validating the row would race
173
+ // with the debounced save of the table answer.
174
+ if (this.add.isRunning) {
175
+ await this.add.last;
176
+ }
133
177
 
178
+ if (this.documentToEditIsNew) {
179
+ await this.deleteRow(this.documentToEdit);
134
180
  this.documentToEditIsNew = false;
181
+ this.showAddModal = false;
182
+ this.documentToEdit = null;
183
+ // No validation for new documents that are deleted
184
+ return;
135
185
  }
136
186
 
137
187
  if (!this.args.disabled) {
@@ -142,17 +192,6 @@ export default class CfFieldInputTableComponent extends Component {
142
192
  this.documentToEdit = null;
143
193
  });
144
194
 
145
- async removeOrphan(calumaDocument) {
146
- // Remove orphaned document from database.
147
- await this.apollo.mutate({
148
- mutation: removeDocumentMutation,
149
- variables: { input: { document: calumaDocument.uuid } },
150
- });
151
-
152
- // Remove orphaned document from Caluma store.
153
- this.calumaStore.delete(calumaDocument.pk);
154
- }
155
-
156
195
  @action
157
196
  edit(document) {
158
197
  this.documentToEdit = document;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@projectcaluma/ember-form",
3
- "version": "14.13.0",
3
+ "version": "14.14.0",
4
4
  "description": "Ember addon for rendering Caluma forms.",
5
5
  "keywords": [
6
6
  "ember-addon"
@@ -39,7 +39,7 @@
39
39
  "luxon": "^3.5.0",
40
40
  "reactiveweb": "^1.3.0",
41
41
  "tracked-toolbox": "^2.0.0",
42
- "@projectcaluma/ember-core": "^14.13.0"
42
+ "@projectcaluma/ember-core": "^14.14.0"
43
43
  },
44
44
  "devDependencies": {
45
45
  "@ember/optional-features": "2.3.0",
@@ -74,12 +74,12 @@
74
74
  "uikit": "3.25.6",
75
75
  "uuid": "13.0.0",
76
76
  "webpack": "5.104.1",
77
- "@projectcaluma/ember-testing": "14.13.0",
78
- "@projectcaluma/ember-workflow": "14.13.0"
77
+ "@projectcaluma/ember-testing": "14.14.0",
78
+ "@projectcaluma/ember-workflow": "14.14.0"
79
79
  },
80
80
  "peerDependencies": {
81
81
  "ember-source": ">= 4.0.0",
82
- "@projectcaluma/ember-workflow": "^14.13.0"
82
+ "@projectcaluma/ember-workflow": "^14.14.0"
83
83
  },
84
84
  "dependenciesMeta": {
85
85
  "@projectcaluma/ember-core": {