@dile/crud 1.8.1 → 1.9.1

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.
@@ -0,0 +1 @@
1
+ export { DileManyRelation } from './src/DileManyRelation.js';
@@ -0,0 +1,3 @@
1
+ import { DileManyRelation } from './src/DileManyRelation.js';
2
+
3
+ customElements.define('dile-many-relation', DileManyRelation);
@@ -0,0 +1,299 @@
1
+ import { LitElement, html, css } from 'lit';
2
+ import { DileI18nMixin } from '../../../lib/DileI18nMixin.js';
3
+ import { addIcon, clearIcon } from '@dile/icons';
4
+ import '../../ajax/ajax.js';
5
+ import '../../ajax-select-crud/ajax-select-crud.js';
6
+ import '@dile/ui/components/icon/icon.js';
7
+ import '@dile/ui/components/spinner/spinner.js';
8
+
9
+ export class DileManyRelation extends DileI18nMixin(LitElement) {
10
+ static styles = [
11
+ css`
12
+ :host {
13
+ display: block;
14
+ }
15
+ label {
16
+ display: block;
17
+ margin-bottom: var(--dile-input-label-margin-bottom, 4px);
18
+ font-size: var(--dile-input-label-font-size, 1em);
19
+ color: var(--dile-input-label-color, #59e);
20
+ font-weight: var(--dile-input-label-font-weight, normal);
21
+ }
22
+ dile-ajax-select-crud{
23
+ margin-bottom: 0;
24
+ }
25
+ .relation-item {
26
+ display: flex;
27
+ align-items: center;
28
+ gap: 0.5rem;
29
+ padding: 0.25rem 0;
30
+ }
31
+ .relation-item-content {
32
+ flex: 1;
33
+ padding-left: 0.4rem;
34
+ font-size: var(--many-relation-item-font-size, 0.9rem);
35
+ color: var(--many-relation-item-color, inherit);
36
+ }
37
+ button.remove-btn,
38
+ button.add-btn {
39
+ background: none;
40
+ border: none;
41
+ padding: 0;
42
+ cursor: pointer;
43
+ display: flex;
44
+ align-items: center;
45
+ justify-content: center;
46
+ width: var(--many-relation-add-size, 38px);
47
+ flex-shrink: 0;
48
+ }
49
+ button.remove-btn:disabled {
50
+ opacity: 0.4;
51
+ cursor: not-allowed;
52
+ }
53
+ button.remove-btn dile-icon {
54
+ --dile-icon-color: var(--many-relation-remove-color, #c00);
55
+ --dile-icon-size: var(--many-relation-remove-size, 24px);
56
+ }
57
+ .add-row {
58
+ display: flex;
59
+ align-items: center;
60
+ gap: 0.5rem;
61
+ margin-bottom: 0.5rem;
62
+ }
63
+ .add-row dile-ajax-select-crud {
64
+ flex: 1;
65
+ }
66
+ button.add-btn dile-icon {
67
+ --dile-icon-color: var(--many-relation-add-color, #2962ff);
68
+ --dile-icon-size: var(--many-relation-add-size, 38px);
69
+ margin-bottom: 8px;
70
+ }
71
+ button.add-btn:disabled dile-icon {
72
+ --dile-icon-color: var(--many-relation-add-disabled-color, #ccc);
73
+ }
74
+ button.add-btn:disabled {
75
+ cursor: default;
76
+ }
77
+ .empty-msg {
78
+ color: var(--many-relation-empty-color, #888);
79
+ font-style: var(--many-relation-empty-font-style, italic);
80
+ font-size: var(--many-relation-empty-font-size, 0.9rem);
81
+ }
82
+ `
83
+ ];
84
+
85
+ static get properties() {
86
+ return {
87
+ label: { type: String },
88
+
89
+ // Endpoints
90
+ endpointGet: { type: String },
91
+ endpointList: { type: String },
92
+ endpointAdd: { type: String },
93
+ endpointRemove: { type: String },
94
+
95
+ // Initial data behaviour
96
+ relatedItems: { type: Array },
97
+ loadFromEndpoint: { type: Boolean },
98
+
99
+ // Select (dile-ajax-select-crud) passthrough
100
+ displayProperty: { type: String },
101
+ idProperty: { type: String },
102
+ queryStringVariable: { type: String },
103
+ placeholder: { type: String },
104
+ selectDefaultPlaceholder: { type: String },
105
+ resultDataProperty: { type: String },
106
+ maxResults: { type: Number },
107
+ pageParamName: { type: String },
108
+ getSelectResultList: { type: Object },
109
+
110
+ // Related list customisation
111
+ itemTemplate: { type: Object },
112
+ getListItems: { type: Object },
113
+ addRelationLabel: { type: String },
114
+ bodyIdProperty: { type: String },
115
+
116
+ // Internal state
117
+ _items: { type: Array, state: true },
118
+ _selectedId: { type: String, state: true },
119
+ _removingItemId: { type: String, state: true },
120
+ _loadingList: { type: Boolean, state: true },
121
+ };
122
+ }
123
+
124
+ constructor() {
125
+ super();
126
+ this.relatedItems = [];
127
+ this._items = [];
128
+ this.loadFromEndpoint = false;
129
+ this.displayProperty = 'name';
130
+ this.idProperty = 'id';
131
+ this.getListItems = (response) => response.data;
132
+ this.itemTemplate = (item) => html`${item[this.displayProperty]}`;
133
+ this.bodyIdProperty = null;
134
+ this._loadingList = false;
135
+ }
136
+
137
+ updated(changedProperties) {
138
+ if (changedProperties.has('relatedItems') && !this.loadFromEndpoint) {
139
+ this._items = [...this.relatedItems];
140
+ }
141
+ }
142
+
143
+ firstUpdated() {
144
+ this._ajaxlist = this.shadowRoot.getElementById('ajaxlist');
145
+ this._ajaxadd = this.shadowRoot.getElementById('ajaxadd');
146
+ this._ajaxrem = this.shadowRoot.getElementById('ajaxrem');
147
+
148
+ if (this.loadFromEndpoint) {
149
+ this._refreshList();
150
+ }
151
+ }
152
+
153
+ render() {
154
+ return html`
155
+ <dile-ajax
156
+ id="ajaxlist"
157
+ method="get"
158
+ url="${this.endpointList}"
159
+ @ajax-success="${this._onListSuccess}"
160
+ @ajax-error="${this._onListError}"
161
+ ></dile-ajax>
162
+ <dile-ajax
163
+ id="ajaxadd"
164
+ method="post"
165
+ url="${this.endpointAdd}"
166
+ @ajax-success="${this._onAddSuccess}"
167
+ @ajax-error="${this._onAddError}"
168
+ ></dile-ajax>
169
+ <dile-ajax
170
+ id="ajaxrem"
171
+ method="delete"
172
+ @ajax-success="${this._onRemoveSuccess}"
173
+ @ajax-error="${this._onRemoveError}"
174
+ ></dile-ajax>
175
+
176
+ ${this.label
177
+ ? html`<label for="textField">${this.label}</label>`
178
+ : ""
179
+ }
180
+ <div class="add-row">
181
+ <dile-ajax-select-crud
182
+ id="theselect"
183
+ endpoint="${this.endpointGet}"
184
+ displayProperty="${this.displayProperty}"
185
+ idProperty="${this.idProperty}"
186
+ queryStringVariable="${this.queryStringVariable}"
187
+ placeholder="${this.placeholder}"
188
+ selectDefaultPlaceholder="${this.selectDefaultPlaceholderComputed(this.selectDefaultPlaceholder, this.translations)}"
189
+ resultDataProperty="${this.resultDataProperty}"
190
+ maxResults="${this.maxResults}"
191
+ pageParamName="${this.pageParamName}"
192
+ .getSelectResultList="${this.getSelectResultList}"
193
+ language="${this.language}"
194
+ @element-changed="${this._onSelectChanged}"
195
+ ></dile-ajax-select-crud>
196
+ <button
197
+ class="add-btn"
198
+ ?disabled="${!this._selectedId}"
199
+ title="${this.addRelationLabelComputed(this.addRelationLabel, this.translations)}"
200
+ @click="${this._addSelectedItem}"
201
+ ><dile-icon .icon="${addIcon}"></dile-icon></button>
202
+ </div>
203
+
204
+ ${this._loadingList
205
+ ? html`<dile-spinner active></dile-spinner>`
206
+ : this._items.length === 0
207
+ ? html`<p class="empty-msg">${this.translations?.empty_list ?? 'There are no items yet'}</p>`
208
+ : this._items.map(item => html`
209
+ <div class="relation-item">
210
+ <span class="relation-item-content">${this.itemTemplate(item)}</span>
211
+ <button
212
+ class="remove-btn"
213
+ ?disabled="${this._removingItemId === item[this.idProperty]}"
214
+ @click="${() => this._removeItem(item)}"
215
+ title="${this.translations?.delete_label ?? 'Delete'}"
216
+ ><dile-icon .icon="${clearIcon}"></dile-icon></button>
217
+ </div>
218
+ `)
219
+ }
220
+ `;
221
+ }
222
+
223
+ _onSelectChanged(e) {
224
+ this._selectedId = e.detail.value || null;
225
+ }
226
+
227
+ _addSelectedItem() {
228
+ if (!this._selectedId) {
229
+ this._dispatch('many-relation-add-no-selection');
230
+ return;
231
+ }
232
+ const bodyKey = this.bodyIdProperty || this.idProperty;
233
+ this._ajaxadd.data = { [bodyKey]: this._selectedId };
234
+ this._ajaxadd.generateRequest();
235
+ }
236
+
237
+ _onAddSuccess() {
238
+ this._selectedId = null;
239
+ this._clearSelect();
240
+ this._refreshList();
241
+ this._dispatch('many-relation-add-success');
242
+ }
243
+
244
+ _onAddError() {
245
+ this._dispatch('many-relation-add-error');
246
+ }
247
+
248
+ _removeItem(item) {
249
+ const id = item[this.idProperty];
250
+ this._removingItemId = id;
251
+ this._ajaxrem.url = `${this.endpointRemove}/${id}`;
252
+ this._ajaxrem.generateRequest();
253
+ }
254
+
255
+ _onRemoveSuccess() {
256
+ this._removingItemId = undefined;
257
+ this._refreshList();
258
+ this._dispatch('many-relation-remove-success');
259
+ }
260
+
261
+ _onRemoveError() {
262
+ this._removingItemId = undefined;
263
+ this._dispatch('many-relation-remove-error');
264
+ }
265
+
266
+ _refreshList() {
267
+ this._loadingList = true;
268
+ this.updateComplete.then(() => this._ajaxlist.generateRequest());
269
+ }
270
+
271
+ _onListSuccess(e) {
272
+ this._items = this.getListItems(e.detail);
273
+ this._loadingList = false;
274
+ }
275
+
276
+ _onListError() {
277
+ this._loadingList = false;
278
+ this._dispatch('many-relation-list-error');
279
+ }
280
+
281
+ _clearSelect() {
282
+ const select = this.shadowRoot.getElementById('theselect');
283
+ if (select) {
284
+ select.clear();
285
+ }
286
+ }
287
+
288
+ _dispatch(eventName) {
289
+ this.dispatchEvent(new CustomEvent(eventName, { bubbles: true, composed: true }));
290
+ }
291
+
292
+ addRelationLabelComputed(label, translations) {
293
+ return label ? label : translations?.add_relation_label ?? 'Add';
294
+ }
295
+
296
+ selectDefaultPlaceholderComputed(value, translations) {
297
+ return value ? value : translations?.select_relation_placeholder ?? 'Select...';
298
+ }
299
+ }
package/lib/i18n/en.js CHANGED
@@ -54,4 +54,6 @@ export const translations = {
54
54
  extension_allowed: "Only this file extensions are allowed: ",
55
55
  confirm_submit_title: "Confirm submission",
56
56
  confirm_submit_text: "Are you sure you want to submit this form?",
57
+ add_relation_label: "Add",
58
+ select_relation_placeholder: "Select...",
57
59
  };
