@smartsoft001/crud-shell-angular 2.81.0 → 2.82.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.
@@ -1,9 +1,9 @@
1
1
  import * as i0 from '@angular/core';
2
- import { Injectable, inject, computed, ElementRef, Component, input, Directive, signal, InjectionToken, Pipe, NgModule, viewChild, viewChildren, output, ChangeDetectorRef, effect, Injector } from '@angular/core';
3
- import { PaginationMode, BaseComponent as BaseComponent$1, PopoverService, StyleService, ButtonComponent, MenuService, FormComponent, AccordionComponent, AccordionHeaderComponent, AccordionBodyComponent, ListComponent as ListComponent$1, SharedModule, DetailsComponent, AuthService, CreateDynamicComponent, DynamicComponentLoader, ToastService, DetailsService, DynamicContentDirective, PageComponent, HardwareService, ListMode, FILE_SERVICE_CONFIG } from '@smartsoft001/angular';
4
- import { patchState, signalStore, withState, withComputed, withMethods } from '@ngrx/signals';
5
- import { HttpClient } from '@angular/common/http';
6
- import { firstValueFrom, Subscription, BehaviorSubject, combineLatest, Subject } from 'rxjs';
2
+ import { Injectable, inject, ElementRef, Component, input, Directive, computed, signal, InjectionToken, Pipe, NgModule, viewChild, viewChildren, output, ChangeDetectorRef, effect, Injector } from '@angular/core';
3
+ import { NgrxStoreService, BaseComponent as BaseComponent$1, PopoverService, StyleService, ButtonComponent, MenuService, FormComponent, AccordionComponent, AccordionHeaderComponent, AccordionBodyComponent, ListComponent as ListComponent$1, SharedModule, DetailsComponent, AuthService, CreateDynamicComponent, DynamicComponentLoader, ToastService, DetailsService, DynamicContentDirective, PageComponent, HardwareService, ListMode, FILE_SERVICE_CONFIG } from '@smartsoft001/angular';
4
+ import { toSignal } from '@angular/core/rxjs-interop';
5
+ import * as i1 from '@ngrx/store';
6
+ import { createFeatureSelector, createSelector, select as select$1 } from '@ngrx/store';
7
7
  import { map } from 'rxjs/operators';
8
8
  import { FieldType, getModelOptions, getModelFieldsWithOptions } from '@smartsoft001/models';
9
9
  import { TranslateService, TranslatePipe } from '@ngx-translate/core';
@@ -12,10 +12,12 @@ import { Debounce, debounce } from 'lodash-decorators';
12
12
  import { FormsModule, UntypedFormControl, UntypedFormGroup, UntypedFormArray } from '@angular/forms';
13
13
  import * as moment from 'moment';
14
14
  import { GuidService, SpecificationService } from '@smartsoft001/utils';
15
+ import { Subscription, firstValueFrom, BehaviorSubject, combineLatest, Subject } from 'rxjs';
15
16
  import { NgComponentOutlet, NgClass, CommonModule, NgTemplateOutlet, Location } from '@angular/common';
16
17
  import * as _ from 'lodash';
17
18
  import { DynamicIoDirective, DynamicIoModule } from 'ng-dynamic-component';
18
- import * as i1 from '@angular/router';
19
+ import { HttpClient } from '@angular/common/http';
20
+ import * as i1$1 from '@angular/router';
19
21
  import { Router, ActivatedRoute, RouterModule } from '@angular/router';
20
22
 
21
23
  class CrudConfig {
@@ -50,376 +52,284 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.0", ngImpor
50
52
  type: Injectable
51
53
  }] });
52
54
 
