@smartsoft001/crud-shell-angular 1.2.91 → 2.70.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (214) hide show
  1. package/.storybook/addons.js +1 -0
  2. package/.storybook/config.js +5 -0
  3. package/.storybook/tsconfig.json +8 -0
  4. package/.storybook/webpack.config.js +7 -0
  5. package/jest.config.ts +38 -0
  6. package/ng-package.json +7 -0
  7. package/package.json +12 -23
  8. package/project.json +49 -0
  9. package/src/index.ts +13 -0
  10. package/src/lib/+state/crud.facade.ts +82 -0
  11. package/src/lib/+state/crud.feature.methods.ts +258 -0
  12. package/src/lib/+state/crud.feature.store.ts +77 -0
  13. package/src/lib/components/components.module.ts +58 -0
  14. package/src/lib/components/export/export.component.ts +69 -0
  15. package/src/lib/components/filter/base/base.component.ts +175 -0
  16. package/src/lib/components/filter/check/check.component.scss +25 -0
  17. package/src/lib/components/filter/check/check.component.ts +72 -0
  18. package/src/lib/components/filter/date/date.component.html +30 -0
  19. package/src/lib/components/filter/date/date.component.ts +70 -0
  20. package/src/lib/components/filter/date-time/date-time.component.html +62 -0
  21. package/src/lib/components/filter/date-time/date-time.component.ts +56 -0
  22. package/src/lib/components/filter/date-with-edit/date-with-edit.component.html +109 -0
  23. package/src/lib/components/filter/date-with-edit/date-with-edit.component.ts +70 -0
  24. package/src/lib/components/filter/filter.component.html +52 -0
  25. package/src/lib/components/filter/filter.component.ts +34 -0
  26. package/src/lib/components/filter/flag/flag.component.ts +55 -0
  27. package/src/lib/components/filter/index.ts +9 -0
  28. package/src/lib/components/filter/int/int.component.html +74 -0
  29. package/src/lib/components/filter/int/int.component.ts +57 -0
  30. package/src/lib/components/filter/radio/radio.component.ts +74 -0
  31. package/src/lib/components/filter/text/text.component.ts +46 -0
  32. package/src/lib/components/filters/filters.component.scss +150 -0
  33. package/src/lib/components/filters/filters.component.ts +157 -0
  34. package/src/lib/components/filters-config/filters-config.component.ts +69 -0
  35. package/src/lib/components/group/group.component.ts +93 -0
  36. package/src/lib/components/index.ts +7 -0
  37. package/src/lib/components/multiselect/multiselect.component.html +41 -0
  38. package/src/lib/components/multiselect/multiselect.component.scss +125 -0
  39. package/src/lib/components/multiselect/multiselect.component.ts +104 -0
  40. package/src/lib/crud-full.module.ts +51 -0
  41. package/src/lib/crud.config.ts +79 -0
  42. package/src/lib/crud.module.ts +72 -0
  43. package/src/lib/factories/list-pagination/list-pagination.factory.ts +77 -0
  44. package/src/lib/models/index.ts +1 -0
  45. package/src/lib/models/interfaces.ts +34 -0
  46. package/src/lib/pages/index.ts +6 -0
  47. package/src/lib/pages/item/base/base.component.ts +54 -0
  48. package/src/lib/pages/item/item.component.ts +513 -0
  49. package/src/lib/pages/item/standard/standard.component.scss +0 -0
  50. package/src/lib/pages/item/standard/standard.component.ts +50 -0
  51. package/src/lib/pages/list/base/base.component.ts +29 -0
  52. package/src/lib/pages/list/list.component.stories.ts +77 -0
  53. package/src/lib/pages/list/list.component.ts +438 -0
  54. package/src/lib/pages/list/standard/standard.component.ts +42 -0
  55. package/src/lib/pipes/form-options/form-options.pipe.ts +61 -0
  56. package/src/lib/pipes/index.ts +2 -0
  57. package/src/lib/pipes/pipes.module.ts +9 -0
  58. package/src/lib/providers/model-possibilities/model-possibilities.provider.ts +19 -0
  59. package/src/lib/services/crud/crud.service.spec.ts +303 -0
  60. package/src/lib/services/crud/crud.service.ts +178 -0
  61. package/src/lib/services/list-group/list-group.service.spec.ts +87 -0
  62. package/src/lib/services/list-group/list-group.service.ts +65 -0
  63. package/src/lib/services/page/page.service.spec.ts +143 -0
  64. package/src/lib/services/page/page.service.ts +44 -0
  65. package/src/lib/services/search/search.service.spec.ts +134 -0
  66. package/src/lib/services/search/search.service.ts +42 -0
  67. package/test-setup.ts +0 -0
  68. package/tsconfig.json +13 -0
  69. package/tsconfig.lib.json +31 -0
  70. package/tsconfig.lib.prod.json +11 -0
  71. package/tsconfig.spec.json +10 -0
  72. package/tslint.json +10 -0
  73. package/esm2022/index.mjs +0 -18
  74. package/esm2022/lib/+state/crud.actions.mjs +0 -224
  75. package/esm2022/lib/+state/crud.effects.mjs +0 -182
  76. package/esm2022/lib/+state/crud.facade.mjs +0 -91
  77. package/esm2022/lib/+state/crud.reducer.mjs +0 -214
  78. package/esm2022/lib/+state/crud.selectors.mjs +0 -11
  79. package/esm2022/lib/components/components.module.mjs +0 -110
  80. package/esm2022/lib/components/export/export.component.mjs +0 -47
  81. package/esm2022/lib/components/filter/base/base.component.mjs +0 -152
  82. package/esm2022/lib/components/filter/check/check.component.mjs +0 -36
  83. package/esm2022/lib/components/filter/date/date.component.mjs +0 -47
  84. package/esm2022/lib/components/filter/date-time/date-time.component.mjs +0 -43
  85. package/esm2022/lib/components/filter/date-with-edit/date-with-edit.component.mjs +0 -49
  86. package/esm2022/lib/components/filter/filter.component.mjs +0 -30
  87. package/esm2022/lib/components/filter/flag/flag.component.mjs +0 -16
  88. package/esm2022/lib/components/filter/index.mjs +0 -10
  89. package/esm2022/lib/components/filter/int/int.component.mjs +0 -38
  90. package/esm2022/lib/components/filter/radio/radio.component.mjs +0 -16
  91. package/esm2022/lib/components/filter/text/text.component.mjs +0 -16
  92. package/esm2022/lib/components/filters/filters.component.mjs +0 -111
  93. package/esm2022/lib/components/filters-config/filters-config.component.mjs +0 -37
  94. package/esm2022/lib/components/group/group.component.mjs +0 -54
  95. package/esm2022/lib/components/index.mjs +0 -8
  96. package/esm2022/lib/components/multiselect/multiselect.component.mjs +0 -71
  97. package/esm2022/lib/crud-full.module.mjs +0 -103
  98. package/esm2022/lib/crud.config.mjs +0 -17
  99. package/esm2022/lib/crud.module.mjs +0 -106
  100. package/esm2022/lib/factories/list-pagination/list-pagination.factory.mjs +0 -69
  101. package/esm2022/lib/models/index.mjs +0 -2
  102. package/esm2022/lib/models/interfaces.mjs +0 -2
  103. package/esm2022/lib/pages/index.mjs +0 -7
  104. package/esm2022/lib/pages/item/base/base.component.mjs +0 -44
  105. package/esm2022/lib/pages/item/item.component.mjs +0 -395
  106. package/esm2022/lib/pages/item/standard/standard.component.mjs +0 -15
  107. package/esm2022/lib/pages/list/base/base.component.mjs +0 -23
  108. package/esm2022/lib/pages/list/list.component.mjs +0 -355
  109. package/esm2022/lib/pages/list/standard/standard.component.mjs +0 -34
  110. package/esm2022/lib/pipes/form-options/form-options.pipe.mjs +0 -55
  111. package/esm2022/lib/pipes/index.mjs +0 -3
  112. package/esm2022/lib/pipes/pipes.module.mjs +0 -20
  113. package/esm2022/lib/providers/model-possibilities/model-possibilities.provider.mjs +0 -11
  114. package/esm2022/lib/services/crud/crud.service.mjs +0 -138
  115. package/esm2022/lib/services/list-group/list-group.service.mjs +0 -60
  116. package/esm2022/lib/services/page/page.service.mjs +0 -41
  117. package/esm2022/lib/services/search/search.service.mjs +0 -41
  118. package/esm2022/lib/services/socket/socket.service.mjs +0 -17
  119. package/esm2022/smartsoft001-crud-shell-angular.mjs +0 -5
  120. package/fesm2022/smartsoft001-crud-shell-angular.mjs +0 -2810
  121. package/fesm2022/smartsoft001-crud-shell-angular.mjs.map +0 -1
  122. package/index.d.ts +0 -18
  123. package/index.d.ts.map +0 -1
  124. package/lib/+state/crud.actions.d.ts +0 -152
  125. package/lib/+state/crud.actions.d.ts.map +0 -1
  126. package/lib/+state/crud.effects.d.ts +0 -18
  127. package/lib/+state/crud.effects.d.ts.map +0 -1
  128. package/lib/+state/crud.facade.d.ts +0 -44
  129. package/lib/+state/crud.facade.d.ts.map +0 -1
  130. package/lib/+state/crud.reducer.d.ts +0 -43
  131. package/lib/+state/crud.reducer.d.ts.map +0 -1
  132. package/lib/+state/crud.selectors.d.ts +0 -10
  133. package/lib/+state/crud.selectors.d.ts.map +0 -1
  134. package/lib/components/components.module.d.ts +0 -27
  135. package/lib/components/components.module.d.ts.map +0 -1
  136. package/lib/components/export/export.component.d.ts +0 -21
  137. package/lib/components/export/export.component.d.ts.map +0 -1
  138. package/lib/components/filter/base/base.component.d.ts +0 -39
  139. package/lib/components/filter/base/base.component.d.ts.map +0 -1
  140. package/lib/components/filter/check/check.component.d.ts +0 -19
  141. package/lib/components/filter/check/check.component.d.ts.map +0 -1
  142. package/lib/components/filter/date/date.component.d.ts +0 -16
  143. package/lib/components/filter/date/date.component.d.ts.map +0 -1
  144. package/lib/components/filter/date-time/date-time.component.d.ts +0 -15
  145. package/lib/components/filter/date-time/date-time.component.d.ts.map +0 -1
  146. package/lib/components/filter/date-with-edit/date-with-edit.component.d.ts +0 -17
  147. package/lib/components/filter/date-with-edit/date-with-edit.component.d.ts.map +0 -1
  148. package/lib/components/filter/filter.component.d.ts +0 -14
  149. package/lib/components/filter/filter.component.d.ts.map +0 -1
  150. package/lib/components/filter/flag/flag.component.d.ts +0 -8
  151. package/lib/components/filter/flag/flag.component.d.ts.map +0 -1
  152. package/lib/components/filter/index.d.ts +0 -10
  153. package/lib/components/filter/index.d.ts.map +0 -1
  154. package/lib/components/filter/int/int.component.d.ts +0 -15
  155. package/lib/components/filter/int/int.component.d.ts.map +0 -1
  156. package/lib/components/filter/radio/radio.component.d.ts +0 -8
  157. package/lib/components/filter/radio/radio.component.d.ts.map +0 -1
  158. package/lib/components/filter/text/text.component.d.ts +0 -8
  159. package/lib/components/filter/text/text.component.d.ts.map +0 -1
  160. package/lib/components/filters/filters.component.d.ts +0 -83
  161. package/lib/components/filters/filters.component.d.ts.map +0 -1
  162. package/lib/components/filters-config/filters-config.component.d.ts +0 -19
  163. package/lib/components/filters-config/filters-config.component.d.ts.map +0 -1
  164. package/lib/components/group/group.component.d.ts +0 -23
  165. package/lib/components/group/group.component.d.ts.map +0 -1
  166. package/lib/components/index.d.ts +0 -8
  167. package/lib/components/index.d.ts.map +0 -1
  168. package/lib/components/multiselect/multiselect.component.d.ts +0 -28
  169. package/lib/components/multiselect/multiselect.component.d.ts.map +0 -1
  170. package/lib/crud-full.module.d.ts +0 -28
  171. package/lib/crud-full.module.d.ts.map +0 -1
  172. package/lib/crud.config.d.ts +0 -65
  173. package/lib/crud.config.d.ts.map +0 -1
  174. package/lib/crud.module.d.ts +0 -34
  175. package/lib/crud.module.d.ts.map +0 -1
  176. package/lib/factories/list-pagination/list-pagination.factory.d.ts +0 -20
  177. package/lib/factories/list-pagination/list-pagination.factory.d.ts.map +0 -1
  178. package/lib/models/index.d.ts +0 -2
  179. package/lib/models/index.d.ts.map +0 -1
  180. package/lib/models/interfaces.d.ts +0 -30
  181. package/lib/models/interfaces.d.ts.map +0 -1
  182. package/lib/pages/index.d.ts +0 -7
  183. package/lib/pages/index.d.ts.map +0 -1
  184. package/lib/pages/item/base/base.component.d.ts +0 -25
  185. package/lib/pages/item/base/base.component.d.ts.map +0 -1
  186. package/lib/pages/item/item.component.d.ts +0 -70
  187. package/lib/pages/item/item.component.d.ts.map +0 -1
  188. package/lib/pages/item/standard/standard.component.d.ts +0 -8
  189. package/lib/pages/item/standard/standard.component.d.ts.map +0 -1
  190. package/lib/pages/list/base/base.component.d.ts +0 -15
  191. package/lib/pages/list/base/base.component.d.ts.map +0 -1
  192. package/lib/pages/list/list.component.d.ts +0 -54
  193. package/lib/pages/list/list.component.d.ts.map +0 -1
  194. package/lib/pages/list/standard/standard.component.d.ts +0 -14
  195. package/lib/pages/list/standard/standard.component.d.ts.map +0 -1
  196. package/lib/pipes/form-options/form-options.pipe.d.ts +0 -15
  197. package/lib/pipes/form-options/form-options.pipe.d.ts.map +0 -1
  198. package/lib/pipes/index.d.ts +0 -3
  199. package/lib/pipes/index.d.ts.map +0 -1
  200. package/lib/pipes/pipes.module.d.ts +0 -8
  201. package/lib/pipes/pipes.module.d.ts.map +0 -1
  202. package/lib/providers/model-possibilities/model-possibilities.provider.d.ts +0 -18
  203. package/lib/providers/model-possibilities/model-possibilities.provider.d.ts.map +0 -1
  204. package/lib/services/crud/crud.service.d.ts +0 -38
  205. package/lib/services/crud/crud.service.d.ts.map +0 -1
  206. package/lib/services/list-group/list-group.service.d.ts +0 -15
  207. package/lib/services/list-group/list-group.service.d.ts.map +0 -1
  208. package/lib/services/page/page.service.d.ts +0 -12
  209. package/lib/services/page/page.service.d.ts.map +0 -1
  210. package/lib/services/search/search.service.d.ts +0 -16
  211. package/lib/services/search/search.service.d.ts.map +0 -1
  212. package/lib/services/socket/socket.service.d.ts +0 -10
  213. package/lib/services/socket/socket.service.d.ts.map +0 -1
  214. package/smartsoft001-crud-shell-angular.d.ts.map +0 -1