package/lib/i18n/es.js CHANGED
@@ -54,4 +54,6 @@ export const translations = {
54
54
  extension_allowed: "Solo se permiten estas extensiones: ",
55
55
  confirm_submit_title: "Confirmar envío",
56
56
  confirm_submit_text: "¿Estás seguro de que deseas enviar este formulario?",
57
+ add_relation_label: "Añadir",
58
+ select_relation_placeholder: "Selecciona...",
57
59
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dile/crud",
3
- "version": "1.8.1",
3
+ "version": "1.9.1",
4
4
  "description": "Components to create a generic crud system based on Web Components and Lit",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -24,12 +24,12 @@
24
24
  },
25
25
  "homepage": "https://dile-components.com/",
26
26
  "dependencies": {
27
- "@dile/ui": "^2.21.2",
27
+ "@dile/ui": "^2.21.3",
28
28
  "axios": "^1.16.0",
29
29
  "lit": "^2.7.0 || ^3.0.0"
30
30
  },
31
31
  "publishConfig": {
32
32
  "access": "public"
33
33
  },
34
- "gitHead": "5c09eb3ba4a0f9fcc4235d670c00ab91bf68860c"
34
+ "gitHead": "f56676f00eb84aed3ee4ffd8a0542988da652d51"
35
35
  }