53
- class CrudService {
54
- config = inject((CrudConfig));
55
- http = inject(HttpClient);
56
- _formatMap = {
57
- csv: 'text/csv',
58
- xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
55
+ /*
56
+ * Create
57
+ */
58
+ const create = function (entity, item) {
59
+ return {
60
+ type: `[${entity}] Create`,
61
+ item,
59
62
  };
60
- create(item) {
61
- return firstValueFrom(this.http
62
- .post(this.config.apiUrl, item, { observe: 'response' })
63
- .pipe(map((response) => {
64
- const location = response.headers['Location'];
65
- if (!location)
66
- return null;
67
- const array = location.split('/');
68
- return array[array.length - 1];
69
- })));
63
+ };
64
+ const createSuccess = function (entity, item) {
65
+ return {
66
+ type: `[${entity}] Create Success`,
67
+ item,
68
+ };
69
+ };
70
+ const createFailure = function (entity, item, error) {
71
+ return {
72
+ type: `[${entity}] Create Failure`,
73
+ item,
74
+ error,
75
+ };
76
+ };
77
+ /*
78
+ * Create many
79
+ */
80
+ const createMany = function (entity, data) {
81
+ return {
82
+ type: `[${entity}] Create Many`,
83
+ data,
84
+ };
85
+ };
86
+ const createManySuccess = function (entity, data) {
87
+ return {
88
+ type: `[${entity}] Create Many Success`,
89
+ data,
90
+ };
91
+ };
92
+ const createManyFailure = function (entity, data, error) {
93
+ return {
94
+ type: `[${entity}] Create Many Failure`,
95
+ data,
96
+ error,
97
+ };
98
+ };
99
+ /*
100
+ * Read
101
+ */
102
+ const read = function (entity, filter) {
103
+ return {
104
+ type: `[${entity}] Read`,
105
+ filter: filter,
106
+ };
107
+ };
108
+ const readSuccess = function (entity, filter, result) {
109
+ return {
110
+ type: `[${entity}] Read Success`,
111
+ result,
112
+ filter,
113
+ };
114
+ };
115
+ const readFailure = function (entity, filter, error) {
116
+ return {
117
+ type: `[${entity}] Read Failure`,
118
+ filter,
119
+ error,
120
+ };
121
+ };
122
+ /*
123
+ * Clear
124
+ */
125
+ const clear = function (entity) {
126
+ return {
127
+ type: `[${entity}] Clear`,
128
+ };
129
+ };
130
+ /*
131
+ * Export
132
+ */
133
+ const exportList = function (entity, filter = null, format) {
134
+ return {
135
+ type: `[${entity}] Export`,
136
+ filter: filter,
137
+ format,
138
+ };
139
+ };
140
+ const exportListSuccess = function (entity, filter) {
141
+ return {
142
+ type: `[${entity}] Export Success`,
143
+ filter,
144
+ };
145
+ };
146
+ const exportListFailure = function (entity, filter, error) {
147
+ return {
148
+ type: `[${entity}] Export Failure`,
149
+ filter,
150
+ error,
151
+ };
152
+ };
153
+ /*
154
+ * Select
155
+ */
156
+ const select = function (entity, id) {
157
+ return {
158
+ type: `[${entity}] Select`,
159
+ id,
160
+ };
161
+ };
162
+ const selectSuccess = function (entity, id, item) {
163
+ return {
164
+ type: `[${entity}] Select Success`,
165
+ id,
166
+ item,
167
+ };
168
+ };
169
+ const selectFailure = function (entity, id, error) {
170
+ return {
171
+ type: `[${entity}] Select Failure`,
172
+ id,
173
+ error,
174
+ };
175
+ };
176
+ const unselect = function (entity) {
177
+ return {
178
+ type: `[${entity}] Unselect`,
179
+ };
180
+ };
181
+ /*
182
+ * MultiSelect
183
+ */
184
+ const multiSelect = function (entity, items) {
185
+ return {
186
+ type: `[${entity}] MultiSelect`,
187
+ items,
188
+ };
189
+ };
190
+ /*
191
+ * Update
192
+ */
193
+ const update = function (entity, item) {
194
+ return {
195
+ type: `[${entity}] Update`,
196
+ item,
197
+ };
198
+ };
199
+ const updateSuccess = function (entity, item) {
200
+ return {
201
+ type: `[${entity}] Update Success`,
202
+ item,
203
+ };
204
+ };
205
+ const updateFailure = function (entity, item, error) {
206
+ return {
207
+ type: `[${entity}] Update Failure`,
208
+ item,
209
+ error,
210
+ };
211
+ };
212
+ /*
213
+ * Update partial
214
+ */
215
+ const updatePartial = function (entity, item) {
216
+ return {
217
+ type: `[${entity}] Update partial`,
218
+ item,
219
+ };
220
+ };
221
+ const updatePartialSuccess = function (entity, item) {
222
+ return {
223
+ type: `[${entity}] Update partial Success`,
224
+ item,
225
+ };
226
+ };
227
+ const updatePartialFailure = function (entity, item, error) {
228
+ return {
229
+ type: `[${entity}] Update partial Failure`,
230
+ item,
231
+ error,
232
+ };
233
+ };
234
+ /*
235
+ * Update partial many
236
+ */
237
+ const updatePartialMany = function (entity, items) {
238
+ return {
239
+ type: `[${entity}] Update partial many`,
240
+ items,
241
+ };
242
+ };
243
+ const updatePartialManySuccess = function (entity, items) {
244
+ return {
245
+ type: `[${entity}] Update partial many Success`,
246
+ items,
247
+ };
248
+ };
249
+ const updatePartialManyFailure = function (entity, items, error) {
250
+ return {
251
+ type: `[${entity}] Update partial many Failure`,
252
+ items,
253
+ error,
254
+ };
255
+ };
256
+ /*
257
+ * Delete
258
+ */
259
+ const deleteItem = function (entity, id) {
260
+ return {
261
+ type: `[${entity}] Delete`,
262
+ id,
263
+ };
264
+ };
265
+ const deleteSuccess = function (entity, id) {
266
+ return {
267
+ type: `[${entity}] Delete Success`,
268
+ id,
269
+ };
270
+ };
271
+ const deleteFailure = function (entity, id, error) {
272
+ return {
273
+ type: `[${entity}] Delete Failure`,
274
+ id,
275
+ error,
276
+ };
277
+ };
278
+
279
+ const getCrudState = (entity) => createFeatureSelector(entity);
280
+ const getCrudSelected = (entity) => createSelector(getCrudState(entity), (state) => state.selected);
281
+ const getCrudMultiSelected = (entity) => createSelector(getCrudState(entity), (state) => state.multiSelected);
282
+ const getCrudList = (entity) => createSelector(getCrudState(entity), (state) => state.list);
283
+ const getCrudTotalCount = (entity) => createSelector(getCrudState(entity), (state) => state.totalCount);
284
+ const getCrudLinks = (entity) => createSelector(getCrudState(entity), (state) => state.links);
285
+ const getCrudLoaded = (entity) => createSelector(getCrudState(entity), (state) => state.loaded);
286
+ const getCrudFilter = (entity) => createSelector(getCrudState(entity), (state) => state.filter);
287
+ const getCrudError = (entity) => createSelector(getCrudState(entity), (state) => state.error);
288
+
289
+ class CrudFacade {
290
+ store;
291
+ config;
292
+ constructor(store, config) {
293
+ this.store = store;
294
+ this.config = config;
295
+ if (NgrxStoreService.store) {
296
+ this.store = NgrxStoreService.store;
297
+ }
70
298
  }
71
- createMany(items, options) {
72
- return firstValueFrom(this.http.post(this.config.apiUrl + '/bulk?mode=' + options.mode, items));
299
+ get loaded() {
300
+ return toSignal(this.store.pipe(select$1(getCrudLoaded(this.config.entity))));
73
301
  }
74
- getById(id) {
75
- return firstValueFrom(this.http.get(this.config.apiUrl + '/' + id));
302
+ get loading() {
303
+ return toSignal(this.store.pipe(select$1(getCrudLoaded(this.config.entity)), map((l) => !l)));
76
304
  }
77
- getList(filter = null) {
78
- return firstValueFrom(this.http.get(this.config.apiUrl + this.getQuery(filter)));
305
+ get selected() {
306
+ return toSignal(this.store.pipe(select$1(getCrudSelected(this.config.entity))));
79
307
  }
80
- exportList(filter = null, format) {
81
- if (!format) {
82
- format = 'csv';
83
- }
84
- if (format === 'xlsx') {
85
- return firstValueFrom(this.http
86
- .get(this.config.apiUrl + this.getQuery(filter), {
87
- headers: {
88
- 'Content-Type': this._formatMap[format],
89
- },
90
- observe: 'response',
91
- reportProgress: false,
92
- responseType: 'blob',
93
- })
94
- .pipe(map((res) => {
95
- const downloadLink = document.createElement('a');
96
- const blob = res.body;
97
- downloadLink.href = URL.createObjectURL(blob);
98
- downloadLink.download = 'data.' + format;
99
- document.body.appendChild(downloadLink);
100
- downloadLink.click();
101
- document.body.removeChild(downloadLink);
102
- })));
103
- }
104
- return firstValueFrom(this.http
105
- .get(this.config.apiUrl + this.getQuery(filter), {
106
- headers: {
107
- 'Content-Type': this._formatMap[format],
108
- },
109
- responseType: 'text',
110
- })
111
- .pipe(map((res) => {
112
- const downloadLink = document.createElement('a');
113
- const blob = new Blob(['\ufeff', res]);
114
- downloadLink.href = URL.createObjectURL(blob);
115
- downloadLink.download = 'data.' + format;
116
- document.body.appendChild(downloadLink);
117
- downloadLink.click();
118
- document.body.removeChild(downloadLink);
119
- })));
308
+ get multiSelected() {
309
+ return toSignal(this.store.pipe(select$1(getCrudMultiSelected(this.config.entity))));
120
310
  }
121
- update(item) {
122
- return firstValueFrom(this.http.put(this.config.apiUrl + '/' + item.id, item));
311
+ get list() {
312
+ return toSignal(this.store.pipe(select$1(getCrudList(this.config.entity))));
123
313
  }
124
- updatePartial(item) {
125
- return firstValueFrom(this.http.patch(this.config.apiUrl + '/' + item.id, item));
314
+ get filter() {
315
+ return toSignal(this.store.pipe(select$1(getCrudFilter(this.config.entity))));
126
316
  }
127
- updatePartialMany(items) {
128
- const updatePromises = items.map((item) => {
129
- return this.updatePartial(item);
130
- });
131
- return Promise.all(updatePromises);
317
+ get totalCount() {
318
+ return toSignal(this.store.pipe(select$1(getCrudTotalCount(this.config.entity))));
132
319
  }
133
- delete(id) {
134
- return firstValueFrom(this.http.delete(this.config.apiUrl + '/' + id));
320
+ get links() {
321
+ return toSignal(this.store.pipe(select$1(getCrudLinks(this.config.entity))));
135
322
  }
136
- getQuery(filter) {
137
- let query = '';
138
- if (filter && filter.searchText) {
139
- query += '&$search=' + filter.searchText;
140
- }
141
- if (filter && filter.limit) {
142
- query += `&limit=${filter.limit}&offset=${filter.offset ? filter.offset : 0}`;
143
- }
144
- if (filter && filter.sortBy) {
145
- query += `&sort=${(filter.sortDesc ? '-' : '') + filter.sortBy}`;
146
- }
147
- if (filter && filter.query) {
148
- filter.query.forEach((q) => {
149
- if (q.value &&
150
- typeof q.value === 'string' &&
151
- q.value.match(/^-?\d+$/) &&
152
- q.value[0] !== "'" &&
153
- q.value[0] !== '"') {
154
- query += '&' + q.key + q.type + `'${q.value}'`;
155
- }
156
- else {
157
- query += '&' + q.key + q.type + q.value;
158
- }
159
- });
160
- }
161
- return query ? '?' + query.replace('&', '') : '';
162
- }
163
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.0", ngImport: i0, type: CrudService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
164
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.0", ngImport: i0, type: CrudService });
165
- }
166
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.0", ngImport: i0, type: CrudService, decorators: [{
167
- type: Injectable
168
- }] });
169
-
170
- // "Actions, Reducers, Effects" in a normal store
171
- function CrudMethodsFactory() {
172
- return (store, crudService = inject((CrudService))) => {
173
- const methods = {
174
- async create(item) {
175
- patchState(store, {
176
- loaded: false,
177
- error: null,
178
- });
179
- try {
180
- await crudService.create(item);
181
- await this.createSuccess();
182
- }
183
- catch (error) {
184
- methods.defaultFailure(error);
185
- }
186
- },
187
- async createSuccess() {
188
- patchState(store, {
189
- loaded: true,
190
- error: null,
191
- });
192
- await methods.read(store.filter ? { ...store.filter, offset: 0 } : null);
193
- },
194
- async createMany(data) {
195
- patchState(store, {
196
- loaded: false,
197
- error: null,
198
- });
199
- try {
200
- await crudService.createMany(data.items, data.options);
201
- await methods.createManySuccess();
202
- }
203
- catch (e) {
204
- methods.defaultFailure(e);
205
- }
206
- },
207
- async createManySuccess() {
208
- patchState(store, {
209
- loaded: true,
210
- error: null,
211
- });
212
- await methods.read(store.filter ? { ...store.filter, offset: 0 } : null);
213
- },
214
- async export(filter, format) {
215
- patchState(store, {
216
- loaded: false,
217
- });
218
- try {
219
- await crudService.exportList(filter, format);
220
- methods.exportSuccess();
221
- }
222
- catch (e) {
223
- methods.defaultFailure(e);
224
- }
225
- },
226
- exportSuccess() {
227
- patchState(store, {
228
- loaded: true,
229
- });
230
- },
231
- async read(filter) {
232
- patchState(store, {
233
- loaded: false,
234
- filter,
235
- error: null,
236
- totalCount: null,
237
- links: null,
238
- });
239
- try {
240
- const result = await crudService.getList(filter);
241
- methods.readSuccess({
242
- list: result.data,
243
- filter,
244
- totalCount: result.totalCount,
245
- links: result.links,
246
- });
247
- }
248
- catch (error) {
249
- methods.defaultFailure(error);
250
- }
251
- },
252
- readSuccess(data) {
253
- let list = [];
254
- if (data.filter?.offset &&
255
- store.list() &&
256
- data.filter.paginationMode !== PaginationMode.singlePage) {
257
- list = [...store.list(), ...data.list];
258
- }
259
- else {
260
- list = data.list;
261
- }
262
- patchState(store, {
263
- loaded: true,
264
- list,
265
- totalCount: data.totalCount,
266
- links: data.links,
267
- error: null,
268
- });
269
- },
270
- clear() {
271
- store.set(() => ({ ...initialState }));
272
- },
273
- async select(id) {
274
- patchState(store, {
275
- loaded: false,
276
- selected: null,
277
- error: null,
278
- });
279
- try {
280
- const result = await crudService.getById(id);
281
- methods.selectSuccess(result);
282
- }
283
- catch (e) {
284
- methods.defaultFailure(e);
285
- }
286
- },
287
- selectSuccess(selected) {
288
- patchState(store, {
289
- loaded: true,
290
- selected,
291
- error: null,
292
- });
293
- },
294
- unselect() {
295
- patchState(store, {
296
- loaded: true,
297
- selected: null,
298
- error: null,
299
- });
300
- },
301
- multiSelect(items) {
302
- patchState(store, {
303
- multiSelected: [...items],
304
- });
305
- },
306
- async update(item) {
307
- patchState(store, {
308
- loaded: false,
309
- error: null,
310
- });
311
- try {
312
- await crudService.updatePartial(item);
313
- await methods.updateSuccess(item.id);
314
- }
315
- catch (e) {
316
- methods.defaultFailure(e);
317
- }
318
- },
319
- async updateSuccess(id) {
320
- await methods.read({ ...store.filter, offset: 0 });
321
- await methods.select(id);
322
- },
323
- async updatePartial(item) {
324
- patchState(store, {
325
- loaded: false,
326
- error: null,
327
- });
328
- try {
329
- await crudService.updatePartial(item);
330
- await methods.updatePartialSuccess(item.id);
331
- }
332
- catch (e) {
333
- methods.defaultFailure(e);
334
- }
335
- },
336
- async updatePartialSuccess(id) {
337
- await methods.read({ ...store.filter, offset: 0 });
338
- await methods.select(id);
339
- },
340
- async updatePartialMany(items) {
341
- patchState(store, {
342
- loaded: false,
343
- error: null,
344
- });
345
- try {
346
- await crudService.updatePartialMany(items);
347
- await methods.updatePartialManySuccess();
348
- }
349
- catch (e) {
350
- methods.defaultFailure(e);
351
- }
352
- },
353
- async updatePartialManySuccess() {
354
- await methods.read({ ...store.filter, offset: 0 });
355
- },
356
- async delete(id) {
357
- patchState(store, {
358
- loaded: false,
359
- error: null,
360
- });
361
- try {
362
- await crudService.delete(id);
363
- await methods.deleteSuccess();
364
- }
365
- catch (e) {
366
- methods.defaultFailure(e);
367
- }
368
- },
369
- async deleteSuccess() {
370
- await methods.read({ ...store.filter, offset: 0 });
371
- },
372
- defaultFailure(error) {
373
- patchState(store, {
374
- loaded: true,
375
- error,
376
- });
377
- },
378
- };
379
- return methods;
380
- };
381
- }
382
-
383
- const initialState = {
384
- loaded: false,
385
- };
386
- function createCrudFeatureStore() {
387
- return signalStore({ providedIn: 'root' }, withState(initialState), withComputed((store) => {
388
- return {
389
- getError: computed(() => (store.error ? store.error() : null)),
390
- getLoaded: computed(() => store.loaded()),
391
- getSelected: computed(() => store.selected ? store.selected() : undefined),
392
- getMultiSelected: computed(() => store.multiSelected ? store.multiSelected() : undefined),
393
- getList: computed(() => (store.list ? store.list() : undefined)),
394
- getTotalCount: computed(() => store.totalCount ? store.totalCount() : undefined),
395
- getLinks: computed(() => (store.links ? store.links() : undefined)),
396
- getFilter: computed(() => (store.filter ? store.filter() : undefined)),
397
- };
398
- }), withMethods(CrudMethodsFactory()));
399
- }
400
-
401
- class CrudFacade {
402
- config;
403
- store = createCrudFeatureStore();
404
- loaded = this.store.getLoaded;
405
- loading = computed(() => !this.store.getLoaded(), ...(ngDevMode ? [{ debugName: "loading" }] : []));
406
- selected = this.store.getSelected;
407
- multiSelected = this.store.getMultiSelected;
408
- list = this.store.getList;
409
- filter = this.store.getFilter;
410
- totalCount = this.store.getTotalCount;
411
- links = this.store.getLinks;
412
- error = this.store.getError;
413
- constructor(config) {
414
- this.config = config;
323
+ get error() {
324
+ return toSignal(this.store.pipe(select$1(getCrudError(this.config.entity))));
415
325
  }
416
326
  create(item) {
417
- this.store.create(item);
327
+ this.store.dispatch(create(this.config.entity, item));
418
328
  }
419
329
  createMany(items, options) {
420
- this.store.createMany({ items, options });
330
+ this.store.dispatch(createMany(this.config.entity, { items, options }));
421
331
  }
422
- read(filter = null) {
332
+ read(filter = {}) {
423
333
  let baseQuery = [];
424
334
  if (this.config.baseQuery) {
425
335
  baseQuery = this.config.baseQuery;
@@ -428,41 +338,46 @@ class CrudFacade {
428
338
  ...(filter ? filter : {}),
429
339
  query: filter && filter.query ? filter.query : baseQuery,
430
340
  };
431
- this.store.read(fullFilter);
341
+ this.store.dispatch(read(this.config.entity, fullFilter));
432
342
  }
433
343
  clear() {
434
- this.store.clear();
344
+ this.store.dispatch(clear(this.config.entity));
435
345
  }
436
346
  select(id) {
437
- this.store.select(id);
347
+ this.store.dispatch(select(this.config.entity, id));
438
348
  }
439
349
  unselect() {
440
- this.store.unselect();
350
+ this.store.dispatch(unselect(this.config.entity));
441
351
  }
442
352
  multiSelect(items) {
443
- this.store.multiSelect(items);
353
+ this.store.dispatch(multiSelect(this.config.entity, items));
444
354
  }
445
355
  update(item) {
446
- this.store.update(item);
356
+ this.getStore().dispatch(update(this.config.entity, item));
447
357
  }
448
- export(filter = null, format = null) {
449
- this.store.export(filter || {}, format);
358
+ export(filter = {}, format) {
359
+ this.getStore().dispatch(exportList(this.config.entity, filter, format));
450
360
  }
451
361
  updatePartial(item) {
452
- this.store.updatePartial(item);
362
+ this.getStore().dispatch(updatePartial(this.config.entity, item));
453
363
  }
454
364
  updatePartialMany(items) {
455
- this.store.updatePartialMany(items);
365
+ this.getStore().dispatch(updatePartialMany(this.config.entity, items));
456
366
  }
457
367
  delete(id) {
458
- this.store.delete(id);
368
+ this.getStore().dispatch(deleteItem(this.config.entity, id));
369
+ }
370
+ getStore() {
371
+ if (NgrxStoreService.store)
372
+ return NgrxStoreService.store;
373
+ return this.store;
459
374
  }
460
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.0", ngImport: i0, type: CrudFacade, deps: [{ token: CrudConfig }], target: i0.ɵɵFactoryTarget.Injectable });
375
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.0", ngImport: i0, type: CrudFacade, deps: [{ token: i1.Store }, { token: CrudConfig }], target: i0.ɵɵFactoryTarget.Injectable });
461
376
  static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.0", ngImport: i0, type: CrudFacade });
462
377
  }
463
378
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.0", ngImport: i0, type: CrudFacade, decorators: [{
464
379
  type: Injectable
465
- }], ctorParameters: () => [{ type: CrudConfig }] });
380
+ }], ctorParameters: () => [{ type: i1.Store }, { type: CrudConfig }] });
466
381
 
467
382
  class ExportComponent extends BaseComponent$1 {
468
383
  facade = inject((CrudFacade));
@@ -485,7 +400,7 @@ class ExportComponent extends BaseComponent$1 {
485
400
  const loading = this.facade.loading();
486
401
  if (loading)
487
402
  return;
488
- this.popoverService.close();
403
+ this.popoverService.close().then();
489
404
  },
490
405
  loading: this.facade.loading,
491
406
  expand: 'block',
@@ -1230,11 +1145,13 @@ class FiltersComponent {
1230
1145
  <!-- </ion-list>-->
1231
1146
  <div class="h-20">&nbsp;</div>
1232
1147
  <!--</ion-content>-->
1233
- `, isInline: true, styles: [":host ion-toolbar.ios{height:4.6rem}:host ion-toolbar ion-buttons.ios{height:var(--smart-button-height);margin:0}\n"], dependencies: [{ kind: "component", type: FilterComponent, selector: "smart-crud-filter", inputs: ["item", "filter"] }] });
1148
+ `, isInline: true, dependencies: [{ kind: "component", type: FilterComponent, selector: "smart-crud-filter", inputs: ["item", "filter"] }] });
1234
1149
  }
1235
1150
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.0", ngImport: i0, type: FiltersComponent, decorators: [{
1236
1151
  type: Component,
1237
- args: [{ selector: 'smart-crud-filters', template: `
1152
+ args: [{
1153
+ selector: 'smart-crud-filters',
1154
+ template: `
1238
1155
  <!--<ion-header [hidden]="hideMenu()">-->
1239
1156
  <!-- <ion-toolbar>-->
1240
1157
  <!-- <ion-buttons slot="end">-->
@@ -1253,7 +1170,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.0", ngImpor
1253
1170
  <!-- </ion-list>-->
1254
1171
  <div class="h-20">&nbsp;</div>
1255
1172
  <!--</ion-content>-->
1256
- `, imports: [FilterComponent, TranslatePipe], styles: [":host ion-toolbar.ios{height:4.6rem}:host ion-toolbar ion-buttons.ios{height:var(--smart-button-height);margin:0}\n"] }]
1173
+ `,
1174
+ imports: [FilterComponent],
1175
+ }]
1257
1176
  }] });