@@ -0,0 +1,438 @@
1
+ import { NgTemplateOutlet } from '@angular/common';
2
+ import {
3
+ ChangeDetectorRef,
4
+ Component,
5
+ ComponentFactory,
6
+ computed,
7
+ inject,
8
+ Injector,
9
+ input,
10
+ OnDestroy,
11
+ OnInit,
12
+ Signal,
13
+ TemplateRef,
14
+ viewChild,
15
+ viewChildren,
16
+ ViewContainerRef,
17
+ WritableSignal,
18
+ } from '@angular/core';
19
+ import { Router } from '@angular/router';
20
+ import { Subject } from 'rxjs';
21
+
22
+ import {
23
+ CreateDynamicComponent,
24
+ DynamicComponentLoader,
25
+ DynamicContentDirective,
26
+ HardwareService,
27
+ IIconButtonOptions,
28
+ IListOptions,
29
+ IPageOptions,
30
+ ListMode,
31
+ MenuService,
32
+ PageComponent,
33
+ } from '@smartsoft001/angular';
34
+ import { IEntity } from '@smartsoft001/domain-core';
35
+ import {
36
+ getModelFieldsWithOptions,
37
+ getModelOptions,
38
+ IFieldEditMetadata,
39
+ IFieldListMetadata,
40
+ } from '@smartsoft001/models';
41
+ import { SpecificationService } from '@smartsoft001/utils';
42
+
43
+ import { CrudFacade } from '../../+state/crud.facade';
44
+ import { ExportComponent } from '../../components';
45
+ import { FiltersComponent } from '../../components';
46
+ import { MultiselectComponent } from '../../components';
47
+ import { CrudFullConfig } from '../../crud.config';
48
+ import { CrudListPageBaseComponent } from './base/base.component';
49
+ import { CrudListPaginationFactory } from '../../factories/list-pagination/list-pagination.factory';
50
+ import { ICrudFilter } from '../../models';
51
+ import { ListStandardComponent } from './standard/standard.component';
52
+ import { PageService } from '../../services/page/page.service';
53
+ import { CrudSearchService } from '../../services/search/search.service';
54
+
55
+ @Component({
56
+ selector: 'smart-crud-list-page',
57
+ imports: [PageComponent, ListStandardComponent, NgTemplateOutlet],
58
+ template: `
59
+ @if (filter()) {
60
+ <smart-page [options]="pageOptions()">
61
+ <div #topTpl></div>
62
+
63
+ @if (template() === 'default') {
64
+ <smart-crud-list-standard-page [listOptions]="listOptions()">
65
+ <ng-container [ngTemplateOutlet]="contentTpl"></ng-container>
66
+ </smart-crud-list-standard-page>
67
+ }
68
+ <ng-template #contentTpl>
69
+ <ng-content></ng-content>
70
+ </ng-template>
71
+ <div class="dynamic-content"></div>
72
+ </smart-page>
73
+ }
74
+ `,
75
+ })
76
+ export class ListComponent<T extends IEntity<string>>
77
+ extends CreateDynamicComponent<CrudListPageBaseComponent<any>>(
78
+ 'crud-list-page',
79
+ )
80
+ implements OnInit, OnDestroy
81
+ {
82
+ private facade = inject(CrudFacade<T>);
83
+ private router = inject(Router);
84
+ private dynamicComponentLoader = inject(DynamicComponentLoader<T>);
85
+ private injector = inject(Injector);
86
+ private cd = inject(ChangeDetectorRef);
87
+ private menuService = inject(MenuService);
88
+ private hardwareService = inject(HardwareService);
89
+ private paginationFacade = inject(CrudListPaginationFactory<T>);
90
+ private pageService = inject(PageService<T>);
91
+ public config = inject(CrudFullConfig<T>);
92
+ private searchService = inject(CrudSearchService);
93
+
94
+ private _cleanMultiSelected$ = new Subject<void>();
95
+
96
+ pageOptions: Signal<IPageOptions>;
97
+ listOptions: WritableSignal<IListOptions<T>>;
98
+ links: { next; prev };
99
+
100
+ filter: Signal<ICrudFilter> = this.facade.filter;
101
+
102
+ topTpl = viewChild<ViewContainerRef>('topTpl');
103
+
104
+ contentTpl = viewChild<TemplateRef<any>>('contentTpl');
105
+
106
+ dynamicContents = viewChildren<DynamicContentDirective>(
107
+ DynamicContentDirective,
108
+ );
109
+
110
+ constructor() {
111
+ super();
112
+
113
+ this.links = this.facade.links();
114
+ }
115
+
116
+ refreshProperties(): void {
117
+ this.baseComponentRef.setInput('listOptions', this.listOptions());
118
+ }
119
+
120
+ async ngOnInit(): Promise<void> {
121
+ this.pageService.checkPermissions();
122
+
123
+ const options = getModelOptions(this.config.type);
124
+
125
+ let newFilter = null;
126
+
127
+ if (this.config.list?.resetQuery === 'beforeInit') {
128
+ newFilter = {
129
+ query: this.config.baseQuery ? [...this.config.baseQuery] : [],
130
+ paginationMode: this.config.list.paginationMode,
131
+ limit: this.config.pagination ? this.config.pagination.limit : null,
132
+ offset: this.config.pagination ? 0 : null,
133
+ sortBy: this.config.sort ? this.config.sort['default'] : null,
134
+ sortDesc: this.config.sort ? this.config.sort['defaultDesc'] : null,
135
+ ...this.searchService.filter,
136
+ };
137
+ } else if (this.filter()) {
138
+ newFilter = this.filter();
139
+ } else {
140
+ newFilter = {
141
+ paginationMode: this.config.list.paginationMode,
142
+ limit: this.searchService.filter?.limit
143
+ ? this.searchService.filter.limit
144
+ : this.config.pagination
145
+ ? this.config.pagination.limit
146
+ : null,
147
+ offset:
148
+ this.searchService.filter?.offset ||
149
+ this.searchService.filter?.offset === 0
150
+ ? this.searchService.filter.offset
151
+ : this.config.pagination
152
+ ? 0
153
+ : null,
154
+ sortBy: this.searchService.filter?.sortBy
155
+ ? this.searchService.filter.sortBy
156
+ : this.config.sort
157
+ ? this.config.sort['default']
158
+ : null,
159
+ sortDesc: this.searchService.filter?.sortDesc
160
+ ? this.searchService.filter.sortDesc
161
+ : this.config.sort
162
+ ? this.config.sort['defaultDesc']
163
+ : null,
164
+ query: this.config.baseQuery ? [...this.config.baseQuery] : [],
165
+ ...this.searchService.filter,
166
+ };
167
+ }
168
+
169
+ this.facade.read(newFilter);
170
+
171
+ const endButtons = this.getEndButtons();
172
+
173
+ this.pageOptions = computed(() => ({
174
+ title: this.config.title,
175
+ search: this.config.search
176
+ ? {
177
+ text: computed(() => this.filter().searchText ?? null),
178
+ set: (txt) => {
179
+ if (txt !== this.filter().searchText)
180
+ this.facade.read({
181
+ ...this.filter(),
182
+ searchText: txt,
183
+ offset: 0,
184
+ });
185
+ },
186
+ }
187
+ : null,
188
+ endButtons: endButtons,
189
+ }));
190
+
191
+ const compiledComponents =
192
+ await this.dynamicComponentLoader.getComponentsWithFactories({
193
+ components: [
194
+ ...(this.config.details &&
195
+ this.config.details['components'] &&
196
+ this.config.details['components'].top
197
+ ? [this.config.details['components'].top]
198
+ : []),
199
+ ...(this.config.details &&
200
+ this.config.details['components'] &&
201
+ this.config.details['components'].bottom
202
+ ? [this.config.details['components'].bottom]
203
+ : []),
204
+ ...(this.config.list &&
205
+ this.config.list['components'] &&
206
+ this.config.list['components'].top
207
+ ? [this.config.list['components'].top]
208
+ : []),
209
+ ],
210
+ });
211
+
212
+ this.listOptions.set({
213
+ provider: {
214
+ getData: (filter): void => {
215
+ const global = {
216
+ ...this.filter(),
217
+ ...filter,
218
+ };
219
+ this.facade.read(global);
220
+ },
221
+ onChangeMultiSelected: async (list) => {
222
+ if (list.length && !this.menuService.openedEnd) {
223
+ await this.menuService.openEnd({
224
+ injector: this.injector,
225
+ component: MultiselectComponent,
226
+ });
227
+ } else if (!list.length && this.menuService.openedEnd) {
228
+ await this.menuService.closeEnd();
229
+ }
230
+
231
+ this.facade.multiSelect(list);
232
+ },
233
+ list: this.facade.list,
234
+ loading: this.facade.loading,
235
+ onCleanMultiSelected$: this._cleanMultiSelected$,
236
+ },
237
+ cellPipe: this.config.list ? this.config.list.cellPipe : null,
238
+ mode: this.config.list?.mode,
239
+ type: this.config.type,
240
+ details: this.config.details
241
+ ? {
242
+ provider: {
243
+ getData: (id) => {
244
+ this.facade.select(id);
245
+ },
246
+ clearData: () => {
247
+ this.facade.unselect();
248
+ },
249
+ item: this.facade.selected,
250
+ loading: this.facade.loading,
251
+ },
252
+ componentFactories: {
253
+ top:
254
+ this.config.details &&
255
+ this.config.details['components'] &&
256
+ this.config.details['components'].top
257
+ ? compiledComponents.find(
258
+ (cc) =>
259
+ cc.component === this.config.details['components'].top,
260
+ ).factory
261
+ : null,
262
+ bottom:
263
+ this.config.details &&
264
+ this.config.details['components'] &&
265
+ this.config.details['components'].bottom
266
+ ? compiledComponents.find(
267
+ (cc) =>
268
+ cc.component ===
269
+ this.config.details['components'].bottom,
270
+ ).factory
271
+ : null,
272
+ },
273
+ }
274
+ : null,
275
+ item:
276
+ !!this.config.edit || this.config.details
277
+ ? {
278
+ options: {
279
+ routingPrefix: '/' + this.router.routerState.snapshot.url + '/',
280
+ edit: !!this.config.edit,
281
+ },
282
+ }
283
+ : null,
284
+ remove: this.config.remove
285
+ ? {
286
+ provider: {
287
+ invoke: (id) => this.facade.delete(id),
288
+ check: (item: T) => {
289
+ return options?.remove?.enabled
290
+ ? SpecificationService.valid(item, options?.remove?.enabled)
291
+ : true;
292
+ },
293
+ },
294
+ }
295
+ : null,
296
+ pagination: await this.paginationFacade.create({
297
+ mode: this.config.list.paginationMode,
298
+ limit: this.config.pagination.limit,
299
+ provider: {
300
+ getFilter: () => {
301
+ return this.filter();
302
+ },
303
+ getLinks: () => this.links,
304
+ },
305
+ }),
306
+ sort: this.config.sort,
307
+ });
308
+
309
+ this.cd.detectChanges();
310
+
311
+ this.initCloseMenu();
312
+ this.initTopComponent(compiledComponents);
313
+
314
+ this.refreshDynamicInstance();
315
+ }
316
+
317
+ private initCloseMenu() {
318
+ this.router.events.pipe(this.takeUntilDestroy).subscribe(async () => {
319
+ await this.clear();
320
+ });
321
+ }
322
+
323
+ private async clear() {
324
+ await this.menuService.closeEnd();
325
+
326
+ this.listOptions.update((val) => ({
327
+ ...val,
328
+ select: null,
329
+ }));
330
+
331
+ this.facade.multiSelect([]);
332
+ }
333
+
334
+ private getEndButtons(): Array<IIconButtonOptions> {
335
+ const fieldsWithOptions = getModelFieldsWithOptions(new this.config.type());
336
+ const modelOptions = getModelOptions(this.config.type);
337
+
338
+ const showFilters =
339
+ fieldsWithOptions.some(
340
+ (x) => (x.options?.list as IFieldListMetadata)?.filter,
341
+ ) || modelOptions?.filters?.length;
342
+
343
+ const showMultiEdit =
344
+ this.config.list?.components?.multi ||
345
+ (this.config.edit &&
346
+ fieldsWithOptions.some(
347
+ (x) => (x.options?.update as IFieldEditMetadata)?.multi,
348
+ ) &&
349
+ !this.hardwareService.isMobile &&
350
+ (!this.config?.list?.mode ||
351
+ this.config?.list?.mode === ListMode.desktop));
352
+
353
+ return [
354
+ ...(showMultiEdit
355
+ ? [
356
+ {
357
+ icon: 'checkbox-outline',
358
+ text: 'multi',
359
+ handler: () => {
360
+ this.facade.multiSelect([]);
361
+ this._cleanMultiSelected$.next();
362
+
363
+ setTimeout(async () => {
364
+ this.listOptions.update((val) => ({
365
+ ...val,
366
+ select: val.select === 'multi' ? null : 'multi',
367
+ }));
368
+ if (this.menuService.openedEnd)
369
+ await this.menuService.closeEnd();
370
+ this.cd.detectChanges();
371
+ });
372
+ },
373
+ },
374
+ ]
375
+ : []),
376
+ ...(showFilters
377
+ ? [
378
+ {
379
+ icon: 'filter-outline',
380
+ text: 'filters',
381
+ handler: async () => {
382
+ await this.menuService.openEnd({
383
+ injector: this.injector,
384
+ component: FiltersComponent,
385
+ });
386
+ },
387
+ },
388
+ ]
389
+ : []),
390
+ ...(this.config.add
391
+ ? [
392
+ {
393
+ icon: 'add',
394
+ text: 'add',
395
+ handler: () => {
396
+ this.router.navigate([
397
+ '/' + this.router.routerState.snapshot.url + '/add',
398
+ ]);
399
+ },
400
+ },
401
+ ]
402
+ : []),
403
+ ...(this.config.export
404
+ ? [
405
+ {
406
+ text: 'export',
407
+ icon: 'download-outline',
408
+ type: 'popover' as const,
409
+ component: ExportComponent,
410
+ },
411
+ ]
412
+ : []),
413
+ ...(this.config.buttons ? this.config.buttons : []),
414
+ ];
415
+ }
416
+
417
+ private initTopComponent(
418
+ compiledComponents: {
419
+ component: any;
420
+ factory: ComponentFactory<any>;
421
+ }[],
422
+ ) {
423
+ const factory =
424
+ this.config.list &&
425
+ this.config.list['components'] &&
426
+ this.config.list['components'].top
427
+ ? compiledComponents.find(
428
+ (cc) => cc.component === this.config.list['components'].top,
429
+ ).factory
430
+ : null;
431
+
432
+ setTimeout(() => {
433
+ if (factory && !this.topTpl().get(0)) {
434
+ this.topTpl().createComponent(factory);
435
+ }
436
+ });
437
+ }
438
+ }
@@ -0,0 +1,42 @@
1
+ import { Component, computed, inject, Signal } from '@angular/core';
2
+
3
+ import { ListComponent } from '@smartsoft001/angular';
4
+ import { IEntity } from '@smartsoft001/domain-core';
5
+
6
+ import { CrudFacade } from '../../../+state/crud.facade';
7
+ import { FiltersConfigComponent, GroupComponent } from '../../../components';
8
+ import { CrudFullConfig } from '../../../crud.config';
9
+ import { CrudListGroupService } from '../../../services/list-group/list-group.service';
10
+ import { CrudListPageBaseComponent } from '../base/base.component';
11
+
12
+ @Component({
13
+ selector: 'smart-crud-list-standard-page',
14
+ template: `
15
+ <smart-crud-filters-config></smart-crud-filters-config>
16
+ @let groups = config.list?.groups;
17
+ @if (listOptions) {
18
+ <smart-list
19
+ [hidden]="groups && !isSearch()"
20
+ [options]="listOptions()"
21
+ ></smart-list>
22
+ }
23
+ @if (groups && !isSearch()) {
24
+ <smart-crud-group
25
+ [groups]="groups"
26
+ [listOptions]="listOptions()"
27
+ ></smart-crud-group>
28
+ }
29
+ `,
30
+ imports: [FiltersConfigComponent, ListComponent, GroupComponent],
31
+ providers: [CrudListGroupService],
32
+ })
33
+ export class ListStandardComponent<
34
+ T extends IEntity<string>,
35
+ > extends CrudListPageBaseComponent<T> {
36
+ private readonly facade = inject(CrudFacade<T>);
37
+ public readonly config = inject(CrudFullConfig<T>);
38
+
39
+ isSearch: Signal<boolean> = computed(
40
+ () => !!this.facade.filter()?.searchText,
41
+ );
42
+ }
@@ -0,0 +1,61 @@
1
+ import { inject, Pipe, PipeTransform, Type } from '@angular/core';
2
+
3
+ import { IFormOptions, InputBaseComponent } from '@smartsoft001/angular';
4
+ import { IEntity } from '@smartsoft001/domain-core';
5
+
6
+ import { CRUD_MODEL_POSSIBILITIES_PROVIDER } from '../../providers/model-possibilities/model-possibilities.provider';
7
+
8
+ @Pipe({
9
+ name: 'smartFormOptions',
10
+ })
11
+ export class FormOptionsPipe<T extends IEntity<string>>
12
+ implements PipeTransform
13
+ {
14
+ private modelPossibilitiesProvider = inject(
15
+ CRUD_MODEL_POSSIBILITIES_PROVIDER,
16
+ );
17
+
18
+ transform(
19
+ item: T,
20
+ mode: string,
21
+ type: any,
22
+ uniqueProvider?: (values: Record<keyof T, any>) => Promise<boolean>,
23
+ inputComponents?: { [key: string]: Type<InputBaseComponent<any>> },
24
+ ): IFormOptions<T> {
25
+ if (!mode || !type) return null;
26
+
27
+ let possibilities = {};
28
+
29
+ if (type && this.modelPossibilitiesProvider) {
30
+ possibilities = this.modelPossibilitiesProvider.get(type);
31
+ }
32
+
33
+ if (mode === 'create') {
34
+ return {
35
+ mode: 'create',
36
+ possibilities,
37
+ inputComponents,
38
+ uniqueProvider,
39
+ model: new type(),
40
+ show: true,
41
+ };
42
+ } else {
43
+ const model = new type();
44
+
45
+ if (item) {
46
+ Object.keys(item).forEach((key) => {
47
+ model[key] = item[key];
48
+ });
49
+ }
50
+
51
+ return {
52
+ mode: mode,
53
+ uniqueProvider,
54
+ possibilities: possibilities,
55
+ inputComponents,
56
+ model: model,
57
+ show: true,
58
+ };
59
+ }
60
+ }
61
+ }
@@ -0,0 +1,2 @@
1
+ export * from './pipes.module';
2
+ export * from './form-options/form-options.pipe';
@@ -0,0 +1,9 @@
1
+ import { NgModule } from '@angular/core';
2
+
3
+ import { FormOptionsPipe } from './form-options/form-options.pipe';
4
+
5
+ @NgModule({
6
+ exports: [FormOptionsPipe],
7
+ imports: [FormOptionsPipe],
8
+ })
9
+ export class CrudPipesModule {}
@@ -0,0 +1,19 @@
1
+ import { InjectionToken } from '@angular/core';
2
+ import { Observable } from 'rxjs';
3
+
4
+ /**
5
+ * @deprecated - please, use IModelPossibilitiesProvider from @smartsoft001/angular
6
+ */
7
+ export abstract class ICrudModelPossibilitiesProvider {
8
+ abstract get<T>(type: any): {
9
+ [key: string]: Observable<{ id: any; text: string }[]>;
10
+ };
11
+ }
12
+
13
+ /**
14
+ * @deprecated - please, use MODEL_POSSIBILITIES_PROVIDER from @smartsoft001/angular
15
+ */
16
+ export const CRUD_MODEL_POSSIBILITIES_PROVIDER =
17
+ new InjectionToken<ICrudModelPossibilitiesProvider>(
18
+ 'CRUD_MODEL_POSSIBILITIES_PROVIDER',
19
+ );