@ngrx-traits/common 0.0.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.
- package/README.md +7 -0
- package/async-action/async-action.model.d.ts +19 -0
- package/async-action/async-action.trait.d.ts +59 -0
- package/async-action/index.d.ts +2 -0
- package/bundles/ngrx-traits-common.umd.js +2126 -0
- package/bundles/ngrx-traits-common.umd.js.map +1 -0
- package/crud-entities/crud-entities.model.d.ts +76 -0
- package/crud-entities/crud-entities.trait.actions.d.ts +2 -0
- package/crud-entities/crud-entities.trait.d.ts +35 -0
- package/crud-entities/crud-entities.trait.mutators.d.ts +3 -0
- package/crud-entities/crud-entities.trait.reducer.d.ts +7 -0
- package/crud-entities/crud-entities.trait.selectors.d.ts +3 -0
- package/crud-entities/index.d.ts +2 -0
- package/entities-pagination/entities-pagination.model.d.ts +82 -0
- package/entities-pagination/entities-pagination.model.internal.d.ts +12 -0
- package/entities-pagination/entities-pagination.trait.actions.d.ts +2 -0
- package/entities-pagination/entities-pagination.trait.d.ts +55 -0
- package/entities-pagination/entities-pagination.trait.effects.d.ts +8 -0
- package/entities-pagination/entities-pagination.trait.mutators.d.ts +3 -0
- package/entities-pagination/entities-pagination.trait.reducer.d.ts +7 -0
- package/entities-pagination/entities-pagination.trait.selectors.d.ts +4 -0
- package/entities-pagination/index.d.ts +2 -0
- package/esm2015/async-action/async-action.model.js +2 -0
- package/esm2015/async-action/async-action.model.js.map +1 -0
- package/esm2015/async-action/async-action.trait.js +96 -0
- package/esm2015/async-action/async-action.trait.js.map +1 -0
- package/esm2015/async-action/index.js +3 -0
- package/esm2015/async-action/index.js.map +1 -0
- package/esm2015/crud-entities/crud-entities.model.js +8 -0
- package/esm2015/crud-entities/crud-entities.model.js.map +1 -0
- package/esm2015/crud-entities/crud-entities.trait.actions.js +20 -0
- package/esm2015/crud-entities/crud-entities.trait.actions.js.map +1 -0
- package/esm2015/crud-entities/crud-entities.trait.js +53 -0
- package/esm2015/crud-entities/crud-entities.trait.js.map +1 -0
- package/esm2015/crud-entities/crud-entities.trait.mutators.js +101 -0
- package/esm2015/crud-entities/crud-entities.trait.mutators.js.map +1 -0
- package/esm2015/crud-entities/crud-entities.trait.reducer.js +15 -0
- package/esm2015/crud-entities/crud-entities.trait.reducer.js.map +1 -0
- package/esm2015/crud-entities/crud-entities.trait.selectors.js +70 -0
- package/esm2015/crud-entities/crud-entities.trait.selectors.js.map +1 -0
- package/esm2015/crud-entities/index.js +3 -0
- package/esm2015/crud-entities/index.js.map +1 -0
- package/esm2015/entities-pagination/entities-pagination.model.internal.js +2 -0
- package/esm2015/entities-pagination/entities-pagination.model.internal.js.map +1 -0
- package/esm2015/entities-pagination/entities-pagination.model.js +2 -0
- package/esm2015/entities-pagination/entities-pagination.model.js.map +1 -0
- package/esm2015/entities-pagination/entities-pagination.trait.actions.js +20 -0
- package/esm2015/entities-pagination/entities-pagination.trait.actions.js.map +1 -0
- package/esm2015/entities-pagination/entities-pagination.trait.effects.js +54 -0
- package/esm2015/entities-pagination/entities-pagination.trait.effects.js.map +1 -0
- package/esm2015/entities-pagination/entities-pagination.trait.js +80 -0
- package/esm2015/entities-pagination/entities-pagination.trait.js.map +1 -0
- package/esm2015/entities-pagination/entities-pagination.trait.mutators.js +23 -0
- package/esm2015/entities-pagination/entities-pagination.trait.mutators.js.map +1 -0
- package/esm2015/entities-pagination/entities-pagination.trait.reducer.js +33 -0
- package/esm2015/entities-pagination/entities-pagination.trait.reducer.js.map +1 -0
- package/esm2015/entities-pagination/entities-pagination.trait.selectors.js +65 -0
- package/esm2015/entities-pagination/entities-pagination.trait.selectors.js.map +1 -0
- package/esm2015/entities-pagination/index.js +3 -0
- package/esm2015/entities-pagination/index.js.map +1 -0
- package/esm2015/filter-entities/filter-entities.model.internal.js +2 -0
- package/esm2015/filter-entities/filter-entities.model.internal.js.map +1 -0
- package/esm2015/filter-entities/filter-entities.model.js +2 -0
- package/esm2015/filter-entities/filter-entities.model.js.map +1 -0
- package/esm2015/filter-entities/filter-entities.trait.actions.js +16 -0
- package/esm2015/filter-entities/filter-entities.trait.actions.js.map +1 -0
- package/esm2015/filter-entities/filter-entities.trait.effect.js +56 -0
- package/esm2015/filter-entities/filter-entities.trait.effect.js.map +1 -0
- package/esm2015/filter-entities/filter-entities.trait.js +68 -0
- package/esm2015/filter-entities/filter-entities.trait.js.map +1 -0
- package/esm2015/filter-entities/filter-entities.trait.mutators.js +7 -0
- package/esm2015/filter-entities/filter-entities.trait.mutators.js.map +1 -0
- package/esm2015/filter-entities/filter-entities.trait.reducer.js +9 -0
- package/esm2015/filter-entities/filter-entities.trait.reducer.js.map +1 -0
- package/esm2015/filter-entities/filter-entities.trait.selectors.js +9 -0
- package/esm2015/filter-entities/filter-entities.trait.selectors.js.map +1 -0
- package/esm2015/filter-entities/index.js +3 -0
- package/esm2015/filter-entities/index.js.map +1 -0
- package/esm2015/index.js +12 -0
- package/esm2015/index.js.map +1 -0
- package/esm2015/load-entities/index.js +3 -0
- package/esm2015/load-entities/index.js.map +1 -0
- package/esm2015/load-entities/load-entities.model.js +2 -0
- package/esm2015/load-entities/load-entities.model.js.map +1 -0
- package/esm2015/load-entities/load-entities.mutators.js +8 -0
- package/esm2015/load-entities/load-entities.mutators.js.map +1 -0
- package/esm2015/load-entities/load-entities.trait.actions.js +10 -0
- package/esm2015/load-entities/load-entities.trait.actions.js.map +1 -0
- package/esm2015/load-entities/load-entities.trait.js +57 -0
- package/esm2015/load-entities/load-entities.trait.js.map +1 -0
- package/esm2015/load-entities/load-entities.trait.reducer.js +12 -0
- package/esm2015/load-entities/load-entities.trait.reducer.js.map +1 -0
- package/esm2015/load-entities/load-entities.trait.selectors.js +33 -0
- package/esm2015/load-entities/load-entities.trait.selectors.js.map +1 -0
- package/esm2015/load-entities/load-entities.utils.js +10 -0
- package/esm2015/load-entities/load-entities.utils.js.map +1 -0
- package/esm2015/load-entity/index.js +3 -0
- package/esm2015/load-entity/index.js.map +1 -0
- package/esm2015/load-entity/load-entity.model.js +2 -0
- package/esm2015/load-entity/load-entity.model.js.map +1 -0
- package/esm2015/load-entity/load-entity.traits.js +65 -0
- package/esm2015/load-entity/load-entity.traits.js.map +1 -0
- package/esm2015/ngrx-traits-common.js +5 -0
- package/esm2015/ngrx-traits-common.js.map +1 -0
- package/esm2015/public_api.js +2 -0
- package/esm2015/public_api.js.map +1 -0
- package/esm2015/reset/index.js +2 -0
- package/esm2015/reset/index.js.map +1 -0
- package/esm2015/reset/reset.trait.js +66 -0
- package/esm2015/reset/reset.trait.js.map +1 -0
- package/esm2015/select-entities/index.js +4 -0
- package/esm2015/select-entities/index.js.map +1 -0
- package/esm2015/select-entities/select-entities.model.js +2 -0
- package/esm2015/select-entities/select-entities.model.js.map +1 -0
- package/esm2015/select-entities/select-entities.trait.actions.js +11 -0
- package/esm2015/select-entities/select-entities.trait.actions.js.map +1 -0
- package/esm2015/select-entities/select-entities.trait.js +50 -0
- package/esm2015/select-entities/select-entities.trait.js.map +1 -0
- package/esm2015/select-entities/select-entities.trait.mutators.js +21 -0
- package/esm2015/select-entities/select-entities.trait.mutators.js.map +1 -0
- package/esm2015/select-entities/select-entities.trait.reducer.js +40 -0
- package/esm2015/select-entities/select-entities.trait.reducer.js.map +1 -0
- package/esm2015/select-entities/select-entities.trait.selectors.js +28 -0
- package/esm2015/select-entities/select-entities.trait.selectors.js.map +1 -0
- package/esm2015/select-entities/select-entities.utils.js +25 -0
- package/esm2015/select-entities/select-entities.utils.js.map +1 -0
- package/esm2015/select-entity/index.js +3 -0
- package/esm2015/select-entity/index.js.map +1 -0
- package/esm2015/select-entity/select-entity.model.js +2 -0
- package/esm2015/select-entity/select-entity.model.js.map +1 -0
- package/esm2015/select-entity/select-entity.trait.actions.js +9 -0
- package/esm2015/select-entity/select-entity.trait.actions.js.map +1 -0
- package/esm2015/select-entity/select-entity.trait.js +47 -0
- package/esm2015/select-entity/select-entity.trait.js.map +1 -0
- package/esm2015/select-entity/select-entity.trait.mutators.js +17 -0
- package/esm2015/select-entity/select-entity.trait.mutators.js.map +1 -0
- package/esm2015/select-entity/select-entity.trait.reducer.js +26 -0
- package/esm2015/select-entity/select-entity.trait.reducer.js.map +1 -0
- package/esm2015/select-entity/select-entity.trait.selectors.js +13 -0
- package/esm2015/select-entity/select-entity.trait.selectors.js.map +1 -0
- package/esm2015/set-entity/index.js +3 -0
- package/esm2015/set-entity/index.js.map +1 -0
- package/esm2015/set-entity/set-entity.model.js +2 -0
- package/esm2015/set-entity/set-entity.model.js.map +1 -0
- package/esm2015/set-entity/set-entity.trait.js +52 -0
- package/esm2015/set-entity/set-entity.trait.js.map +1 -0
- package/esm2015/sort-entities/index.js +4 -0
- package/esm2015/sort-entities/index.js.map +1 -0
- package/esm2015/sort-entities/sort-entities.model.js +2 -0
- package/esm2015/sort-entities/sort-entities.model.js.map +1 -0
- package/esm2015/sort-entities/sort-entities.trait.actions.js +8 -0
- package/esm2015/sort-entities/sort-entities.trait.actions.js.map +1 -0
- package/esm2015/sort-entities/sort-entities.trait.effect.js +28 -0
- package/esm2015/sort-entities/sort-entities.trait.effect.js.map +1 -0
- package/esm2015/sort-entities/sort-entities.trait.js +53 -0
- package/esm2015/sort-entities/sort-entities.trait.js.map +1 -0
- package/esm2015/sort-entities/sort-entities.trait.mutators.js +13 -0
- package/esm2015/sort-entities/sort-entities.trait.mutators.js.map +1 -0
- package/esm2015/sort-entities/sort-entities.trait.reducer.js +22 -0
- package/esm2015/sort-entities/sort-entities.trait.reducer.js.map +1 -0
- package/esm2015/sort-entities/sort-entities.trait.selectors.js +10 -0
- package/esm2015/sort-entities/sort-entities.trait.selectors.js.map +1 -0
- package/esm2015/sort-entities/sort-entities.utils.js +61 -0
- package/esm2015/sort-entities/sort-entities.utils.js.map +1 -0
- package/fesm2015/ngrx-traits-common.js +1511 -0
- package/fesm2015/ngrx-traits-common.js.map +1 -0
- package/filter-entities/filter-entities.model.d.ts +57 -0
- package/filter-entities/filter-entities.model.internal.d.ts +14 -0
- package/filter-entities/filter-entities.trait.actions.d.ts +2 -0
- package/filter-entities/filter-entities.trait.d.ts +42 -0
- package/filter-entities/filter-entities.trait.effect.d.ts +6 -0
- package/filter-entities/filter-entities.trait.mutators.d.ts +2 -0
- package/filter-entities/filter-entities.trait.reducer.d.ts +5 -0
- package/filter-entities/filter-entities.trait.selectors.d.ts +4 -0
- package/filter-entities/index.d.ts +2 -0
- package/index.d.ts +11 -0
- package/load-entities/index.d.ts +2 -0
- package/load-entities/load-entities.model.d.ts +97 -0
- package/load-entities/load-entities.mutators.d.ts +3 -0
- package/load-entities/load-entities.trait.actions.d.ts +2 -0
- package/load-entities/load-entities.trait.d.ts +39 -0
- package/load-entities/load-entities.trait.reducer.d.ts +4 -0
- package/load-entities/load-entities.trait.selectors.d.ts +3 -0
- package/load-entities/load-entities.utils.d.ts +4 -0
- package/load-entity/index.d.ts +2 -0
- package/load-entity/load-entity.model.d.ts +9 -0
- package/load-entity/load-entity.traits.d.ts +64 -0
- package/ngrx-traits-common.d.ts +5 -0
- package/package.json +28 -0
- package/public_api.d.ts +1 -0
- package/reset/index.d.ts +1 -0
- package/reset/reset.trait.d.ts +32 -0
- package/select-entities/index.d.ts +3 -0
- package/select-entities/select-entities.model.d.ts +41 -0
- package/select-entities/select-entities.trait.actions.d.ts +2 -0
- package/select-entities/select-entities.trait.d.ts +34 -0
- package/select-entities/select-entities.trait.mutators.d.ts +2 -0
- package/select-entities/select-entities.trait.reducer.d.ts +8 -0
- package/select-entities/select-entities.trait.selectors.d.ts +3 -0
- package/select-entities/select-entities.utils.d.ts +7 -0
- package/select-entity/index.d.ts +2 -0
- package/select-entity/select-entity.model.d.ts +33 -0
- package/select-entity/select-entity.trait.actions.d.ts +2 -0
- package/select-entity/select-entity.trait.d.ts +30 -0
- package/select-entity/select-entity.trait.mutators.d.ts +2 -0
- package/select-entity/select-entity.trait.reducer.d.ts +8 -0
- package/select-entity/select-entity.trait.selectors.d.ts +2 -0
- package/set-entity/index.d.ts +2 -0
- package/set-entity/set-entity.model.d.ts +16 -0
- package/set-entity/set-entity.trait.d.ts +39 -0
- package/sort-entities/index.d.ts +3 -0
- package/sort-entities/sort-entities.model.d.ts +35 -0
- package/sort-entities/sort-entities.trait.actions.d.ts +2 -0
- package/sort-entities/sort-entities.trait.d.ts +33 -0
- package/sort-entities/sort-entities.trait.effect.d.ts +6 -0
- package/sort-entities/sort-entities.trait.mutators.d.ts +3 -0
- package/sort-entities/sort-entities.trait.reducer.d.ts +4 -0
- package/sort-entities/sort-entities.trait.selectors.d.ts +2 -0
- package/sort-entities/sort-entities.utils.d.ts +8 -0
|
@@ -0,0 +1,1511 @@
|
|
|
1
|
+
import * as i2 from '@ngrx/store';
|
|
2
|
+
import { createReducer, on, createAction, props, createSelector } from '@ngrx/store';
|
|
3
|
+
import { insertIf, createTraitFactory, TraitEffect, toMap, camelCaseToSentence, capitalize } from '@ngrx-traits/core';
|
|
4
|
+
import { createEntityAdapter } from '@ngrx/entity';
|
|
5
|
+
import * as i0 from '@angular/core';
|
|
6
|
+
import { Injectable } from '@angular/core';
|
|
7
|
+
import { asyncScheduler, EMPTY, timer, of, pipe } from 'rxjs';
|
|
8
|
+
import { debounce, concatMap, first, map, distinctUntilChanged, startWith, pairwise, concatMapTo, filter, mapTo } from 'rxjs/operators';
|
|
9
|
+
import * as i1 from '@ngrx/effects';
|
|
10
|
+
import { createEffect, ofType, concatLatestFrom } from '@ngrx/effects';
|
|
11
|
+
import { __rest } from 'tslib';
|
|
12
|
+
|
|
13
|
+
const loadEntitiesTraitKey = 'loadEntities';
|
|
14
|
+
|
|
15
|
+
function createLoadEntitiesInitialState(previousInitialState = {}, allConfigs) {
|
|
16
|
+
const traitConfig = allConfigs.loadEntities;
|
|
17
|
+
const adapter = traitConfig.adapter;
|
|
18
|
+
return Object.assign(Object.assign(Object.assign({}, previousInitialState), adapter.getInitialState()), { status: undefined });
|
|
19
|
+
}
|
|
20
|
+
function createLoadEntitiesTraitReducer(initialState, actions, allMutators, allConfigs) {
|
|
21
|
+
const handleEntitiesMerge = !(allConfigs === null || allConfigs === void 0 ? void 0 : allConfigs.pagination);
|
|
22
|
+
return createReducer(initialState, on(actions.loadEntities, (state) => (Object.assign(Object.assign({}, state), { status: 'loading' }))), on(actions.loadEntitiesFail, (state) => (Object.assign(Object.assign({}, state), { status: 'fail' }))), on(actions.loadEntitiesSuccess, (state) => (Object.assign(Object.assign({}, state), { status: 'success' }))), ...insertIf(handleEntitiesMerge, () => on(actions.loadEntitiesSuccess, (state, { entities }) => allMutators.setEntitiesList(entities, Object.assign({}, state)))));
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function createLoadEntitiesTraitMutators(allConfigs) {
|
|
26
|
+
var _a;
|
|
27
|
+
const adapter = (_a = allConfigs === null || allConfigs === void 0 ? void 0 : allConfigs.loadEntities) === null || _a === void 0 ? void 0 : _a.adapter;
|
|
28
|
+
return {
|
|
29
|
+
setEntitiesList: adapter === null || adapter === void 0 ? void 0 : adapter.setAll,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function createLoadEntitiesTraitActions(actionsGroupKey, entitiesName) {
|
|
34
|
+
const actions = {
|
|
35
|
+
loadEntities: createAction(`${actionsGroupKey} Load ${entitiesName}`),
|
|
36
|
+
loadEntitiesSuccess: createAction(`${actionsGroupKey} Load ${entitiesName} Success`, props()),
|
|
37
|
+
loadEntitiesFail: createAction(`${actionsGroupKey} Load ${entitiesName} Fail`, (props) => ({ error: props === null || props === void 0 ? void 0 : props.error })),
|
|
38
|
+
};
|
|
39
|
+
return actions;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function isLoading(state) {
|
|
43
|
+
return state.status === 'loading';
|
|
44
|
+
}
|
|
45
|
+
function isSuccess(state) {
|
|
46
|
+
return state.status === 'success';
|
|
47
|
+
}
|
|
48
|
+
function isFail(state) {
|
|
49
|
+
return state.status === 'fail';
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function selectEntitiesFilter(state) {
|
|
53
|
+
return state.filters;
|
|
54
|
+
}
|
|
55
|
+
function createFilterTraitSelectors() {
|
|
56
|
+
return {
|
|
57
|
+
selectEntitiesFilter,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function createLoadEntitiesTraitSelectors(allConfigs) {
|
|
62
|
+
var _a, _b;
|
|
63
|
+
const adapter = (_a = allConfigs === null || allConfigs === void 0 ? void 0 : allConfigs.loadEntities) === null || _a === void 0 ? void 0 : _a.adapter;
|
|
64
|
+
const entitySelectors = adapter.getSelectors();
|
|
65
|
+
const filterFunction = (_b = allConfigs === null || allConfigs === void 0 ? void 0 : allConfigs.filter) === null || _b === void 0 ? void 0 : _b.filterFn;
|
|
66
|
+
let selectors = {
|
|
67
|
+
selectEntitiesList: entitySelectors.selectAll,
|
|
68
|
+
selectEntitiesMap: entitySelectors.selectEntities,
|
|
69
|
+
selectEntitiesIdsList: entitySelectors.selectIds,
|
|
70
|
+
selectEntitiesTotal: entitySelectors.selectTotal,
|
|
71
|
+
isEntitiesLoadingFail: isFail,
|
|
72
|
+
isEntitiesLoading: isLoading,
|
|
73
|
+
isEntitiesLoadingSuccess: isSuccess,
|
|
74
|
+
};
|
|
75
|
+
if (filterFunction && entitySelectors) {
|
|
76
|
+
const selectEntitiesList = createSelector(entitySelectors.selectAll, selectEntitiesFilter, (entities, filters) => filters ? entities.filter((e) => filterFunction(filters, e)) : entities);
|
|
77
|
+
selectors = Object.assign(Object.assign({}, selectors), { selectEntitiesList, selectEntitiesMap: createSelector(selectors.selectEntitiesMap, selectEntitiesFilter, (entities, filters) => {
|
|
78
|
+
const result = {};
|
|
79
|
+
for (const id in entities) {
|
|
80
|
+
const e = entities[id];
|
|
81
|
+
if (filterFunction(filters, e)) {
|
|
82
|
+
result[id] = e;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return result;
|
|
86
|
+
}), selectEntitiesTotal: createSelector(selectEntitiesList, (entities) => entities.length), selectEntitiesIdsList: createSelector(selectEntitiesList, (entities) => entities.map((e) => adapter === null || adapter === void 0 ? void 0 : adapter.selectId(e))) });
|
|
87
|
+
}
|
|
88
|
+
return selectors;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Generates the ngrx code needed to load a list of entities from the backend
|
|
93
|
+
* with a load[EntitiesName], load[EntitiesName]Success, load[EntitiesName]Fail actions, and selectors to query the
|
|
94
|
+
* entities like selectEntity[EntitiesName]List, selectEntity[EntitiesName]Ids, selectEntity[EntitiesName]Map, and its progress loading
|
|
95
|
+
* with isLoading[EntitiesName],isLoading[EntitiesName]Success, isLoading[EntitiesName]Fail. This trait is the base for all other traits related
|
|
96
|
+
* to a list of entities, the other will call loadEntities when needing data.
|
|
97
|
+
* @param traitConfig - Config object fot the trait factory
|
|
98
|
+
* @param traitConfig.selectId - Function that returns the id of an entity
|
|
99
|
+
* @param traitConfig.sortComparer - Default sort function for to @ngrx/entity EntityAdapter
|
|
100
|
+
*
|
|
101
|
+
* @example
|
|
102
|
+
* // The following trait config
|
|
103
|
+
*
|
|
104
|
+
* export interface TestState
|
|
105
|
+
* extends LoadEntitiesState<Todo>{}
|
|
106
|
+
*
|
|
107
|
+
* const traits = createEntityFeatureFactory(
|
|
108
|
+
* {entityName: 'Todo'},
|
|
109
|
+
* addLoadEntitiesTrait<Todo>(),
|
|
110
|
+
* )({
|
|
111
|
+
* actionsGroupKey: '[Todos]',
|
|
112
|
+
* featureSelector: createFeatureSelector<TestState>>(
|
|
113
|
+
* 'todos',
|
|
114
|
+
* ),
|
|
115
|
+
* });
|
|
116
|
+
* // will generate the actions and selectors
|
|
117
|
+
* traits.actions.loadTodos()
|
|
118
|
+
* traits.actions.loadTodosSuccess({entities: todos})
|
|
119
|
+
* traits.actions.loadTodosFail();
|
|
120
|
+
* traits.selectors.selectTodosList
|
|
121
|
+
* traits.selectors.selectTodosMap
|
|
122
|
+
* traits.selectors.selectTodosIds
|
|
123
|
+
* traits.selectors.selectTodosTotal
|
|
124
|
+
* traits.selectors.isLoadingTodos
|
|
125
|
+
* traits.selectors.isSuccessTodosSuccess
|
|
126
|
+
* traits.selectors.isFailTodosFail
|
|
127
|
+
*/
|
|
128
|
+
function addLoadEntitiesTrait(traitConfig) {
|
|
129
|
+
const adapter = createEntityAdapter(traitConfig);
|
|
130
|
+
return createTraitFactory({
|
|
131
|
+
key: loadEntitiesTraitKey,
|
|
132
|
+
config: Object.assign(Object.assign({}, traitConfig), { adapter }),
|
|
133
|
+
actions: ({ actionsGroupKey, entitiesName }) => createLoadEntitiesTraitActions(actionsGroupKey, entitiesName),
|
|
134
|
+
selectors: ({ allConfigs }) => createLoadEntitiesTraitSelectors(allConfigs),
|
|
135
|
+
mutators: ({ allConfigs }) => createLoadEntitiesTraitMutators(allConfigs),
|
|
136
|
+
initialState: ({ previousInitialState, allConfigs, }) => createLoadEntitiesInitialState(previousInitialState, allConfigs),
|
|
137
|
+
reducer: ({ initialState, allActions, allMutators, allConfigs }) => createLoadEntitiesTraitReducer(initialState, allActions, allMutators, allConfigs),
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const entitiesPaginationTraitKey = 'pagination';
|
|
142
|
+
|
|
143
|
+
function createFilterTraitEffects(allActions, allSelectors, allConfigs) {
|
|
144
|
+
const traitConfig = allConfigs.filter;
|
|
145
|
+
class FilterEffect extends TraitEffect {
|
|
146
|
+
constructor() {
|
|
147
|
+
super(...arguments);
|
|
148
|
+
this.storeFilter$ = createEffect(() => ({ debounce: debounceTime = traitConfig.defaultDebounceTime, scheduler = asyncScheduler, } = {}) => this.actions$.pipe(ofType(allActions.filterEntities), debounce((value) => (value === null || value === void 0 ? void 0 : value.forceLoad) ? EMPTY : timer(debounceTime, scheduler)), concatMap((payload) => payload.patch
|
|
149
|
+
? this.store.select(allSelectors.selectEntitiesFilter).pipe(first(), map((storedFilters) => (Object.assign(Object.assign({}, payload), { filters: Object.assign(Object.assign({}, storedFilters), payload === null || payload === void 0 ? void 0 : payload.filters) }))))
|
|
150
|
+
: of(payload)), distinctUntilChanged((previous, current) => !(current === null || current === void 0 ? void 0 : current.forceLoad) &&
|
|
151
|
+
JSON.stringify(previous === null || previous === void 0 ? void 0 : previous.filters) ===
|
|
152
|
+
JSON.stringify(current === null || current === void 0 ? void 0 : current.filters)), (traitConfig === null || traitConfig === void 0 ? void 0 : traitConfig.isRemoteFilter)
|
|
153
|
+
? pipe(startWith({
|
|
154
|
+
filters: traitConfig.defaultFilter,
|
|
155
|
+
patch: false,
|
|
156
|
+
}), pairwise(), concatMap(([previous, current]) => (traitConfig === null || traitConfig === void 0 ? void 0 : traitConfig.isRemoteFilter(previous === null || previous === void 0 ? void 0 : previous.filters, current === null || current === void 0 ? void 0 : current.filters))
|
|
157
|
+
? [
|
|
158
|
+
allActions.storeEntitiesFilter({
|
|
159
|
+
filters: current === null || current === void 0 ? void 0 : current.filters,
|
|
160
|
+
patch: current === null || current === void 0 ? void 0 : current.patch,
|
|
161
|
+
}),
|
|
162
|
+
allActions.loadEntities(),
|
|
163
|
+
]
|
|
164
|
+
: [
|
|
165
|
+
allActions.storeEntitiesFilter({
|
|
166
|
+
filters: current === null || current === void 0 ? void 0 : current.filters,
|
|
167
|
+
patch: current === null || current === void 0 ? void 0 : current.patch,
|
|
168
|
+
}),
|
|
169
|
+
]))
|
|
170
|
+
: map((action) => allActions.storeEntitiesFilter({
|
|
171
|
+
filters: action === null || action === void 0 ? void 0 : action.filters,
|
|
172
|
+
patch: action === null || action === void 0 ? void 0 : action.patch,
|
|
173
|
+
}))));
|
|
174
|
+
this.loadEntities$ = (!(traitConfig === null || traitConfig === void 0 ? void 0 : traitConfig.filterFn) || (traitConfig === null || traitConfig === void 0 ? void 0 : traitConfig.isRemoteFilter)) &&
|
|
175
|
+
createEffect(() => {
|
|
176
|
+
return this.actions$.pipe(ofType(allActions['storeEntitiesFilter']), concatMap(() => (allActions === null || allActions === void 0 ? void 0 : allActions.loadEntitiesFirstPage)
|
|
177
|
+
? [
|
|
178
|
+
allActions.clearEntitiesPagesCache(),
|
|
179
|
+
allActions.loadEntitiesFirstPage(),
|
|
180
|
+
]
|
|
181
|
+
: [allActions.loadEntities()]));
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
FilterEffect.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.1.2", ngImport: i0, type: FilterEffect, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
|
|
186
|
+
FilterEffect.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "12.1.2", ngImport: i0, type: FilterEffect });
|
|
187
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.1.2", ngImport: i0, type: FilterEffect, decorators: [{
|
|
188
|
+
type: Injectable
|
|
189
|
+
}] });
|
|
190
|
+
return [FilterEffect];
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
function createFilterInitialState(previousInitialState, allConfigs) {
|
|
194
|
+
var _a;
|
|
195
|
+
return Object.assign(Object.assign({}, previousInitialState), { filters: (_a = allConfigs === null || allConfigs === void 0 ? void 0 : allConfigs.filter) === null || _a === void 0 ? void 0 : _a.defaultFilter });
|
|
196
|
+
}
|
|
197
|
+
function createFilterTraitReducer(initialState, allActions, allMutators) {
|
|
198
|
+
return createReducer(initialState, on(allActions.storeEntitiesFilter, (state, { filters }) => allMutators.setEntitiesFilters(filters, state)));
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
const filterEntitiesTraitKey = 'filter';
|
|
202
|
+
|
|
203
|
+
function createFilterTraitMutators() {
|
|
204
|
+
function setEntitiesFilters(filters, state) {
|
|
205
|
+
return Object.assign(Object.assign({}, state), { filters });
|
|
206
|
+
}
|
|
207
|
+
return { setEntitiesFilters };
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
function createFilterTraitActions(actionsGroupKey, entitiesName) {
|
|
211
|
+
const actions = {
|
|
212
|
+
filterEntities: createAction(`${actionsGroupKey} Filter ${entitiesName}`, (props) => ({
|
|
213
|
+
filters: props === null || props === void 0 ? void 0 : props.filters,
|
|
214
|
+
forceLoad: props === null || props === void 0 ? void 0 : props.forceLoad,
|
|
215
|
+
patch: props === null || props === void 0 ? void 0 : props.patch,
|
|
216
|
+
})),
|
|
217
|
+
storeEntitiesFilter: createAction(`${actionsGroupKey} Store ${entitiesName} Filter`, (props) => ({
|
|
218
|
+
filters: props === null || props === void 0 ? void 0 : props.filters,
|
|
219
|
+
patch: props === null || props === void 0 ? void 0 : props.patch,
|
|
220
|
+
})),
|
|
221
|
+
};
|
|
222
|
+
return actions;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Generates the ngrx code needed to filter a list of entities locally or remotely, adds a filter
|
|
227
|
+
* action and a selectFilter selector, the filter action is debounced and the filter will only
|
|
228
|
+
* call the loadEntities action if the params have changed, so there is no need to implement that in
|
|
229
|
+
* the components. The filter action has a `forceLoad` param which can
|
|
230
|
+
* be use to skip that restriction for one call or setting the `defaultDebounceTime` to 0 for all calls.
|
|
231
|
+
* Calling the filter action will also replace the `filters` param in the store, if the `patch` param is set
|
|
232
|
+
* the filters are merged with the previous value in the store.
|
|
233
|
+
* @param traitConfig - Config object fot the trait factory
|
|
234
|
+
* @param traitConfig.defaultFilter - Initial value for the filter
|
|
235
|
+
* @param traitConfig.filterFn - Function to filter entities in memory, if not present then its expected
|
|
236
|
+
* is filtered by the backend unless isRemoteFilter is defned
|
|
237
|
+
* @param traitConfig.defaultDebounceTime - Value in milliseconds. Default to 400ms
|
|
238
|
+
* @param traitConfig.isRemoteFilter - Function to when it returns true it fires loadEntities so a remote
|
|
239
|
+
* backend filtering can run, otherwise it uses filterFn to do a local filtering
|
|
240
|
+
*
|
|
241
|
+
* @example
|
|
242
|
+
* // The following trait config
|
|
243
|
+
*
|
|
244
|
+
* export interface TestState
|
|
245
|
+
* extends EntityAndStatusState<Todo>,FilterState<TodoFilter>{}
|
|
246
|
+
*
|
|
247
|
+
* const traits = createEntityFeatureFactory(
|
|
248
|
+
* addLoadEntitiesTrait<Todo>(),
|
|
249
|
+
* //addFilterEntitiesTrait<Todo,TodoFilter>() // no params uses remote filtering
|
|
250
|
+
* addFilterEntitiesTrait<Todo,TodoFilter>({filterFn: (filter, entity) => // local filtering
|
|
251
|
+
* filter?.content && entity.content?.includes(filter?.content) || false})
|
|
252
|
+
* // or use the following function to switch between remote search and local
|
|
253
|
+
* // depending on which properties have changed in the filter
|
|
254
|
+
* // isRemoteFilter: (previous, current) => previous?.someRemoteParam !== current?.someRemoteParam,
|
|
255
|
+
* )({
|
|
256
|
+
* actionsGroupKey: '[Todos]',
|
|
257
|
+
* featureSelector: createFeatureSelector<TestState>>(
|
|
258
|
+
* 'todos',
|
|
259
|
+
* ),
|
|
260
|
+
* });
|
|
261
|
+
* // will generate the following actions and selectors, plus the ones generated by other traits
|
|
262
|
+
* traits.actions.filterTodos()
|
|
263
|
+
* traits.selectors.selectTodosFilter()
|
|
264
|
+
*/
|
|
265
|
+
function addFilterEntitiesTrait({ defaultDebounceTime = 400, defaultFilter, filterFn, isRemoteFilter, } = {}) {
|
|
266
|
+
return createTraitFactory({
|
|
267
|
+
key: filterEntitiesTraitKey,
|
|
268
|
+
depends: [entitiesPaginationTraitKey, loadEntitiesTraitKey],
|
|
269
|
+
config: {
|
|
270
|
+
defaultDebounceTime,
|
|
271
|
+
defaultFilter,
|
|
272
|
+
filterFn,
|
|
273
|
+
isRemoteFilter,
|
|
274
|
+
},
|
|
275
|
+
actions: ({ actionsGroupKey, entitiesName }) => createFilterTraitActions(actionsGroupKey, entitiesName),
|
|
276
|
+
selectors: () => createFilterTraitSelectors(),
|
|
277
|
+
mutators: () => createFilterTraitMutators(),
|
|
278
|
+
initialState: ({ previousInitialState, allConfigs, }) => createFilterInitialState(previousInitialState, allConfigs),
|
|
279
|
+
reducer: ({ initialState, allActions, allMutators }) => createFilterTraitReducer(initialState, allActions, allMutators),
|
|
280
|
+
effects: ({ allActions, allSelectors, allConfigs }) => createFilterTraitEffects(allActions, allSelectors, allConfigs),
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
function createPaginationTraitSelectors(previousSelectors, allConfigs) {
|
|
285
|
+
var _a;
|
|
286
|
+
const { selectEntitiesList, isEntitiesLoading } = previousSelectors;
|
|
287
|
+
const filterFunction = (_a = allConfigs === null || allConfigs === void 0 ? void 0 : allConfigs.filter) === null || _a === void 0 ? void 0 : _a.filterFn;
|
|
288
|
+
function selectPagination(state) {
|
|
289
|
+
return state.pagination;
|
|
290
|
+
}
|
|
291
|
+
const selectPaginationFiltered = filterFunction
|
|
292
|
+
? createSelector(selectEntitiesList, selectPagination, (entities, pagination) => {
|
|
293
|
+
return Object.assign(Object.assign({}, pagination), { total: entities.length, cache: Object.assign(Object.assign({}, pagination.cache), { start: 0, end: entities.length }) });
|
|
294
|
+
})
|
|
295
|
+
: selectPagination;
|
|
296
|
+
const selectPageEntitiesList = createSelector(selectEntitiesList, selectPaginationFiltered, (entities, pagination, { page } = { page: pagination.currentPage }) => {
|
|
297
|
+
const startIndex = page * pagination.pageSize - pagination.cache.start;
|
|
298
|
+
let endIndex = startIndex + pagination.pageSize;
|
|
299
|
+
endIndex =
|
|
300
|
+
endIndex < pagination.cache.end ? endIndex : pagination.cache.end;
|
|
301
|
+
return entities.slice(startIndex, endIndex);
|
|
302
|
+
});
|
|
303
|
+
const selectEntitiesPageInfo = createSelector(selectPaginationFiltered, (pagination) => {
|
|
304
|
+
const pagesCount = pagination.total && pagination.total > 0
|
|
305
|
+
? Math.ceil(pagination.total / pagination.pageSize)
|
|
306
|
+
: undefined;
|
|
307
|
+
return {
|
|
308
|
+
pageIndex: pagination.currentPage,
|
|
309
|
+
total: pagination.total,
|
|
310
|
+
pageSize: pagination.pageSize,
|
|
311
|
+
pagesCount,
|
|
312
|
+
hasPrevious: pagination.currentPage - 1 >= 0,
|
|
313
|
+
hasNext: pagination.total && pagination.total > 0
|
|
314
|
+
? pagination.currentPage + 1 < pagesCount
|
|
315
|
+
: true,
|
|
316
|
+
cacheType: pagination.cache.type,
|
|
317
|
+
};
|
|
318
|
+
});
|
|
319
|
+
const isEntitiesPageInCache = createSelector(selectPaginationFiltered, (pagination, { page } = { page: pagination.currentPage }) => {
|
|
320
|
+
const startIndex = page * pagination.pageSize;
|
|
321
|
+
let endIndex = startIndex + pagination.pageSize - 1;
|
|
322
|
+
endIndex =
|
|
323
|
+
pagination.total && endIndex > pagination.total
|
|
324
|
+
? pagination.total - 1
|
|
325
|
+
: endIndex;
|
|
326
|
+
return (startIndex >= pagination.cache.start && endIndex <= pagination.cache.end);
|
|
327
|
+
});
|
|
328
|
+
const selectEntitiesPage = createSelector(selectPageEntitiesList, selectEntitiesPageInfo,
|
|
329
|
+
// props look unsued but they are pass to the selectPageEntities
|
|
330
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
331
|
+
(entities, pageInfo, props = { page: pageInfo.pageIndex }) => (Object.assign({ entities }, pageInfo)));
|
|
332
|
+
const selectEntitiesPagedRequest = createSelector(selectPagination, (pagination) => ({
|
|
333
|
+
startIndex: pagination.pageSize * pagination.requestPage,
|
|
334
|
+
size: pagination.pageSize * pagination.pagesToCache,
|
|
335
|
+
page: pagination.requestPage,
|
|
336
|
+
}));
|
|
337
|
+
const isLoadingEntitiesPage = createSelector(isEntitiesLoading, selectPagination, (isLoading, pagination) => isLoading && pagination.requestPage === pagination.currentPage);
|
|
338
|
+
return {
|
|
339
|
+
selectPageEntitiesList,
|
|
340
|
+
isEntitiesPageInCache,
|
|
341
|
+
selectEntitiesPage,
|
|
342
|
+
selectEntitiesPagedRequest,
|
|
343
|
+
selectEntitiesPageInfo,
|
|
344
|
+
isLoadingEntitiesPage,
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
function createPaginationTraitActions(actionsGroupKey, entitiesName) {
|
|
349
|
+
const actions = {
|
|
350
|
+
loadEntitiesPage: createAction(`${actionsGroupKey} Load ${entitiesName} Page`, ({ index, forceLoad }) => ({
|
|
351
|
+
index,
|
|
352
|
+
forceLoad,
|
|
353
|
+
})),
|
|
354
|
+
loadEntitiesPageSuccess: createAction(`${actionsGroupKey} Load ${entitiesName}
|
|
355
|
+
Page Success`),
|
|
356
|
+
loadEntitiesPageFail: createAction(`${actionsGroupKey} Load ${entitiesName} Page Fail`),
|
|
357
|
+
loadEntitiesPreviousPage: createAction(`${actionsGroupKey} Load Previous ${entitiesName} Page`),
|
|
358
|
+
loadEntitiesNextPage: createAction(`${actionsGroupKey} Load Next ${entitiesName} Page`),
|
|
359
|
+
loadEntitiesFirstPage: createAction(`${actionsGroupKey} Load First ${entitiesName} Page`, (forceLoad) => ({ forceLoad })),
|
|
360
|
+
loadEntitiesLastPage: createAction(`${actionsGroupKey} Load Last ${entitiesName} Page`),
|
|
361
|
+
clearEntitiesPagesCache: createAction(`${actionsGroupKey} Clear ${entitiesName} Cache`),
|
|
362
|
+
setEntitiesRequestPage: createAction(`${actionsGroupKey} Set ${entitiesName} Request Page`, props()),
|
|
363
|
+
};
|
|
364
|
+
return actions;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
function createPaginationInitialState(previousInitialState, allConfigs) {
|
|
368
|
+
const { currentPage, pageSize, cacheType, pagesToCache } = allConfigs.pagination;
|
|
369
|
+
return Object.assign(Object.assign({}, previousInitialState), { pagination: {
|
|
370
|
+
pageSize,
|
|
371
|
+
currentPage,
|
|
372
|
+
requestPage: currentPage,
|
|
373
|
+
pagesToCache,
|
|
374
|
+
cache: {
|
|
375
|
+
type: cacheType,
|
|
376
|
+
start: 0,
|
|
377
|
+
end: 0,
|
|
378
|
+
},
|
|
379
|
+
} });
|
|
380
|
+
}
|
|
381
|
+
function createPaginationTraitReducer(initialState, allActions, allSelectors, allMutators, allConfigs) {
|
|
382
|
+
var _a;
|
|
383
|
+
function addToCacheTotal(state, add) {
|
|
384
|
+
var _a;
|
|
385
|
+
return Object.assign(Object.assign({}, state), { pagination: Object.assign(Object.assign({}, state.pagination), { total: ((_a = state.pagination.total) !== null && _a !== void 0 ? _a : 0) + add }) });
|
|
386
|
+
}
|
|
387
|
+
function clearPagesCache(state) {
|
|
388
|
+
return Object.assign(Object.assign({}, state), { entities: {}, ids: [], pagination: Object.assign(Object.assign({}, state.pagination), { currentPage: 0, total: 0, cache: Object.assign(Object.assign({}, state.pagination.cache), { start: 0, end: 0 }) }) });
|
|
389
|
+
}
|
|
390
|
+
function recalculateTotal(state) {
|
|
391
|
+
const total = allSelectors.selectEntitiesTotal(state);
|
|
392
|
+
return Object.assign(Object.assign({}, state), { status: 'success', pagination: Object.assign(Object.assign({}, state.pagination), { currentPage: 0, total, cache: Object.assign(Object.assign({}, state.pagination.cache), { start: 0, end: total }) }) });
|
|
393
|
+
}
|
|
394
|
+
const filterRemote = !((_a = allConfigs === null || allConfigs === void 0 ? void 0 : allConfigs.filter) === null || _a === void 0 ? void 0 : _a.filterFn);
|
|
395
|
+
return createReducer(initialState, on(allActions.loadEntitiesPage, (state, { index }) => (Object.assign(Object.assign({}, state), { pagination: Object.assign(Object.assign({}, state.pagination), { currentPage: index, requestPage: index }), status: 'loading' }))), on(allActions.setEntitiesRequestPage, (state, { index }) => (Object.assign(Object.assign({}, state), { pagination: Object.assign(Object.assign({}, state.pagination), { requestPage: index }), status: 'loading' }))), on(allActions.loadEntitiesPageSuccess, (state) => (Object.assign(Object.assign({}, state), { status: 'success' }))), on(allActions.loadEntitiesPageFail, (state) => (Object.assign(Object.assign({}, state), { status: 'fail' }))), on(allActions.clearEntitiesPagesCache, (state) => clearPagesCache(state)), on(allActions.loadEntitiesSuccess, (state, { entities, total }) => allMutators.mergePaginatedEntities(entities, total, Object.assign(Object.assign({}, state), { status: 'success' }))), ...insertIf(allActions.addEntities, () => on(allActions.addEntities, (state, { entities }) => addToCacheTotal(state, entities.length))), ...insertIf(allActions.removeEntities, () => on(allActions.removeEntities, (state, { keys }) => addToCacheTotal(state, -keys.length))), ...insertIf(filterRemote && allActions.filterEntities, () => on(allActions.filterEntities, (state) => recalculateTotal(state))), ...insertIf(allActions.removeAllEntities, () => on(allActions.removeAllEntities, (state) => clearPagesCache(state))));
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
function createPaginationTraitEffects(allActions, allSelectors) {
|
|
399
|
+
class PaginationEffect extends TraitEffect {
|
|
400
|
+
constructor() {
|
|
401
|
+
super(...arguments);
|
|
402
|
+
this.loadPage$ = createEffect(() => {
|
|
403
|
+
return this.actions$.pipe(ofType(allActions.loadEntitiesPage), concatLatestFrom(() => this.store.select(allSelectors.isEntitiesPageInCache)), map(([{ forceLoad }, isInCache]) => !forceLoad && isInCache
|
|
404
|
+
? allActions.loadEntitiesPageSuccess()
|
|
405
|
+
: allActions.loadEntities()));
|
|
406
|
+
});
|
|
407
|
+
this.preloadNextPage$ = createEffect(() => {
|
|
408
|
+
return this.actions$.pipe(ofType(allActions.loadEntitiesPageSuccess), concatMapTo(this.store.select(allSelectors.selectEntitiesPageInfo).pipe(first())), filter((pageInfo) => !!pageInfo.total &&
|
|
409
|
+
pageInfo.hasNext &&
|
|
410
|
+
pageInfo.cacheType !== 'full'), concatMap((pageInfo) => this.store
|
|
411
|
+
.select(allSelectors.isEntitiesPageInCache, {
|
|
412
|
+
page: pageInfo.pageIndex + 1,
|
|
413
|
+
})
|
|
414
|
+
.pipe(first(), map((isInCache) => (!isInCache && pageInfo) || undefined))), filter((pageInfo) => !!pageInfo), concatMap((pageInfo) => [
|
|
415
|
+
allActions.setEntitiesRequestPage({ index: pageInfo.pageIndex + 1 }),
|
|
416
|
+
allActions.loadEntities(),
|
|
417
|
+
]));
|
|
418
|
+
});
|
|
419
|
+
this.loadFirstPage$ = createEffect(() => {
|
|
420
|
+
return this.actions$.pipe(ofType(allActions.loadEntitiesFirstPage), map(() => allActions.loadEntitiesPage({ index: 0 })));
|
|
421
|
+
});
|
|
422
|
+
this.loadPreviousPage$ = createEffect(() => {
|
|
423
|
+
return this.actions$.pipe(ofType(allActions.loadEntitiesPreviousPage), concatMapTo(this.store.select(allSelectors.selectEntitiesPageInfo).pipe(first())), map((page) => page.hasPrevious
|
|
424
|
+
? allActions.loadEntitiesPage({ index: page.pageIndex - 1 })
|
|
425
|
+
: allActions.loadEntitiesPageFail()));
|
|
426
|
+
});
|
|
427
|
+
this.loadNextPage$ = createEffect(() => {
|
|
428
|
+
return this.actions$.pipe(ofType(allActions.loadEntitiesNextPage), concatMapTo(this.store.select(allSelectors.selectEntitiesPageInfo).pipe(first())), map((page) => page.hasNext
|
|
429
|
+
? allActions.loadEntitiesPage({ index: page.pageIndex + 1 })
|
|
430
|
+
: allActions.loadEntitiesPageFail()));
|
|
431
|
+
});
|
|
432
|
+
this.loadLastPage$ = createEffect(() => {
|
|
433
|
+
return this.actions$.pipe(ofType(allActions.loadEntitiesLastPage), concatMapTo(this.store.select(allSelectors.selectEntitiesPageInfo).pipe(first())), map((page) => page.hasNext && page.pagesCount
|
|
434
|
+
? allActions.loadEntitiesPage({ index: page.pagesCount - 1 })
|
|
435
|
+
: allActions.loadEntitiesPageFail()));
|
|
436
|
+
});
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
PaginationEffect.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.1.2", ngImport: i0, type: PaginationEffect, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
|
|
440
|
+
PaginationEffect.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "12.1.2", ngImport: i0, type: PaginationEffect });
|
|
441
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.1.2", ngImport: i0, type: PaginationEffect, decorators: [{
|
|
442
|
+
type: Injectable
|
|
443
|
+
}] });
|
|
444
|
+
return [PaginationEffect];
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
function createPaginationTraitMutators(allSelectors, allConfigs) {
|
|
448
|
+
const adapter = allConfigs.loadEntities.adapter;
|
|
449
|
+
function mergePaginatedEntities(entities, total = undefined, state) {
|
|
450
|
+
const cacheType = state.pagination.cache.type;
|
|
451
|
+
switch (cacheType) {
|
|
452
|
+
case 'full':
|
|
453
|
+
return adapter.setAll(entities, Object.assign(Object.assign({}, state), { pagination: Object.assign(Object.assign({}, state.pagination), { total: entities.length, cache: Object.assign(Object.assign({}, state.pagination.cache), { start: 0, end: entities.length }) }) }));
|
|
454
|
+
case 'partial': {
|
|
455
|
+
const isPreloadNextPages = state.pagination.currentPage + 1 === state.pagination.requestPage;
|
|
456
|
+
const start = state.pagination.currentPage * state.pagination.pageSize;
|
|
457
|
+
const newEntities = isPreloadNextPages
|
|
458
|
+
? [...allSelectors.selectPageEntitiesList(state), ...entities]
|
|
459
|
+
: entities;
|
|
460
|
+
return adapter.setAll(newEntities, Object.assign(Object.assign({}, state), { pagination: Object.assign(Object.assign({}, state.pagination), { total, cache: Object.assign(Object.assign({}, state.pagination.cache), { start, end: start + entities.length }) }) }));
|
|
461
|
+
}
|
|
462
|
+
case 'grow':
|
|
463
|
+
return adapter.addMany(entities, Object.assign(Object.assign({}, state), { pagination: Object.assign(Object.assign({}, state.pagination), { total, cache: Object.assign(Object.assign({}, state.pagination.cache), { end: state.ids.length + entities.length }) }) }));
|
|
464
|
+
}
|
|
465
|
+
return state;
|
|
466
|
+
}
|
|
467
|
+
return { mergePaginatedEntities };
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
/**
|
|
471
|
+
* Generates ngrx code to paginate an list of entities, this has 3 cache `cacheType`
|
|
472
|
+
* - 'full': The full result is cache in memory and split in pages to render, useful
|
|
473
|
+
* for small result but not so small that requires been render in pages
|
|
474
|
+
* - 'partial': Backend returns partial results because is are to big, this has a cache a few pages forward
|
|
475
|
+
* to avoid calling the backend on each page, the cache is clean when a new loadEntities is required
|
|
476
|
+
* - 'grow': Similar to partial that the backend returns partial result, but in this case the cache grows,
|
|
477
|
+
* after each loadEntities the cache is appended to the previous cache, this mode is ideal for infinite scrolls,
|
|
478
|
+
* where you will only call loadNextPage.
|
|
479
|
+
* To make the pagination experience smoother the loadEntities to get new pages is done when the current page is change to
|
|
480
|
+
* the last cached page.
|
|
481
|
+
* @param config
|
|
482
|
+
* @param config.cacheType - Default to 'full', change the cache mode
|
|
483
|
+
* @param config.pageSize - Default to 20, number of entities on each page
|
|
484
|
+
* @param config.currentPage - Default to 0, starting page
|
|
485
|
+
* @param config.pagesToCache - Default to 3, used in partial and grow cache mode, is the number of
|
|
486
|
+
* extra pages kept in cache to avoid calling the backend on each page
|
|
487
|
+
*
|
|
488
|
+
* @example
|
|
489
|
+
* // The following trait config
|
|
490
|
+
*
|
|
491
|
+
* export interface TestState
|
|
492
|
+
* extends EntityAndStatusState<Todo>,SingleSelectionState{}
|
|
493
|
+
*
|
|
494
|
+
* const traits = createEntityFeatureFactory(
|
|
495
|
+
* addLoadEntitiesTrait<Todo>(),
|
|
496
|
+
* addEntitiesPaginationTrait<Todo>()
|
|
497
|
+
* )({
|
|
498
|
+
* actionsGroupKey: '[Todos]',
|
|
499
|
+
* featureSelector: createFeatureSelector<TestState>>(
|
|
500
|
+
* 'todos',
|
|
501
|
+
* ),
|
|
502
|
+
* });
|
|
503
|
+
* // will generate the following actions and selectors, plus the ones generated by other traits
|
|
504
|
+
* traits.actions.loadTodosPage({index})
|
|
505
|
+
* traits.actions.loadTodosPageSuccess()
|
|
506
|
+
* traits.actions.loadTodosPageFail()
|
|
507
|
+
* traits.actions.loadTodosNextPage()
|
|
508
|
+
* traits.actions.loadTodosPreviousPage()
|
|
509
|
+
* traits.actions.loadTodosFirstPage()
|
|
510
|
+
* traits.actions.loadTodosLastPage()
|
|
511
|
+
* traits.actions.clearTodosPagesCache()
|
|
512
|
+
*
|
|
513
|
+
* // page param is optional and defaults to current page
|
|
514
|
+
* traits.selectors.isTodosPageInCache({page})
|
|
515
|
+
* traits.selectors.selectPageTodosList({page})
|
|
516
|
+
* traits.selectors.isLoadingTodosPage({page})
|
|
517
|
+
* // prefer isLoadingTodosPage over isLoadingTodos which will return true even
|
|
518
|
+
* // if the page loading is not the current one
|
|
519
|
+
* traits.selectors.selectTodosPage({page})
|
|
520
|
+
* traits.selectors.selectTodosPagedRequest()// use in effects to get paging parameter
|
|
521
|
+
* traits.selectors.selectTodosPageInfo()
|
|
522
|
+
*/
|
|
523
|
+
function addEntitiesPaginationTrait({ cacheType = 'full', pageSize = 20, currentPage = 0, pagesToCache = 3, } = {}) {
|
|
524
|
+
return createTraitFactory({
|
|
525
|
+
key: entitiesPaginationTraitKey,
|
|
526
|
+
depends: [loadEntitiesTraitKey],
|
|
527
|
+
config: {
|
|
528
|
+
cacheType,
|
|
529
|
+
pageSize,
|
|
530
|
+
currentPage,
|
|
531
|
+
pagesToCache,
|
|
532
|
+
},
|
|
533
|
+
actions: ({ actionsGroupKey, entitiesName }) => createPaginationTraitActions(actionsGroupKey, entitiesName),
|
|
534
|
+
selectors: ({ previousSelectors, allConfigs, }) => createPaginationTraitSelectors(previousSelectors, allConfigs),
|
|
535
|
+
mutators: ({ allSelectors, allConfigs }) => createPaginationTraitMutators(allSelectors, allConfigs),
|
|
536
|
+
initialState: ({ previousInitialState, allConfigs, }) => createPaginationInitialState(previousInitialState, allConfigs),
|
|
537
|
+
reducer: ({ initialState, allActions, allSelectors, allMutators, allConfigs, }) => createPaginationTraitReducer(initialState, allActions, allSelectors, allMutators, allConfigs),
|
|
538
|
+
effects: ({ allActions, allSelectors }) => createPaginationTraitEffects(allActions, allSelectors),
|
|
539
|
+
});
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
function createSelectEntitiesTraitActions(actionsGroupKey, entitiesName) {
|
|
543
|
+
return {
|
|
544
|
+
selectEntities: createAction(`${actionsGroupKey} Select ${entitiesName}`, props()),
|
|
545
|
+
deselectEntities: createAction(`${actionsGroupKey} Deselect ${entitiesName}`, props()),
|
|
546
|
+
toggleSelectEntities: createAction(`${actionsGroupKey} Toggle Select ${entitiesName}`, props()),
|
|
547
|
+
toggleSelectAllEntities: createAction(`${actionsGroupKey} Toggle Select All ${entitiesName}`),
|
|
548
|
+
clearEntitiesSelection: createAction(`${actionsGroupKey} Clear ${entitiesName} Selection`),
|
|
549
|
+
};
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
function deselectEntities(id, state) {
|
|
553
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
554
|
+
const _a = state.selectedIds, _b = id, _value = _a[_b], selectedIds = __rest(_a, [typeof _b === "symbol" ? _b : _b + ""]);
|
|
555
|
+
return Object.assign(Object.assign({}, state), { selectedIds: selectedIds });
|
|
556
|
+
}
|
|
557
|
+
function selectEntities(id, state) {
|
|
558
|
+
return Object.assign(Object.assign({}, state), { selectedIds: Object.assign(Object.assign({}, state.selectedIds), { [id]: true }) });
|
|
559
|
+
}
|
|
560
|
+
function toggleSelectEntities(id, state) {
|
|
561
|
+
const selected = state.selectedIds[id];
|
|
562
|
+
if (selected) {
|
|
563
|
+
return deselectEntities(id, state);
|
|
564
|
+
}
|
|
565
|
+
else {
|
|
566
|
+
return selectEntities(id, state);
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
function clearEntitiesSelection(state) {
|
|
570
|
+
return Object.assign(Object.assign({}, state), { selectedIds: {} });
|
|
571
|
+
}
|
|
572
|
+
function selectTotalSelectedEntities(state) {
|
|
573
|
+
return Object.keys(state.selectedIds).length;
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
function createSelectEntitiesTraitSelectors(previousSelectors) {
|
|
577
|
+
const { selectEntitiesMap, selectEntitiesTotal } = previousSelectors;
|
|
578
|
+
function selectEntitiesIdsSelectedMap(state) {
|
|
579
|
+
return state.selectedIds;
|
|
580
|
+
}
|
|
581
|
+
const selectEntitiesIdsSelectedList = createSelector(selectEntitiesIdsSelectedMap, (ids) => Object.keys(ids));
|
|
582
|
+
const selectEntitiesSelectedMap = createSelector(selectEntitiesIdsSelectedList, selectEntitiesMap, (selectedIds, entities) => selectedIds.reduce((acum, id) => {
|
|
583
|
+
acum[id] = entities[id];
|
|
584
|
+
return acum;
|
|
585
|
+
}, {}));
|
|
586
|
+
const selectEntitiesSelectedList = createSelector(selectEntitiesIdsSelectedList, selectEntitiesMap, (selectedIds, entities) => selectedIds.map((id) => entities[id]));
|
|
587
|
+
const isAllEntitiesSelected = createSelector((state) => selectEntitiesTotal(state), selectTotalSelectedEntities, (total, totalSelected) => totalSelected > 0 && totalSelected === total
|
|
588
|
+
? 'all'
|
|
589
|
+
: totalSelected === 0
|
|
590
|
+
? 'none'
|
|
591
|
+
: 'some');
|
|
592
|
+
return {
|
|
593
|
+
selectEntitiesIdsSelectedMap,
|
|
594
|
+
selectEntitiesIdsSelectedList,
|
|
595
|
+
selectEntitiesSelectedMap,
|
|
596
|
+
selectEntitiesSelectedList,
|
|
597
|
+
selectTotalSelectedEntities,
|
|
598
|
+
isAllEntitiesSelected,
|
|
599
|
+
};
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
function createSelectEntitiesInitialState(previousInitialState) {
|
|
603
|
+
return Object.assign(Object.assign({}, previousInitialState), { selectedIds: {} });
|
|
604
|
+
}
|
|
605
|
+
function createSelectEntitiesTraitReducer(initialState, allActions, allMutators, allConfigs) {
|
|
606
|
+
var _a, _b;
|
|
607
|
+
const { adapter } = allConfigs.loadEntities;
|
|
608
|
+
const sortRemote = (_a = allConfigs.sort) === null || _a === void 0 ? void 0 : _a.remote;
|
|
609
|
+
const paginationCacheType = (_b = allConfigs.pagination) === null || _b === void 0 ? void 0 : _b.cacheType;
|
|
610
|
+
function updateSelectedIdsChanged(state, updates) {
|
|
611
|
+
const changedIds = updates.reduce((acc, updated) => {
|
|
612
|
+
const id = adapter.selectId(updated.changes);
|
|
613
|
+
if (id && id !== updated.id && state.selectedIds[updated.id] != null) {
|
|
614
|
+
acc.push(updated);
|
|
615
|
+
return acc;
|
|
616
|
+
}
|
|
617
|
+
return acc;
|
|
618
|
+
}, []);
|
|
619
|
+
if (changedIds.length) {
|
|
620
|
+
const selectedIds = Object.assign({}, state.selectedIds);
|
|
621
|
+
changedIds.forEach((updated) => {
|
|
622
|
+
const id = adapter.selectId(updated.changes);
|
|
623
|
+
const value = selectedIds[updated.id];
|
|
624
|
+
delete selectedIds[updated.id];
|
|
625
|
+
selectedIds[id] = value;
|
|
626
|
+
});
|
|
627
|
+
return Object.assign(Object.assign({}, state), { selectedIds });
|
|
628
|
+
}
|
|
629
|
+
return state;
|
|
630
|
+
}
|
|
631
|
+
return createReducer(initialState, on(allActions.selectEntities, (state, { id }) => allMutators.selectEntities(id, state)), on(allActions.deselectEntities, (state, { id }) => allMutators.deselectEntities(id, state)), on(allActions.toggleSelectEntities, (state, { id }) => allMutators.toggleSelectEntities(id, state)), on(allActions.toggleSelectAllEntities, (state) => allMutators.toggleSelectAllEntities(state)), ...insertIf(allActions.removeEntities, () => on(allActions.removeEntities, (state, { keys }) => {
|
|
632
|
+
const selectedIds = Object.assign({}, state.selectedIds);
|
|
633
|
+
keys.forEach((v) => {
|
|
634
|
+
delete selectedIds[v];
|
|
635
|
+
});
|
|
636
|
+
return Object.assign(Object.assign({}, state), { selectedIds });
|
|
637
|
+
})), ...insertIf(allActions.updateEntities, () => on(allActions.updateEntities, (state, { updates }) => updateSelectedIdsChanged(state, updates))), on(allActions.clearEntitiesSelection, (state) => allMutators.clearEntitiesSelection(state)), ...insertIf(allActions.removeAllEntities, () => on(allActions.removeAllEntities, (state) => allMutators.clearEntitiesSelection(state))), ...insertIf(sortRemote, () => on(allActions.sortEntities, (state) => allMutators.clearEntitiesSelection(state))), ...insertIf(allActions.filterEntities, () => on(allActions.filterEntities, (state) => allMutators.clearEntitiesSelection(state))), ...insertIf(!allActions.loadEntitiesPageSuccess, () => on(allActions.loadEntitiesSuccess, (state) => allMutators.clearEntitiesSelection(state))), ...insertIf(!!allActions.loadEntitiesPageSuccess && paginationCacheType === 'partial', () => on(allActions.loadEntitiesPageSuccess, (state) => allMutators.clearEntitiesSelection(state))));
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
function createSelectEntitiesTraitMutators({ isAllEntitiesSelected, }) {
|
|
641
|
+
function toggleSelectAllEntities(state) {
|
|
642
|
+
const allSelected = isAllEntitiesSelected(state);
|
|
643
|
+
if (allSelected === 'all') {
|
|
644
|
+
return Object.assign(Object.assign({}, state), { selectedIds: {} });
|
|
645
|
+
}
|
|
646
|
+
else {
|
|
647
|
+
return Object.assign(Object.assign({}, state), { selectedIds: toMap(state.ids) });
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
return {
|
|
651
|
+
selectEntities,
|
|
652
|
+
deselectEntities,
|
|
653
|
+
toggleSelectEntities,
|
|
654
|
+
toggleSelectAllEntities,
|
|
655
|
+
clearEntitiesSelection,
|
|
656
|
+
};
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
/**
|
|
660
|
+
* Generates ngrx code to add multi selection to a list
|
|
661
|
+
*
|
|
662
|
+
* @example
|
|
663
|
+
* // The following trait config
|
|
664
|
+
*
|
|
665
|
+
* export interface TestState
|
|
666
|
+
* extends EntityAndStatusState<Todo>,MultipleSelectionState{}
|
|
667
|
+
*
|
|
668
|
+
* const traits = createEntityFeatureFactory(
|
|
669
|
+
* addLoadEntitiesTrait<Todo>(),
|
|
670
|
+
* addSelectEntitiesTrait<Todo>()
|
|
671
|
+
* )({
|
|
672
|
+
* actionsGroupKey: '[Todos]',
|
|
673
|
+
* featureSelector: createFeatureSelector<TestState>>(
|
|
674
|
+
* 'todos',
|
|
675
|
+
* ),
|
|
676
|
+
* });
|
|
677
|
+
* // will generate the following actions and selectors, plus the ones generated by other traits
|
|
678
|
+
* traits.actions.selectTodos({id})
|
|
679
|
+
* traits.actions.deselectTodos({id})
|
|
680
|
+
* traits.actions.toggleSectTodos({id})
|
|
681
|
+
* traits.actions.toggleSelectAllTodos()
|
|
682
|
+
* traits.actions.clearTodosSelection()
|
|
683
|
+
*
|
|
684
|
+
* traits.selectors.isAllTodosSelected()
|
|
685
|
+
* traits.selectors.selectTodosIdsSelectedMap()
|
|
686
|
+
* traits.selectors.selectTodosIdsSelectedList()
|
|
687
|
+
* traits.selectors.selectTodosSelectedMap()
|
|
688
|
+
* traits.selectors.selectTodosSelectedList()
|
|
689
|
+
* traits.selectors.selectTotalSelectedTodos()
|
|
690
|
+
*/
|
|
691
|
+
function addSelectEntitiesTrait() {
|
|
692
|
+
return createTraitFactory({
|
|
693
|
+
key: 'SelectEntities',
|
|
694
|
+
depends: [loadEntitiesTraitKey],
|
|
695
|
+
actions: ({ actionsGroupKey, entitiesName }) => createSelectEntitiesTraitActions(actionsGroupKey, entitiesName),
|
|
696
|
+
selectors: ({ previousSelectors }) => createSelectEntitiesTraitSelectors(previousSelectors),
|
|
697
|
+
initialState: ({ previousInitialState }) => createSelectEntitiesInitialState(previousInitialState),
|
|
698
|
+
mutators: ({ allSelectors }) => createSelectEntitiesTraitMutators(allSelectors),
|
|
699
|
+
reducer: ({ initialState, allActions, allMutators, allConfigs }) => createSelectEntitiesTraitReducer(initialState, allActions, allMutators, allConfigs),
|
|
700
|
+
});
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
function createSelectEntityTraitActions(actionsGroupKey, entityName) {
|
|
704
|
+
return {
|
|
705
|
+
selectEntity: createAction(`${actionsGroupKey} Select ${entityName}`, props()),
|
|
706
|
+
deselectEntity: createAction(`${actionsGroupKey} Deselect ${entityName}`),
|
|
707
|
+
toggleSelectEntity: createAction(`${actionsGroupKey} Toggle Select ${entityName}`, props()),
|
|
708
|
+
};
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
function createSelectEntityTraitSelectors() {
|
|
712
|
+
function selectEntityIdSelected(state) {
|
|
713
|
+
return state.selectedId;
|
|
714
|
+
}
|
|
715
|
+
function selectEntitySelected(state) {
|
|
716
|
+
return (state.selectedId && state.entities[state.selectedId]) || undefined;
|
|
717
|
+
}
|
|
718
|
+
return {
|
|
719
|
+
selectEntityIdSelected,
|
|
720
|
+
selectEntitySelected,
|
|
721
|
+
};
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
function createSelectEntityInitialState(previousInitialState, allConfigs) {
|
|
725
|
+
var _a;
|
|
726
|
+
const selectedId = (_a = allConfigs.singleSelection) === null || _a === void 0 ? void 0 : _a.selectedId;
|
|
727
|
+
return Object.assign(Object.assign({}, previousInitialState), { selectedId });
|
|
728
|
+
}
|
|
729
|
+
function createSelectEntityTraitReducer(initialState, allActions, allMutators, allConfigs) {
|
|
730
|
+
var _a, _b;
|
|
731
|
+
const { adapter } = allConfigs.loadEntities;
|
|
732
|
+
const sortRemote = (_a = allConfigs.sort) === null || _a === void 0 ? void 0 : _a.remote;
|
|
733
|
+
const paginationCacheType = (_b = allConfigs.pagination) === null || _b === void 0 ? void 0 : _b.cacheType;
|
|
734
|
+
return createReducer(initialState, on(allActions.selectEntity, (state, { id }) => allMutators.selectEntity(id, state)), on(allActions.deselectEntity, (state) => allMutators.deselectEntity(state)), on(allActions.toggleSelectEntity, (state, { id }) => allMutators.toggleSelectEntity(id, state)), ...insertIf(allActions.removeAllEntities, () => on(allActions.removeAllEntities, (state) => allMutators.deselectEntity(state))), ...insertIf(sortRemote, () => on(allActions.sortEntities, (state) => allMutators.deselectEntity(state))), ...insertIf(allActions.filterEntities, () => on(allActions.filterEntities, (state) => allMutators.deselectEntity(state))), ...insertIf(!allActions.loadEntitiesPageSuccess, () => on(allActions.loadEntitiesSuccess, (state) => allMutators.deselectEntity(state))), ...insertIf(!!allActions.loadEntitiesPageSuccess && paginationCacheType === 'partial', () => on(allActions.loadEntitiesPageSuccess, (state) => allMutators.deselectEntity(state))), ...insertIf(allActions.removeEntities, () => on(allActions.removeEntities, (state, { keys }) => {
|
|
735
|
+
const shouldDeselect = keys.some((v) => v === state.selectedId);
|
|
736
|
+
return shouldDeselect
|
|
737
|
+
? Object.assign(Object.assign({}, state), { selectedId: undefined }) : state;
|
|
738
|
+
})), ...insertIf(allActions.updateEntities, () => on(allActions.updateEntities, (state, { updates }) => {
|
|
739
|
+
const change = updates.find((updated) => {
|
|
740
|
+
const id = adapter.selectId(updated.changes);
|
|
741
|
+
return id && id !== updated.id && state.selectedId === updated.id;
|
|
742
|
+
});
|
|
743
|
+
return change
|
|
744
|
+
? Object.assign(Object.assign({}, state), { selectedId: adapter.selectId(change.changes) }) : state;
|
|
745
|
+
})));
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
function createSelectEntityTraitMutators() {
|
|
749
|
+
function selectEntity(id, state) {
|
|
750
|
+
return Object.assign(Object.assign({}, state), { selectedId: id });
|
|
751
|
+
}
|
|
752
|
+
function deselectEntity(state) {
|
|
753
|
+
return Object.assign(Object.assign({}, state), { selectedId: undefined });
|
|
754
|
+
}
|
|
755
|
+
function toggleSelectEntity(id, state) {
|
|
756
|
+
return Object.assign(Object.assign({}, state), { selectedId: state.selectedId === id ? undefined : id });
|
|
757
|
+
}
|
|
758
|
+
return {
|
|
759
|
+
selectEntity,
|
|
760
|
+
deselectEntity,
|
|
761
|
+
toggleSelectEntity,
|
|
762
|
+
};
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
/**
|
|
766
|
+
* Generates ngrx code to add single selection to a list
|
|
767
|
+
* @param config
|
|
768
|
+
* @param config.selectedId - Default selected id
|
|
769
|
+
*
|
|
770
|
+
* @example
|
|
771
|
+
* // The following trait config
|
|
772
|
+
*
|
|
773
|
+
* export interface TestState
|
|
774
|
+
* extends EntityAndStatusState<Todo>,SelectEntityState{}
|
|
775
|
+
*
|
|
776
|
+
* const traits = createEntityFeatureFactory(
|
|
777
|
+
* addLoadEntitiesTrait<Todo>(),
|
|
778
|
+
* addSelectEntityTrait<Todo>()
|
|
779
|
+
* )({
|
|
780
|
+
* actionsGroupKey: '[Todos]',
|
|
781
|
+
* featureSelector: createFeatureSelector<TestState>>(
|
|
782
|
+
* 'todos',
|
|
783
|
+
* ),
|
|
784
|
+
* });
|
|
785
|
+
* // will generate the following actions and selectors, plus the ones generated by other traits
|
|
786
|
+
* traits.actions.selectTodo({id})
|
|
787
|
+
* traits.actions.deselectTodo()
|
|
788
|
+
* traits.actions.toggleSelectTodo({id})
|
|
789
|
+
*
|
|
790
|
+
* traits.selectors.selectTodoIdSelected()
|
|
791
|
+
* traits.selectors.selectTodoSelected()
|
|
792
|
+
*/
|
|
793
|
+
function addSelectEntityTrait(config) {
|
|
794
|
+
return createTraitFactory({
|
|
795
|
+
key: 'singleSelection',
|
|
796
|
+
depends: [loadEntitiesTraitKey],
|
|
797
|
+
config,
|
|
798
|
+
actions: ({ actionsGroupKey, entityName }) => createSelectEntityTraitActions(actionsGroupKey, entityName),
|
|
799
|
+
selectors: () => createSelectEntityTraitSelectors(),
|
|
800
|
+
mutators: () => createSelectEntityTraitMutators(),
|
|
801
|
+
initialState: ({ previousInitialState, allConfigs, }) => createSelectEntityInitialState(previousInitialState, allConfigs),
|
|
802
|
+
reducer: ({ initialState, allActions, allMutators, allConfigs }) => createSelectEntityTraitReducer(initialState, allActions, allMutators, allConfigs),
|
|
803
|
+
});
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
const selectEntityTraitKey = 'singleSelection';
|
|
807
|
+
|
|
808
|
+
var ChangeType;
|
|
809
|
+
(function (ChangeType) {
|
|
810
|
+
ChangeType["CREATED"] = "c";
|
|
811
|
+
ChangeType["UPDATED"] = "u";
|
|
812
|
+
ChangeType["DELETED"] = "d";
|
|
813
|
+
})(ChangeType || (ChangeType = {}));
|
|
814
|
+
const crudEntitiesTraitKey = 'crud';
|
|
815
|
+
|
|
816
|
+
function createCrudTraitActions(actionsGroupKey, entitiesName) {
|
|
817
|
+
return {
|
|
818
|
+
addEntities: createAction(`${actionsGroupKey} Add ${entitiesName}`, (...entities) => ({
|
|
819
|
+
entities,
|
|
820
|
+
})),
|
|
821
|
+
removeEntities: createAction(`${actionsGroupKey} Remove ${entitiesName}`, (...keys) => ({
|
|
822
|
+
keys,
|
|
823
|
+
})),
|
|
824
|
+
updateEntities: createAction(`${actionsGroupKey} Update ${entitiesName}`, (...updates) => ({
|
|
825
|
+
updates,
|
|
826
|
+
})),
|
|
827
|
+
upsertEntities: createAction(`${actionsGroupKey} Upsert ${entitiesName}`, (...entities) => ({
|
|
828
|
+
entities,
|
|
829
|
+
})),
|
|
830
|
+
removeAllEntities: createAction(`${actionsGroupKey} Remove All ${entitiesName}`, (predicate) => ({ predicate })),
|
|
831
|
+
clearEntitiesChanges: createAction(`${actionsGroupKey} Clear ${entitiesName} Changes`),
|
|
832
|
+
};
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
function createCrudTraitSelectors(previousSelectors) {
|
|
836
|
+
function selectChanges(state) {
|
|
837
|
+
return state.changes;
|
|
838
|
+
}
|
|
839
|
+
function selectFilteredChanges(state) {
|
|
840
|
+
const cache = {};
|
|
841
|
+
return state.changes.reduce((acc, value) => {
|
|
842
|
+
const changes = cache[value.id];
|
|
843
|
+
if (!changes) {
|
|
844
|
+
cache[value.id] = [value.changeType];
|
|
845
|
+
acc.push(value);
|
|
846
|
+
return acc;
|
|
847
|
+
}
|
|
848
|
+
if (value.changeType === ChangeType.UPDATED) {
|
|
849
|
+
return acc;
|
|
850
|
+
}
|
|
851
|
+
if (value.changeType === ChangeType.DELETED &&
|
|
852
|
+
changes.includes(ChangeType.CREATED)) {
|
|
853
|
+
delete cache[value.id];
|
|
854
|
+
return acc.filter((v) => v.id !== value.id);
|
|
855
|
+
}
|
|
856
|
+
if (value.changeType === ChangeType.DELETED) {
|
|
857
|
+
delete cache[value.id];
|
|
858
|
+
const newAcc = acc.filter((v) => v.id !== value.id);
|
|
859
|
+
newAcc.push(value);
|
|
860
|
+
return newAcc;
|
|
861
|
+
}
|
|
862
|
+
return acc;
|
|
863
|
+
}, []);
|
|
864
|
+
}
|
|
865
|
+
const { selectEntitiesMap } = previousSelectors;
|
|
866
|
+
const selectEntitiesChangesList = createSelector((state) => selectEntitiesMap(state), selectChanges, (entities, changed, { type }) => {
|
|
867
|
+
if (type)
|
|
868
|
+
return changed
|
|
869
|
+
.filter((c) => c.changeType === type)
|
|
870
|
+
.map((change) => {
|
|
871
|
+
var _a;
|
|
872
|
+
return ({
|
|
873
|
+
changeType: change.changeType,
|
|
874
|
+
entity: (_a = entities[change.id]) !== null && _a !== void 0 ? _a : {
|
|
875
|
+
id: change.id,
|
|
876
|
+
},
|
|
877
|
+
});
|
|
878
|
+
});
|
|
879
|
+
const map = changed.map((change) => {
|
|
880
|
+
var _a;
|
|
881
|
+
return ({
|
|
882
|
+
changeType: change.changeType,
|
|
883
|
+
entity: (_a = entities[change.id]) !== null && _a !== void 0 ? _a : {
|
|
884
|
+
id: change.id,
|
|
885
|
+
},
|
|
886
|
+
});
|
|
887
|
+
});
|
|
888
|
+
return map;
|
|
889
|
+
});
|
|
890
|
+
const selectFilteredEntitiesChangesList = createSelector(selectFilteredChanges, (state) => selectEntitiesMap(state), (changes, entities) => changes.map((c) => {
|
|
891
|
+
var _a;
|
|
892
|
+
return {
|
|
893
|
+
entity: (_a = entities[c.id]) !== null && _a !== void 0 ? _a : { id: c.id },
|
|
894
|
+
changeType: c.changeType,
|
|
895
|
+
};
|
|
896
|
+
}));
|
|
897
|
+
return {
|
|
898
|
+
selectEntitiesChangesList,
|
|
899
|
+
selectFilteredEntitiesChangesList,
|
|
900
|
+
};
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
function createCrudInitialState(previousInitialState) {
|
|
904
|
+
return Object.assign(Object.assign({}, previousInitialState), { changes: [] });
|
|
905
|
+
}
|
|
906
|
+
function createCrudTraitReducer(initialState, allActions, allMutators, allConfigs) {
|
|
907
|
+
var _a, _b, _c;
|
|
908
|
+
const sortRemote = (_a = allConfigs.sort) === null || _a === void 0 ? void 0 : _a.remote;
|
|
909
|
+
const filterRemote = allConfigs.filter && !((_b = allConfigs.filter) === null || _b === void 0 ? void 0 : _b.filterFn);
|
|
910
|
+
const paginationCacheType = (_c = allConfigs.pagination) === null || _c === void 0 ? void 0 : _c.cacheType;
|
|
911
|
+
return createReducer(initialState, on(allActions.addEntities, (state, { entities }) => allMutators.addEntities(entities, state)), on(allActions.updateEntities, (state, { updates }) => allMutators.updateEntities(updates, state)), on(allActions.upsertEntities, (state, { entities }) => allMutators.upsertEntities(entities, state)), on(allActions.removeEntities, (state, { keys }) => allMutators.removeEntities(keys, state)), on(allActions.removeAllEntities, (state, { predicate }) => predicate
|
|
912
|
+
? allMutators.removeEntities(predicate, state)
|
|
913
|
+
: allMutators.removeAllEntities(state)), on(allActions.clearEntitiesChanges, (state) => allMutators.clearEntitiesChanges(state)), ...insertIf(sortRemote, () => on(allActions.sortEntities, (state) => allMutators.clearEntitiesChanges(state))), ...insertIf(filterRemote, () => on(allActions.filterEntities, (state) => allMutators.clearEntitiesChanges(state))), ...insertIf(!allActions.loadEntitiesPageSuccess, () => on(allActions.loadEntitiesSuccess, (state) => allMutators.clearEntitiesChanges(state))), ...insertIf(!!allActions.loadEntitiesPageSuccess && paginationCacheType === 'partial', () => on(allActions.loadEntitiesPageSuccess, (state) => allMutators.clearEntitiesChanges(state))));
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
function createCrudTraitMutators(allConfigs) {
|
|
917
|
+
const { storeChanges } = allConfigs.crud || {};
|
|
918
|
+
const adapter = allConfigs.loadEntities.adapter;
|
|
919
|
+
function generateChangeEntry(entity, changeType, customId) {
|
|
920
|
+
return {
|
|
921
|
+
id: customId !== null && customId !== void 0 ? customId : adapter.selectId(entity),
|
|
922
|
+
changeType,
|
|
923
|
+
entityChanges: (storeChanges && entity) || undefined,
|
|
924
|
+
};
|
|
925
|
+
}
|
|
926
|
+
function addEntities(entities, state, addFirst = false) {
|
|
927
|
+
const changes = [
|
|
928
|
+
...state.changes,
|
|
929
|
+
...entities.map((entity) => generateChangeEntry(entity, ChangeType.CREATED)),
|
|
930
|
+
];
|
|
931
|
+
if (!addFirst)
|
|
932
|
+
return adapter.addMany(entities, Object.assign(Object.assign({}, state), { changes }));
|
|
933
|
+
const newIds = entities.map((e) => adapter.selectId(e));
|
|
934
|
+
const newEntities = Object.assign({}, state.entities);
|
|
935
|
+
entities.forEach((e) => {
|
|
936
|
+
const id = adapter.selectId(e);
|
|
937
|
+
newEntities[id] = e;
|
|
938
|
+
});
|
|
939
|
+
return Object.assign(Object.assign({}, state), { ids: [...newIds, ...state.ids], entities: newEntities, changes });
|
|
940
|
+
}
|
|
941
|
+
function upsertEntities(entities, state) {
|
|
942
|
+
const oldChanges = [...state.changes];
|
|
943
|
+
const existingIds = adapter.getSelectors().selectIds(state);
|
|
944
|
+
const [additions, updates] = entities.reduce(([a, u], entity) => existingIds.indexOf(adapter.selectId(entity)) !== -1
|
|
945
|
+
? [a, [...u, entity]]
|
|
946
|
+
: [[...a, entity], u], [new Array(), new Array()]);
|
|
947
|
+
return adapter.upsertMany(entities, Object.assign(Object.assign({}, state), { changes: [
|
|
948
|
+
...oldChanges,
|
|
949
|
+
...additions.map((entity) => generateChangeEntry(entity, ChangeType.CREATED)),
|
|
950
|
+
...updates.map((entity) => generateChangeEntry(entity, ChangeType.UPDATED)),
|
|
951
|
+
] }));
|
|
952
|
+
}
|
|
953
|
+
function removeEntities(keysOrPredicate, state) {
|
|
954
|
+
if (typeof keysOrPredicate === 'function') {
|
|
955
|
+
return adapter.removeMany(keysOrPredicate, Object.assign(Object.assign({}, state), { changes: [
|
|
956
|
+
...state.changes,
|
|
957
|
+
...state.ids.map((id) => ({
|
|
958
|
+
id,
|
|
959
|
+
changeType: ChangeType.DELETED,
|
|
960
|
+
})),
|
|
961
|
+
] }));
|
|
962
|
+
}
|
|
963
|
+
return adapter.removeMany(keysOrPredicate, Object.assign(Object.assign({}, state), { changes: [
|
|
964
|
+
...state.changes,
|
|
965
|
+
...keysOrPredicate.map((key) => ({
|
|
966
|
+
id: key,
|
|
967
|
+
changeType: ChangeType.DELETED,
|
|
968
|
+
})),
|
|
969
|
+
] }));
|
|
970
|
+
}
|
|
971
|
+
function removeAllEntities(state) {
|
|
972
|
+
return adapter.removeAll(Object.assign(Object.assign({}, state), { changes: [
|
|
973
|
+
...state.changes,
|
|
974
|
+
...state.ids.map((id) => ({
|
|
975
|
+
id,
|
|
976
|
+
changeType: ChangeType.DELETED,
|
|
977
|
+
})),
|
|
978
|
+
] }));
|
|
979
|
+
}
|
|
980
|
+
function clearEntitiesChanges(state) {
|
|
981
|
+
return Object.assign(Object.assign({}, state), { changes: [] });
|
|
982
|
+
}
|
|
983
|
+
function updateEntities(updates, state) {
|
|
984
|
+
const oldChanges = [...state.changes];
|
|
985
|
+
updates.forEach((updated) => {
|
|
986
|
+
const id = adapter.selectId(updated.changes);
|
|
987
|
+
if (id && id !== updated.id) {
|
|
988
|
+
// if the id changes update the id of pold changes
|
|
989
|
+
const index = oldChanges.findIndex((v) => v.id === updated.id);
|
|
990
|
+
const oldChange = oldChanges[index];
|
|
991
|
+
oldChanges[index] = Object.assign(Object.assign({}, oldChange), { id });
|
|
992
|
+
}
|
|
993
|
+
});
|
|
994
|
+
return adapter.updateMany(updates, Object.assign(Object.assign({}, state), { changes: [
|
|
995
|
+
...oldChanges,
|
|
996
|
+
...updates.map((updated) => {
|
|
997
|
+
var _a;
|
|
998
|
+
return ({
|
|
999
|
+
id: (_a = adapter.selectId(updated.changes)) !== null && _a !== void 0 ? _a : updated.id,
|
|
1000
|
+
changeType: ChangeType.UPDATED,
|
|
1001
|
+
entityChanges: (storeChanges && updated.changes) || undefined,
|
|
1002
|
+
});
|
|
1003
|
+
}),
|
|
1004
|
+
] }));
|
|
1005
|
+
}
|
|
1006
|
+
return {
|
|
1007
|
+
addEntities,
|
|
1008
|
+
removeEntities,
|
|
1009
|
+
updateEntities,
|
|
1010
|
+
removeAllEntities,
|
|
1011
|
+
clearEntitiesChanges,
|
|
1012
|
+
upsertEntities,
|
|
1013
|
+
};
|
|
1014
|
+
}
|
|
1015
|
+
|
|
1016
|
+
/**
|
|
1017
|
+
* Generates ngrx code to add, remove update, upsert entities on a list, it also
|
|
1018
|
+
* tracks the changes made, helpful for implementing batch updates. The `storeChanges` (false by default),
|
|
1019
|
+
* will store for add and update the changed entity props in the property `entityChanges` of the `Change` object.
|
|
1020
|
+
* @param config
|
|
1021
|
+
* @param config.storeChanges - Will store the changes made, default fals
|
|
1022
|
+
*
|
|
1023
|
+
* @example
|
|
1024
|
+
* // The following trait config
|
|
1025
|
+
*
|
|
1026
|
+
* export interface TestState
|
|
1027
|
+
* extends EntityAndStatusState<Todo>, CrudState<Todo>{}
|
|
1028
|
+
*
|
|
1029
|
+
* const traits = createEntityFeatureFactory(
|
|
1030
|
+
* addLoadEntitiesTrait<Todo>(),
|
|
1031
|
+
* addCrudEntitiesTrait<Todo>()
|
|
1032
|
+
* )({
|
|
1033
|
+
* actionsGroupKey: '[Todos]',
|
|
1034
|
+
* featureSelector: createFeatureSelector<TestState>>(
|
|
1035
|
+
* 'todos',
|
|
1036
|
+
* ),
|
|
1037
|
+
* });
|
|
1038
|
+
* // will generate the following actions and selectors, plus the ones generated by other traits
|
|
1039
|
+
* traits.actions.addTodos(entity1,entity2...)
|
|
1040
|
+
* traits.actions.updateTodos({id: id1, changes:{prop1}},{id: id2, changes:{prop2}} ...)
|
|
1041
|
+
* traits.actions.upsertTodos(entity1,entity2...)
|
|
1042
|
+
* traits.actions.removeAllTodos()
|
|
1043
|
+
* traits.actions.clearTodosChanges()
|
|
1044
|
+
*
|
|
1045
|
+
* traits.selectors.selectTodosChangesList()
|
|
1046
|
+
* traits.selectors.selectFilteredTodosChangesList()
|
|
1047
|
+
* traits.selectors.selectAllFilteredChanges()
|
|
1048
|
+
*/
|
|
1049
|
+
function addCrudEntitiesTrait({ storeChanges = false, } = {}) {
|
|
1050
|
+
return createTraitFactory({
|
|
1051
|
+
key: crudEntitiesTraitKey,
|
|
1052
|
+
depends: [loadEntitiesTraitKey],
|
|
1053
|
+
config: { storeChanges },
|
|
1054
|
+
actions: ({ actionsGroupKey, entitiesName }) => createCrudTraitActions(actionsGroupKey, entitiesName),
|
|
1055
|
+
selectors: ({ previousSelectors }) => createCrudTraitSelectors(previousSelectors),
|
|
1056
|
+
mutators: ({ allConfigs }) => createCrudTraitMutators(allConfigs),
|
|
1057
|
+
initialState: ({ previousInitialState }) => createCrudInitialState(previousInitialState),
|
|
1058
|
+
reducer: ({ initialState, allActions, allMutators, allConfigs }) => createCrudTraitReducer(initialState, allActions, allMutators, allConfigs),
|
|
1059
|
+
});
|
|
1060
|
+
}
|
|
1061
|
+
|
|
1062
|
+
const sortTraitKey = 'sort';
|
|
1063
|
+
|
|
1064
|
+
const MAX_SAFE_INTEGER = 9007199254740991;
|
|
1065
|
+
function _isNumberValue(value) {
|
|
1066
|
+
// parseFloat(value) handles most of the cases we're interested in (it treats null, empty string,
|
|
1067
|
+
// and other non-number values as NaN, where Number just uses 0) but it considers the string
|
|
1068
|
+
// '123hello' to be a valid number. Therefore we also check if Number(value) is NaN.
|
|
1069
|
+
return !isNaN(parseFloat(value)) && !isNaN(Number(value));
|
|
1070
|
+
}
|
|
1071
|
+
function sortingDataAccessor(data, sortHeaderId) {
|
|
1072
|
+
const value = data[sortHeaderId];
|
|
1073
|
+
if (_isNumberValue(value)) {
|
|
1074
|
+
const numberValue = Number(value);
|
|
1075
|
+
// Numbers beyond `MAX_SAFE_INTEGER` can't be compared reliably so we
|
|
1076
|
+
// leave them as strings. For more info: https://goo.gl/y5vbSg
|
|
1077
|
+
return numberValue < MAX_SAFE_INTEGER ? numberValue : value;
|
|
1078
|
+
}
|
|
1079
|
+
return value;
|
|
1080
|
+
}
|
|
1081
|
+
/**
|
|
1082
|
+
* Gets a sorted copy of the data array based on the state of the Sort.
|
|
1083
|
+
* @param data The array of data that should be sorted.
|
|
1084
|
+
* @param sort The connected MatSort that holds the current sort state.
|
|
1085
|
+
*/
|
|
1086
|
+
function sortData(data, sort) {
|
|
1087
|
+
const active = sort.active;
|
|
1088
|
+
const direction = sort.direction;
|
|
1089
|
+
if (!active || direction === '') {
|
|
1090
|
+
return data;
|
|
1091
|
+
}
|
|
1092
|
+
return data.sort((a, b) => {
|
|
1093
|
+
const valueA = sortingDataAccessor(a, active);
|
|
1094
|
+
const valueB = sortingDataAccessor(b, active);
|
|
1095
|
+
// If both valueA and valueB exist (truthy), then compare the two. Otherwise, check if
|
|
1096
|
+
// one value exists while the other doesn't. In this case, existing value should come last.
|
|
1097
|
+
// This avoids inconsistent results when comparing values to undefined/null.
|
|
1098
|
+
// If neither value exists, return 0 (equal).
|
|
1099
|
+
let comparatorResult = 0;
|
|
1100
|
+
if (valueA != null && valueB != null) {
|
|
1101
|
+
// Check if one value is greater than the other; if equal, comparatorResult should remain 0.
|
|
1102
|
+
if (typeof valueA === 'string' || typeof valueB === 'string') {
|
|
1103
|
+
// if either values are a string, then force both to be strings before localCompare
|
|
1104
|
+
comparatorResult = valueA.toString().localeCompare(valueB.toString());
|
|
1105
|
+
}
|
|
1106
|
+
else {
|
|
1107
|
+
if (valueA > valueB) {
|
|
1108
|
+
comparatorResult = 1;
|
|
1109
|
+
}
|
|
1110
|
+
else if (valueA < valueB) {
|
|
1111
|
+
comparatorResult = -1;
|
|
1112
|
+
}
|
|
1113
|
+
}
|
|
1114
|
+
}
|
|
1115
|
+
else if (valueA != null) {
|
|
1116
|
+
comparatorResult = 1;
|
|
1117
|
+
}
|
|
1118
|
+
else if (valueB != null) {
|
|
1119
|
+
comparatorResult = -1;
|
|
1120
|
+
}
|
|
1121
|
+
return comparatorResult * (direction === 'asc' ? 1 : -1);
|
|
1122
|
+
});
|
|
1123
|
+
}
|
|
1124
|
+
|
|
1125
|
+
function createSortTraitMutators({ selectEntitiesList }, allConfigs) {
|
|
1126
|
+
function sortEntities({ active, direction }, state) {
|
|
1127
|
+
const { adapter } = allConfigs.loadEntities;
|
|
1128
|
+
const entities = selectEntitiesList(state);
|
|
1129
|
+
const sortedIds = sortData(entities, { active, direction }).map((v) => adapter.selectId(v));
|
|
1130
|
+
return Object.assign(Object.assign({}, state), { ids: sortedIds, sort: Object.assign(Object.assign({}, state.sort), { current: { active, direction } }) });
|
|
1131
|
+
}
|
|
1132
|
+
return {
|
|
1133
|
+
sortEntities,
|
|
1134
|
+
};
|
|
1135
|
+
}
|
|
1136
|
+
|
|
1137
|
+
function createSortInitialState(previousInitialState, allConfigs) {
|
|
1138
|
+
const { defaultSort } = allConfigs.sort;
|
|
1139
|
+
return Object.assign(Object.assign({}, previousInitialState), { sort: {
|
|
1140
|
+
current: defaultSort,
|
|
1141
|
+
default: defaultSort,
|
|
1142
|
+
} });
|
|
1143
|
+
}
|
|
1144
|
+
function createSortTraitReducer(initialState, allActions, allMutators, allConfigs) {
|
|
1145
|
+
const { remote } = allConfigs.sort;
|
|
1146
|
+
return createReducer(initialState, on(allActions.sortEntities, (state, { active, direction }) => !remote
|
|
1147
|
+
? allMutators.sortEntities({ active, direction }, state)
|
|
1148
|
+
: Object.assign(Object.assign({}, state), { sort: Object.assign(Object.assign({}, state.sort), { current: { active, direction } }) })), on(allActions.resetEntitiesSort, (state) => {
|
|
1149
|
+
var _a, _b, _c;
|
|
1150
|
+
return ((_a = state.sort) === null || _a === void 0 ? void 0 : _a.default)
|
|
1151
|
+
? !remote
|
|
1152
|
+
? allMutators.sortEntities((_b = state.sort) === null || _b === void 0 ? void 0 : _b.default, state)
|
|
1153
|
+
: Object.assign(Object.assign({}, state), { sort: Object.assign(Object.assign({}, state.sort), { current: (_c = state.sort) === null || _c === void 0 ? void 0 : _c.default }) })
|
|
1154
|
+
: state;
|
|
1155
|
+
}));
|
|
1156
|
+
}
|
|
1157
|
+
|
|
1158
|
+
function createSortTraitSelectors() {
|
|
1159
|
+
function selectEntitiesSort(state) {
|
|
1160
|
+
var _a;
|
|
1161
|
+
return (_a = state.sort) === null || _a === void 0 ? void 0 : _a.current;
|
|
1162
|
+
}
|
|
1163
|
+
return {
|
|
1164
|
+
selectEntitiesSort,
|
|
1165
|
+
};
|
|
1166
|
+
}
|
|
1167
|
+
|
|
1168
|
+
function createSortTraitEffect(allActions, allConfigs) {
|
|
1169
|
+
const { remote } = allConfigs.sort;
|
|
1170
|
+
class SortEffect extends TraitEffect {
|
|
1171
|
+
constructor() {
|
|
1172
|
+
super(...arguments);
|
|
1173
|
+
this.remoteSort$ = createEffect(() => {
|
|
1174
|
+
return this.actions$.pipe(ofType(allActions.sortEntities, allActions.resetEntitiesSort), concatMap(() => allActions.loadEntitiesFirstPage
|
|
1175
|
+
? [
|
|
1176
|
+
allActions.clearEntitiesPagesCache(),
|
|
1177
|
+
allActions.loadEntitiesFirstPage(),
|
|
1178
|
+
]
|
|
1179
|
+
: [allActions.loadEntities()]));
|
|
1180
|
+
});
|
|
1181
|
+
}
|
|
1182
|
+
}
|
|
1183
|
+
SortEffect.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.1.2", ngImport: i0, type: SortEffect, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
|
|
1184
|
+
SortEffect.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "12.1.2", ngImport: i0, type: SortEffect });
|
|
1185
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.1.2", ngImport: i0, type: SortEffect, decorators: [{
|
|
1186
|
+
type: Injectable
|
|
1187
|
+
}] });
|
|
1188
|
+
return remote ? [SortEffect] : [];
|
|
1189
|
+
}
|
|
1190
|
+
|
|
1191
|
+
function createSortTraitActions(actionsGroupKey, entitiesName) {
|
|
1192
|
+
return {
|
|
1193
|
+
sortEntities: createAction(`${actionsGroupKey} Sort ${entitiesName}`, props()),
|
|
1194
|
+
resetEntitiesSort: createAction(`${actionsGroupKey} Reset ${entitiesName} Sort`),
|
|
1195
|
+
};
|
|
1196
|
+
}
|
|
1197
|
+
|
|
1198
|
+
/**
|
|
1199
|
+
* Generates ngrx code to sort locally or remotely a list of entities
|
|
1200
|
+
* @param config
|
|
1201
|
+
* @param config.defaultSort - Required, Default entity prop for the sort
|
|
1202
|
+
* @param config.remote - Optional field, default to false, when true disables local
|
|
1203
|
+
* sorting and every sort action call will now trigger a loadEntities action and the backend
|
|
1204
|
+
* should sort the data, use selectSort in the effect that call backend to get the requested sort,
|
|
1205
|
+
* when false all sorting is done in memory when the sort action is fired
|
|
1206
|
+
*
|
|
1207
|
+
* @example
|
|
1208
|
+
* // The following trait config
|
|
1209
|
+
* export interface TestState
|
|
1210
|
+
* extends EntityAndStatusState<Todo>, SortState<Todo>{}
|
|
1211
|
+
*
|
|
1212
|
+
* const traits = createEntityFeatureFactory(
|
|
1213
|
+
* addLoadEntitiesTrait<Todo>(),
|
|
1214
|
+
* addSortEntitiesTrait<Todo>({
|
|
1215
|
+
* defaultSort: {active:'id', direction:'asc'}
|
|
1216
|
+
* })
|
|
1217
|
+
* )({
|
|
1218
|
+
* actionsGroupKey: '[Todos]',
|
|
1219
|
+
* featureSelector: createFeatureSelector<TestState>>(
|
|
1220
|
+
* 'todos',
|
|
1221
|
+
* ),
|
|
1222
|
+
* });
|
|
1223
|
+
* // will generate the following actions and selectors, plus the ones generated by other traits
|
|
1224
|
+
* traits.actions.sortTodos({active:'id', direction:'desc'})
|
|
1225
|
+
* traits.actions.resetTodosSort()
|
|
1226
|
+
*
|
|
1227
|
+
* traits.selectors.selectTodosSort()
|
|
1228
|
+
*/
|
|
1229
|
+
function addSortEntitiesTrait({ remote = false, defaultSort, }) {
|
|
1230
|
+
return createTraitFactory({
|
|
1231
|
+
key: sortTraitKey,
|
|
1232
|
+
depends: [loadEntitiesTraitKey],
|
|
1233
|
+
config: { remote, defaultSort },
|
|
1234
|
+
actions: ({ actionsGroupKey, entitiesName }) => createSortTraitActions(actionsGroupKey, entitiesName),
|
|
1235
|
+
selectors: () => createSortTraitSelectors(),
|
|
1236
|
+
mutators: ({ allSelectors, allConfigs }) => createSortTraitMutators(allSelectors, allConfigs),
|
|
1237
|
+
initialState: ({ previousInitialState, allConfigs, }) => createSortInitialState(previousInitialState, allConfigs),
|
|
1238
|
+
reducer: ({ initialState, allActions, allMutators, allConfigs }) => createSortTraitReducer(initialState, allActions, allMutators, allConfigs),
|
|
1239
|
+
effects: ({ allActions, allConfigs }) => createSortTraitEffect(allActions, allConfigs),
|
|
1240
|
+
});
|
|
1241
|
+
}
|
|
1242
|
+
|
|
1243
|
+
/**
|
|
1244
|
+
* Generates the ngrx code needed to reset the current state to the initial state.
|
|
1245
|
+
* @param traitConfig - Config object fot the trait factory
|
|
1246
|
+
* @param traitConfig.resetOn - set an extra action which will also trigger a reset state,
|
|
1247
|
+
* useful if you want to create an action that reset several features states
|
|
1248
|
+
*
|
|
1249
|
+
* @example
|
|
1250
|
+
* // The following trait config
|
|
1251
|
+
*
|
|
1252
|
+
* export interface TestState
|
|
1253
|
+
* extends EntityAndStatusState<Todo>,FilterState<TodoFilter>{}
|
|
1254
|
+
*
|
|
1255
|
+
* const traits = createEntityFeatureFactory(
|
|
1256
|
+
* addLoadEntitiesTrait<Todo>(),
|
|
1257
|
+
* addResetEntitiesStateTrait()
|
|
1258
|
+
* )({
|
|
1259
|
+
* actionsGroupKey: '[Todos]',
|
|
1260
|
+
* featureSelector: createFeatureSelector<TestState>>(
|
|
1261
|
+
* 'todos',
|
|
1262
|
+
* ),
|
|
1263
|
+
* });
|
|
1264
|
+
* // will generate the following actions, plus the ones generated by other traits
|
|
1265
|
+
* traits.actions.resetTodosState()
|
|
1266
|
+
*/
|
|
1267
|
+
function addResetEntitiesStateTrait(traitConfig = {}) {
|
|
1268
|
+
return createTraitFactory({
|
|
1269
|
+
key: 'reset',
|
|
1270
|
+
config: traitConfig,
|
|
1271
|
+
actions: ({ actionsGroupKey, entitiesName, }) => ({
|
|
1272
|
+
resetEntitiesState: createAction(`${actionsGroupKey} Reset ${entitiesName} State`),
|
|
1273
|
+
}),
|
|
1274
|
+
reducer: ({ allActions, initialState }) => createReducer(initialState, on(allActions.resetEntitiesState, () => initialState)),
|
|
1275
|
+
effects: ({ allActions }) => {
|
|
1276
|
+
var _a;
|
|
1277
|
+
class ResetEffect extends TraitEffect {
|
|
1278
|
+
//TODO: not sure why Im forced to override this constructor
|
|
1279
|
+
// or test wont pass, strangely doesnt happen in other files
|
|
1280
|
+
// with similar case like pagination.effects.ts
|
|
1281
|
+
constructor(actions$, store) {
|
|
1282
|
+
var _a;
|
|
1283
|
+
super(actions$, store);
|
|
1284
|
+
this.externalReset$ = ((_a = traitConfig === null || traitConfig === void 0 ? void 0 : traitConfig.resetOn) === null || _a === void 0 ? void 0 : _a.length) &&
|
|
1285
|
+
createEffect(() => {
|
|
1286
|
+
return this.actions$.pipe(ofType(...traitConfig === null || traitConfig === void 0 ? void 0 : traitConfig.resetOn), mapTo(allActions.resetEntitiesState()));
|
|
1287
|
+
});
|
|
1288
|
+
}
|
|
1289
|
+
}
|
|
1290
|
+
ResetEffect.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.1.2", ngImport: i0, type: ResetEffect, deps: [{ token: i1.Actions }, { token: i2.Store }], target: i0.ɵɵFactoryTarget.Injectable });
|
|
1291
|
+
ResetEffect.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "12.1.2", ngImport: i0, type: ResetEffect });
|
|
1292
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.1.2", ngImport: i0, type: ResetEffect, decorators: [{
|
|
1293
|
+
type: Injectable
|
|
1294
|
+
}], ctorParameters: function () { return [{ type: i1.Actions }, { type: i2.Store }]; } });
|
|
1295
|
+
return ((_a = traitConfig === null || traitConfig === void 0 ? void 0 : traitConfig.resetOn) === null || _a === void 0 ? void 0 : _a.length) ? [ResetEffect] : [];
|
|
1296
|
+
},
|
|
1297
|
+
});
|
|
1298
|
+
}
|
|
1299
|
+
|
|
1300
|
+
/**
|
|
1301
|
+
* Generates the typical ngrx code need to make a async action with
|
|
1302
|
+
* a request, success and failure actions, plus a status property to track its progress
|
|
1303
|
+
* and selectors to query the status.
|
|
1304
|
+
*
|
|
1305
|
+
* @param options - Config object for the trait factory
|
|
1306
|
+
* @param options.name - Name of the main request action, should be in camel case
|
|
1307
|
+
* @param options.actionProps - Optional param for the main request action, use the props()
|
|
1308
|
+
* function for its value, if not present action will have no params,
|
|
1309
|
+
* @param options.actionSuccessProps - Optional param for the request success action,
|
|
1310
|
+
* use the props() function for its value, if not present action success will have no params
|
|
1311
|
+
* @param options.actionFailProps - Optional param for the request fail action,
|
|
1312
|
+
* use the props() function for its value, if not present action fail will have no params
|
|
1313
|
+
* @returns the trait factory
|
|
1314
|
+
*
|
|
1315
|
+
* @example
|
|
1316
|
+
* // The following trait config
|
|
1317
|
+
* const traits = createEntityFeatureFactory(
|
|
1318
|
+
* {entityName: 'Todo'},
|
|
1319
|
+
* addAsyncActionTrait({
|
|
1320
|
+
* name: 'createClient',
|
|
1321
|
+
* actionProps: props<{ name: string }>(),
|
|
1322
|
+
* actionSuccessProps: props<{ id: string }>(),
|
|
1323
|
+
* }),
|
|
1324
|
+
* )({
|
|
1325
|
+
* actionsGroupKey: 'Client',
|
|
1326
|
+
* featureSelector: createFeatureSelector<AsyncActionState<'createClient'>>(
|
|
1327
|
+
* 'client',
|
|
1328
|
+
* ),
|
|
1329
|
+
* });
|
|
1330
|
+
* // will generate the actions and selectors
|
|
1331
|
+
* traits.actions.createClient({name:'Pedro'})
|
|
1332
|
+
* traits.actions.createClientSuccess({id:'123'})
|
|
1333
|
+
* traits.actions.createClientFail();
|
|
1334
|
+
* traits.selectors.isLoadingCreateClient
|
|
1335
|
+
* traits.selectors.isSuccessCreateClient
|
|
1336
|
+
* traits.selectors.isFailCreateClient
|
|
1337
|
+
*/
|
|
1338
|
+
function addAsyncActionTrait({ name, actionProps, actionSuccessProps, actionFailProps, }) {
|
|
1339
|
+
const nameAsSentence = camelCaseToSentence(name);
|
|
1340
|
+
let internalActions;
|
|
1341
|
+
return createTraitFactory({
|
|
1342
|
+
key: name + '-call',
|
|
1343
|
+
config: {
|
|
1344
|
+
name,
|
|
1345
|
+
actionProps,
|
|
1346
|
+
actionSuccessProps,
|
|
1347
|
+
actionFailProps,
|
|
1348
|
+
},
|
|
1349
|
+
actions: ({ actionsGroupKey, }) => {
|
|
1350
|
+
internalActions = {
|
|
1351
|
+
request: (actionProps
|
|
1352
|
+
? createAction(`${actionsGroupKey} ${nameAsSentence}`, actionProps)
|
|
1353
|
+
: createAction(`${actionsGroupKey} ${nameAsSentence}`)),
|
|
1354
|
+
requestSuccess: (actionSuccessProps
|
|
1355
|
+
? createAction(`${actionsGroupKey} ${nameAsSentence} Success`, actionSuccessProps)
|
|
1356
|
+
: createAction(`${actionsGroupKey} ${nameAsSentence} Success`)),
|
|
1357
|
+
requestFail: (actionFailProps
|
|
1358
|
+
? createAction(`${actionsGroupKey} ${nameAsSentence} Failure`, actionFailProps)
|
|
1359
|
+
: createAction(`${actionsGroupKey} ${nameAsSentence} Failure`)),
|
|
1360
|
+
};
|
|
1361
|
+
if (name) {
|
|
1362
|
+
return {
|
|
1363
|
+
[`${name}`]: internalActions.request,
|
|
1364
|
+
[`${name}Success`]: internalActions.requestSuccess,
|
|
1365
|
+
[`${name}Fail`]: internalActions.requestFail,
|
|
1366
|
+
};
|
|
1367
|
+
}
|
|
1368
|
+
return internalActions;
|
|
1369
|
+
},
|
|
1370
|
+
selectors: () => {
|
|
1371
|
+
function isLoadingEntity(state) {
|
|
1372
|
+
return state[`${name}Status`] === 'loading';
|
|
1373
|
+
}
|
|
1374
|
+
function isSuccessEntity(state) {
|
|
1375
|
+
return state[`${name}Status`] === 'success';
|
|
1376
|
+
}
|
|
1377
|
+
function isFailEntity(state) {
|
|
1378
|
+
return state[`${name}Status`] === 'fail';
|
|
1379
|
+
}
|
|
1380
|
+
const capitalizedName = name.charAt(0).toUpperCase() + name.slice(1);
|
|
1381
|
+
return {
|
|
1382
|
+
[`isLoading${capitalizedName}`]: isLoadingEntity,
|
|
1383
|
+
[`isSuccess${capitalizedName}`]: isSuccessEntity,
|
|
1384
|
+
[`isFail${capitalizedName}`]: isFailEntity,
|
|
1385
|
+
};
|
|
1386
|
+
},
|
|
1387
|
+
initialState: ({ previousInitialState }) => previousInitialState,
|
|
1388
|
+
reducer: ({ initialState }) => {
|
|
1389
|
+
return createReducer(initialState, on(internalActions.request, (state) => (Object.assign(Object.assign({}, state), { [`${name}Status`]: 'loading' }))), on(internalActions.requestFail, (state) => (Object.assign(Object.assign({}, state), { [`${name}Status`]: 'fail' }))), on(internalActions.requestSuccess, (state) => (Object.assign(Object.assign({}, state), { [`${name}Status`]: 'success' }))));
|
|
1390
|
+
},
|
|
1391
|
+
});
|
|
1392
|
+
}
|
|
1393
|
+
|
|
1394
|
+
/**
|
|
1395
|
+
* Generates ngrx code needed to load and entity and store it in a state
|
|
1396
|
+
* @param entityName - Entity name, should be in camel case
|
|
1397
|
+
* @param options.actionProps - Optional param for the main request action,
|
|
1398
|
+
* use the props() function for its value, if not present action will have no params,
|
|
1399
|
+
* @param options.actionSuccessProps - Optional param for the request success
|
|
1400
|
+
* action, use the props() function for its value, if not present action success will have no params
|
|
1401
|
+
* @param options.actionFailProps - Optional param for the request fail action,
|
|
1402
|
+
* use the props() function for its value, if not present action fail will have no params
|
|
1403
|
+
* @returns the trait factory
|
|
1404
|
+
*
|
|
1405
|
+
* @example
|
|
1406
|
+
* const traits = createEntityFeatureFactory(
|
|
1407
|
+
* ...addLoadEntityTraits({
|
|
1408
|
+
* entityName: 'client',
|
|
1409
|
+
* requestProps: props<{ id: string }>(),
|
|
1410
|
+
* responseProps: props<{ client: Client }>(),
|
|
1411
|
+
* }),
|
|
1412
|
+
* )({
|
|
1413
|
+
* actionsGroupKey: 'Client',
|
|
1414
|
+
* featureSelector: createFeatureSelector<
|
|
1415
|
+
* LoadEntityState<Client, 'client'>
|
|
1416
|
+
* >('client'),
|
|
1417
|
+
* });
|
|
1418
|
+
*
|
|
1419
|
+
* // will generate
|
|
1420
|
+
* traits.actions.loadClient({id:123});
|
|
1421
|
+
* traits.actions.loadClientSuccess({client: {id: '123', name: 'gabs'}});
|
|
1422
|
+
* traits.actions.loadClientFail();
|
|
1423
|
+
* traits.selectors.selectClient
|
|
1424
|
+
* traits.selectors.isLoadingLoadClient
|
|
1425
|
+
* traits.selectors.isSuccessLoadClient
|
|
1426
|
+
* traits.selectors.isFailLoadClient
|
|
1427
|
+
*/
|
|
1428
|
+
function addLoadEntityTraits({ entityName, actionProps, actionSuccessProps, actionFailProps, }) {
|
|
1429
|
+
const capitalizedName = capitalize(entityName);
|
|
1430
|
+
return [
|
|
1431
|
+
addAsyncActionTrait({
|
|
1432
|
+
name: ('load' + capitalizedName),
|
|
1433
|
+
actionProps,
|
|
1434
|
+
actionSuccessProps,
|
|
1435
|
+
actionFailProps,
|
|
1436
|
+
}),
|
|
1437
|
+
createTraitFactory({
|
|
1438
|
+
key: `load${capitalizedName}`,
|
|
1439
|
+
config: { entityName, actionProps, actionSuccessProps, actionFailProps },
|
|
1440
|
+
selectors: () => {
|
|
1441
|
+
function selectEntity(state) {
|
|
1442
|
+
return state[`${entityName}`];
|
|
1443
|
+
}
|
|
1444
|
+
return {
|
|
1445
|
+
[`select${capitalizedName}`]: selectEntity,
|
|
1446
|
+
};
|
|
1447
|
+
},
|
|
1448
|
+
initialState: ({ previousInitialState, }) => previousInitialState,
|
|
1449
|
+
reducer: ({ initialState, allActions }) => {
|
|
1450
|
+
return createReducer(initialState, on(allActions[`load${capitalizedName}Success`], (state, action) => (Object.assign(Object.assign({}, state), { [entityName]: action[entityName] }))));
|
|
1451
|
+
},
|
|
1452
|
+
}),
|
|
1453
|
+
];
|
|
1454
|
+
}
|
|
1455
|
+
|
|
1456
|
+
/**
|
|
1457
|
+
* Generates ngrx code needed to set and entity in the store state
|
|
1458
|
+
* @param entityName - Entity name, should be in camel case
|
|
1459
|
+
* @param options.actionProps - param for the main request action,
|
|
1460
|
+
* use the props() function for its value
|
|
1461
|
+
* @returns the trait factory
|
|
1462
|
+
*
|
|
1463
|
+
* @example
|
|
1464
|
+
* const traits = createEntityFeatureFactory(
|
|
1465
|
+
* addSetEntityTraits({
|
|
1466
|
+
* entityName: 'client',
|
|
1467
|
+
* actionProps: props<{ client: { id: number; name: string } }
|
|
1468
|
+
* }),
|
|
1469
|
+
* )({
|
|
1470
|
+
* actionsGroupKey: 'Client',
|
|
1471
|
+
* featureSelector: createFeatureSelector<
|
|
1472
|
+
* SetEntityState<Client, 'client'>
|
|
1473
|
+
* >('client'),
|
|
1474
|
+
* });
|
|
1475
|
+
*
|
|
1476
|
+
* // will generate
|
|
1477
|
+
* traits.actions.setClient({client: {id:123, name: 'gabs'}});
|
|
1478
|
+
* traits.selectors.selectClient
|
|
1479
|
+
*/
|
|
1480
|
+
function addSetEntityTrait({ entityName, actionProps, }) {
|
|
1481
|
+
const capitalizedName = capitalize(entityName);
|
|
1482
|
+
return createTraitFactory({
|
|
1483
|
+
key: `load${capitalizedName}`,
|
|
1484
|
+
config: { entityName, actionProps },
|
|
1485
|
+
actions: ({ actionsGroupKey }) => {
|
|
1486
|
+
const setEntity = createAction(`${actionsGroupKey} Set ${capitalizedName}`, actionProps);
|
|
1487
|
+
return {
|
|
1488
|
+
[`set${capitalizedName}`]: setEntity,
|
|
1489
|
+
};
|
|
1490
|
+
},
|
|
1491
|
+
selectors: () => {
|
|
1492
|
+
function selectEntity(state) {
|
|
1493
|
+
return state[`${entityName}`];
|
|
1494
|
+
}
|
|
1495
|
+
return {
|
|
1496
|
+
[`select${capitalizedName}`]: selectEntity,
|
|
1497
|
+
};
|
|
1498
|
+
},
|
|
1499
|
+
initialState: ({ previousInitialState }) => previousInitialState,
|
|
1500
|
+
reducer: ({ initialState, allActions }) => {
|
|
1501
|
+
return createReducer(initialState, on(allActions[`set${capitalizedName}`], (state, action) => (Object.assign(Object.assign({}, state), { [entityName]: action[entityName] }))));
|
|
1502
|
+
},
|
|
1503
|
+
});
|
|
1504
|
+
}
|
|
1505
|
+
|
|
1506
|
+
/**
|
|
1507
|
+
* Generated bundle index. Do not edit.
|
|
1508
|
+
*/
|
|
1509
|
+
|
|
1510
|
+
export { ChangeType, _isNumberValue, addAsyncActionTrait, addCrudEntitiesTrait, addEntitiesPaginationTrait, addFilterEntitiesTrait, addLoadEntitiesTrait, addLoadEntityTraits, addResetEntitiesStateTrait, addSelectEntitiesTrait, addSelectEntityTrait, addSetEntityTrait, addSortEntitiesTrait, clearEntitiesSelection, crudEntitiesTraitKey, deselectEntities, entitiesPaginationTraitKey, filterEntitiesTraitKey, loadEntitiesTraitKey, selectEntities, selectEntityTraitKey, selectTotalSelectedEntities, sortData, sortTraitKey, toggleSelectEntities };
|
|
1511
|
+
//# sourceMappingURL=ngrx-traits-common.js.map
|