1258
1177
 
1259
1178
  class FiltersConfigComponent {
@@ -1440,7 +1359,7 @@ class MultiselectComponent {
1440
1359
  this.valid = valid;
1441
1360
  }
1442
1361
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.0", ngImport: i0, type: MultiselectComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1443
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.0", type: MultiselectComponent, isStandalone: true, selector: "smart-crud-multiselect", ngImport: i0, template: "@let list = this.list();\n@if (list) {\n <!-- <ion-header>-->\n <!-- <ion-toolbar>-->\n <!-- <ion-buttons slot=\"end\">-->\n <!-- <ion-button (click)=\"onClose()\">-->\n <!-- <ion-icon slot=\"icon-only\" name=\"close\"> </ion-icon>-->\n <!-- </ion-button>-->\n <!-- </ion-buttons>-->\n <!--<ion-title>-->{{ 'selected' | translate }}: {{ list?.length\n }}<!--</ion-title>-->\n <!-- </ion-toolbar>-->\n <!-- </ion-header>-->\n\n @if (config?.list?.components?.multi) {\n <div>\n <ng-template\n [ngComponentOutlet]=\"config?.list?.components?.multi\"\n [ndcDynamicInputs]=\"{ items: list }\"\n ></ng-template>\n </div>\n }\n\n @if (showForm && item) {\n <div>\n <smart-form\n [options]=\"item | smartFormOptions: 'multiUpdate' : config.type\"\n (valuePartialChange)=\"onPartialChange($event, list)\"\n (validChange)=\"onValidChange($event)\"\n ></smart-form>\n\n <smart-button\n style=\"float: right\"\n [disabled]=\"lock || !valid\"\n [options]=\"buttonOptions\"\n >\n {{ 'change' | translate }}\n </smart-button>\n </div>\n }\n}\n", styles: [""], dependencies: [{ kind: "directive", type: NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletEnvironmentInjector", "ngComponentOutletContent", "ngComponentOutletNgModule", "ngComponentOutletNgModuleFactory"], exportAs: ["ngComponentOutlet"] }, { kind: "directive", type: DynamicIoDirective, selector: "[ndcDynamicInputs],[ndcDynamicOutputs]", inputs: ["ndcDynamicInputs", "ndcDynamicOutputs"], exportAs: ["ndcDynamicIo"] }, { kind: "component", type: FormComponent, selector: "smart-form", inputs: ["options"], outputs: ["invokeSubmit", "valueChange", "valuePartialChange", "validChange"] }, { kind: "component", type: ButtonComponent, selector: "smart-button", inputs: ["options", "disabled"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }, { kind: "pipe", type: FormOptionsPipe, name: "smartFormOptions" }] });
1362
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.0", type: MultiselectComponent, isStandalone: true, selector: "smart-crud-multiselect", ngImport: i0, template: "@let list = this.list();\n@if (list) {\n <!-- <ion-header>-->\n <!-- <ion-toolbar>-->\n <!-- <ion-buttons slot=\"end\">-->\n <!-- <ion-button (click)=\"onClose()\">-->\n <!-- <ion-icon slot=\"icon-only\" name=\"close\"> </ion-icon>-->\n <!-- </ion-button>-->\n <!-- </ion-buttons>-->\n <!--<ion-title>-->{{ 'selected' | translate }}: {{ list?.length\n }}<!--</ion-title>-->\n <!-- </ion-toolbar>-->\n <!-- </ion-header>-->\n\n @if (config?.list?.components?.multi) {\n <div>\n <ng-template\n [ngComponentOutlet]=\"config?.list?.components?.multi\"\n [ndcDynamicInputs]=\"{ items: list }\"\n ></ng-template>\n </div>\n }\n\n @if (showForm && item) {\n <div>\n <smart-form\n [options]=\"item | smartFormOptions: 'multiUpdate' : config.type\"\n (valuePartialChange)=\"onPartialChange($event, list)\"\n (validChange)=\"onValidChange($event)\"\n ></smart-form>\n\n <smart-button\n style=\"float: right\"\n [disabled]=\"lock || !valid\"\n [options]=\"buttonOptions\"\n >\n {{ 'change' | translate }}\n </smart-button>\n </div>\n }\n}\n", dependencies: [{ kind: "directive", type: NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletEnvironmentInjector", "ngComponentOutletContent", "ngComponentOutletNgModule", "ngComponentOutletNgModuleFactory"], exportAs: ["ngComponentOutlet"] }, { kind: "directive", type: DynamicIoDirective, selector: "[ndcDynamicInputs],[ndcDynamicOutputs]", inputs: ["ndcDynamicInputs", "ndcDynamicOutputs"], exportAs: ["ndcDynamicIo"] }, { kind: "component", type: FormComponent, selector: "smart-form", inputs: ["options"], outputs: ["invokeSubmit", "valueChange", "valuePartialChange", "validChange"] }, { kind: "component", type: ButtonComponent, selector: "smart-button", inputs: ["options", "disabled"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }, { kind: "pipe", type: FormOptionsPipe, name: "smartFormOptions" }] });
1444
1363
  }
1445
1364
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.0", ngImport: i0, type: MultiselectComponent, decorators: [{
1446
1365
  type: Component,
@@ -1666,6 +1585,123 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.0", ngImpor
1666
1585
  type: Injectable
1667
1586
  }] });
1668
1587
 
1588
+ class CrudService {
1589
+ config = inject((CrudConfig));
1590
+ http = inject(HttpClient);
1591
+ _formatMap = {
1592
+ csv: 'text/csv',
1593
+ xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
1594
+ };
1595
+ create(item) {
1596
+ return firstValueFrom(this.http
1597
+ .post(this.config.apiUrl, item, { observe: 'response' })
1598
+ .pipe(map((response) => {
1599
+ const location = response.headers['Location'];
1600
+ if (!location)
1601
+ return null;
1602
+ const array = location.split('/');
1603
+ return array[array.length - 1];
1604
+ })));
1605
+ }
1606
+ createMany(items, options) {
1607
+ return firstValueFrom(this.http.post(this.config.apiUrl + '/bulk?mode=' + options.mode, items));
1608
+ }
1609
+ getById(id) {
1610
+ return firstValueFrom(this.http.get(this.config.apiUrl + '/' + id));
1611
+ }
1612
+ getList(filter = null) {
1613
+ return firstValueFrom(this.http.get(this.config.apiUrl + this.getQuery(filter)));
1614
+ }
1615
+ exportList(filter = null, format) {
1616
+ if (!format) {
1617
+ format = 'csv';
1618
+ }
1619
+ if (format === 'xlsx') {
1620
+ return firstValueFrom(this.http
1621
+ .get(this.config.apiUrl + this.getQuery(filter), {
1622
+ headers: {
1623
+ 'Content-Type': this._formatMap[format],
1624
+ },
1625
+ observe: 'response',
1626
+ reportProgress: false,
1627
+ responseType: 'blob',
1628
+ })
1629
+ .pipe(map((res) => {
1630
+ const downloadLink = document.createElement('a');
1631
+ const blob = res.body;
1632
+ downloadLink.href = URL.createObjectURL(blob);
1633
+ downloadLink.download = 'data.' + format;
1634
+ document.body.appendChild(downloadLink);
1635
+ downloadLink.click();
1636
+ document.body.removeChild(downloadLink);
1637
+ })));
1638
+ }
1639
+ return firstValueFrom(this.http
1640
+ .get(this.config.apiUrl + this.getQuery(filter), {
1641
+ headers: {
1642
+ 'Content-Type': this._formatMap[format],
1643
+ },
1644
+ responseType: 'text',
1645
+ })
1646
+ .pipe(map((res) => {
1647
+ const downloadLink = document.createElement('a');
1648
+ const blob = new Blob(['\ufeff', res]);
1649
+ downloadLink.href = URL.createObjectURL(blob);
1650
+ downloadLink.download = 'data.' + format;
1651
+ document.body.appendChild(downloadLink);
1652
+ downloadLink.click();
1653
+ document.body.removeChild(downloadLink);
1654
+ })));
1655
+ }
1656
+ update(item) {
1657
+ return firstValueFrom(this.http.put(this.config.apiUrl + '/' + item.id, item));
1658
+ }
1659
+ updatePartial(item) {
1660
+ return firstValueFrom(this.http.patch(this.config.apiUrl + '/' + item.id, item));
1661
+ }
1662
+ updatePartialMany(items) {
1663
+ const updatePromises = items.map((item) => {
1664
+ return this.updatePartial(item);
1665
+ });
1666
+ return Promise.all(updatePromises);
1667
+ }
1668
+ delete(id) {
1669
+ return firstValueFrom(this.http.delete(this.config.apiUrl + '/' + id));
1670
+ }
1671
+ getQuery(filter) {
1672
+ let query = '';
1673
+ if (filter && filter.searchText) {
1674
+ query += '&$search=' + filter.searchText;
1675
+ }
1676
+ if (filter && filter.limit) {
1677
+ query += `&limit=${filter.limit}&offset=${filter.offset ? filter.offset : 0}`;
1678
+ }
1679
+ if (filter && filter.sortBy) {
1680
+ query += `&sort=${(filter.sortDesc ? '-' : '') + filter.sortBy}`;
1681
+ }
1682
+ if (filter && filter.query) {
1683
+ filter.query.forEach((q) => {
1684
+ if (q.value &&
1685
+ typeof q.value === 'string' &&
1686
+ q.value.match(/^-?\d+$/) &&
1687
+ q.value[0] !== "'" &&
1688
+ q.value[0] !== '"') {
1689
+ query += '&' + q.key + q.type + `'${q.value}'`;
1690
+ }
1691
+ else {
1692
+ query += '&' + q.key + q.type + q.value;
1693
+ }
1694
+ });
1695
+ }
1696
+ return query ? '?' + query.replace('&', '') : '';
1697
+ }
1698
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.0", ngImport: i0, type: CrudService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1699
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.0", ngImport: i0, type: CrudService });
1700
+ }
1701
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.0", ngImport: i0, type: CrudService, decorators: [{
1702
+ type: Injectable
1703
+ }] });
1704
+
1669
1705
  const COMPONENTS = [
1670
1706
  ExportComponent,
1671
1707
  FilterComponent,
@@ -2720,7 +2756,7 @@ class CrudFullModule {
2720
2756
  ListComponent,
2721
2757
  ListStandardComponent,
2722
2758
  ItemStandardComponent, SharedModule,
2723
- CrudPipesModule, i1.RouterModule, FormsModule,
2759
+ CrudPipesModule, i1$1.RouterModule, FormsModule,
2724
2760
  CommonModule,
2725
2761
  CrudComponentsModule], exports: [ItemComponent,
2726
2762
  ListComponent,