@planeasyinc/le-angular 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 +6 -0
- package/dist/README.md +6 -0
- package/dist/fesm2022/planeasyinc-le-angular.mjs +1640 -0
- package/dist/fesm2022/planeasyinc-le-angular.mjs.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/lib/components/container/container.component.d.ts +16 -0
- package/dist/lib/components/node/node.component.d.ts +7 -0
- package/dist/lib/components/sidebar/sidebar.component.d.ts +27 -0
- package/dist/lib/components/toast-list/toast-list.component.d.ts +9 -0
- package/dist/lib/constants/default-config.d.ts +2 -0
- package/dist/lib/directives/le-drawer-container.directive.d.ts +5 -0
- package/dist/lib/directives/le-drawer-content.directive.d.ts +5 -0
- package/dist/lib/directives/le-drawer.directive.d.ts +9 -0
- package/dist/lib/icons/icons-map.d.ts +17 -0
- package/dist/lib/icons/le-icon.component.d.ts +23 -0
- package/dist/lib/icons/svg/arrow-down.d.ts +5 -0
- package/dist/lib/icons/svg/chevron.d.ts +5 -0
- package/dist/lib/icons/svg/sort.d.ts +5 -0
- package/dist/lib/interceptors/le-auth.interceptor.d.ts +2 -0
- package/dist/lib/providers/provideConfig.d.ts +11 -0
- package/dist/lib/services/le-api.service.d.ts +17 -0
- package/dist/lib/services/le-auth.service.d.ts +16 -0
- package/dist/lib/services/le-data.service.d.ts +24 -0
- package/dist/lib/services/le-toast.service.d.ts +39 -0
- package/dist/lib/templates/index.d.ts +9 -0
- package/dist/lib/templates/json.template.d.ts +6 -0
- package/dist/lib/templates/reference.template.d.ts +6 -0
- package/dist/lib/templates/string.template.d.ts +6 -0
- package/dist/lib/tokens/config.token.d.ts +2 -0
- package/dist/lib/tokens/http-context.token.d.ts +2 -0
- package/dist/lib/types/le-config.d.ts +7 -0
- package/dist/lib/views/chart-view/chart-view.component.d.ts +7 -0
- package/dist/lib/views/form-view/form-renderer.component.d.ts +15 -0
- package/dist/lib/views/form-view/form-view-attachment.service.d.ts +13 -0
- package/dist/lib/views/form-view/form-view-attachment.utils.d.ts +24 -0
- package/dist/lib/views/form-view/form-view.component.d.ts +33 -0
- package/dist/lib/views/form-view/form-view.utils.d.ts +21 -0
- package/dist/lib/views/form-view/form.adapter.d.ts +2 -0
- package/dist/lib/views/gird-col-view/grid-col-view.component.d.ts +7 -0
- package/dist/lib/views/gird-view/grid-view.component.d.ts +7 -0
- package/dist/lib/views/loading-view/loading-view.component.d.ts +9 -0
- package/dist/lib/views/section-view/section-view.component.d.ts +7 -0
- package/dist/lib/views/table-view/table-data-sourse.d.ts +9 -0
- package/dist/lib/views/table-view/table-view-actions.component.d.ts +8 -0
- package/dist/lib/views/table-view/table-view-cell.directive.d.ts +11 -0
- package/dist/lib/views/table-view/table-view-pagination.component.d.ts +30 -0
- package/dist/lib/views/table-view/table-view.component.d.ts +58 -0
- package/dist/lib/views/table-view/table-view.types.d.ts +24 -0
- package/dist/lib/views/table-view/table-view.utils.d.ts +12 -0
- package/dist/styles/ant-overrides.scss +168 -0
- package/dist/styles/styles.scss +760 -0
- package/package.json +45 -0
|
@@ -0,0 +1,1640 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { InjectionToken, inject, signal, Injectable, computed, Directive, input, ChangeDetectionStrategy, Component, output, forwardRef, effect, untracked, ViewContainerRef, Renderer2, ElementRef, DestroyRef, viewChild } from '@angular/core';
|
|
3
|
+
import { HttpContextToken, HttpClient, HttpContext, HttpRequest, HttpEventType } from '@angular/common/http';
|
|
4
|
+
import { map, filter, distinctUntilChanged, BehaviorSubject, Subject, firstValueFrom, of, tap, catchError, from, concatMap, finalize } from 'rxjs';
|
|
5
|
+
import { decodeJwt, UrlFragmentBuilder, normalizeConfig } from '@planeasyinc/le-core';
|
|
6
|
+
import { CdkDrag } from '@angular/cdk/drag-drop';
|
|
7
|
+
import { BreakpointObserver, Breakpoints } from '@angular/cdk/layout';
|
|
8
|
+
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
9
|
+
import { coerceNumberProperty } from '@angular/cdk/coercion';
|
|
10
|
+
import { DataSource, CdkTable, CdkColumnDef, CdkHeaderCell, CdkHeaderCellDef, CdkCell, CdkCellDef, CdkHeaderRowDef, CdkHeaderRow, CdkRow, CdkRowDef } from '@angular/cdk/table';
|
|
11
|
+
import { CdkMenuTrigger, CdkMenu, CdkMenuItem } from '@angular/cdk/menu';
|
|
12
|
+
import { A11yModule } from '@angular/cdk/a11y';
|
|
13
|
+
import { JsonPipe, ViewportScroller } from '@angular/common';
|
|
14
|
+
import { adaptOld } from '@planeasyinc/fe-adapters-old';
|
|
15
|
+
import { adaptSections } from '@planeasyinc/fe-adapters-sections';
|
|
16
|
+
import { createEngine } from '@planeasyinc/fe-core';
|
|
17
|
+
import { FeFieldHost } from '@planeasyinc/fe-angular';
|
|
18
|
+
import { Overlay } from '@angular/cdk/overlay';
|
|
19
|
+
import { ComponentPortal } from '@angular/cdk/portal';
|
|
20
|
+
|
|
21
|
+
const IS_LIBRARY_REQUEST = new HttpContextToken(() => false);
|
|
22
|
+
|
|
23
|
+
const defaultConfig = {
|
|
24
|
+
apiUrl: '',
|
|
25
|
+
messages: {
|
|
26
|
+
tokenEmpty: 'No token provided',
|
|
27
|
+
tokenExpired: 'Your session has expired for security reasons. Please log in again to continue where you left off.',
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const CONFIG_TOKEN = new InjectionToken('CONFIG', {
|
|
32
|
+
factory: () => defaultConfig,
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
const SECOND_IN_MS = 1000;
|
|
36
|
+
class LEAuthService {
|
|
37
|
+
config = inject(CONFIG_TOKEN);
|
|
38
|
+
_token = signal(null);
|
|
39
|
+
_apiUrl = signal(this.config.apiUrl);
|
|
40
|
+
_isGuest = signal(false);
|
|
41
|
+
token = this._token.asReadonly();
|
|
42
|
+
apiUrl = this._apiUrl.asReadonly();
|
|
43
|
+
isGuest = this._isGuest.asReadonly();
|
|
44
|
+
setApiUrl(apiUrl) {
|
|
45
|
+
this._apiUrl.set(apiUrl);
|
|
46
|
+
}
|
|
47
|
+
setToken(token) {
|
|
48
|
+
this._token.set(token);
|
|
49
|
+
}
|
|
50
|
+
setGuestLogin(isGuest = true) {
|
|
51
|
+
this._isGuest.set(true);
|
|
52
|
+
}
|
|
53
|
+
validateToken() {
|
|
54
|
+
const token = this._token();
|
|
55
|
+
if (!token) {
|
|
56
|
+
throw new Error(this.config.messages.tokenEmpty);
|
|
57
|
+
}
|
|
58
|
+
const decoded = decodeJwt(token);
|
|
59
|
+
if (decoded.exp * SECOND_IN_MS < Date.now()) {
|
|
60
|
+
throw new Error(this.config.messages.tokenExpired);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: LEAuthService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
64
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: LEAuthService, providedIn: 'root' });
|
|
65
|
+
}
|
|
66
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: LEAuthService, decorators: [{
|
|
67
|
+
type: Injectable,
|
|
68
|
+
args: [{
|
|
69
|
+
providedIn: 'root',
|
|
70
|
+
}]
|
|
71
|
+
}] });
|
|
72
|
+
|
|
73
|
+
class LEApiService {
|
|
74
|
+
http = inject(HttpClient);
|
|
75
|
+
authService = inject(LEAuthService);
|
|
76
|
+
apiUrl = computed(() => {
|
|
77
|
+
return this.normalizeApiUrl(this.authService.apiUrl());
|
|
78
|
+
});
|
|
79
|
+
getConfig() {
|
|
80
|
+
const url = new UrlFragmentBuilder(this.apiUrl())
|
|
81
|
+
.setFragment('api/contrib/frontend-config/dashboard/config')
|
|
82
|
+
.build();
|
|
83
|
+
return this.http.get(url, { context: new HttpContext().set(IS_LIBRARY_REQUEST, true) });
|
|
84
|
+
}
|
|
85
|
+
getObject(className, query = '') {
|
|
86
|
+
const url = new UrlFragmentBuilder(this.apiUrl())
|
|
87
|
+
.setFragment('api/objects/')
|
|
88
|
+
.setQuery(`class_name=${className}`)
|
|
89
|
+
.setQuery('include_metadata=true&include_subclasses=true&load_references=false&file_optimized=true')
|
|
90
|
+
.setQuery(query)
|
|
91
|
+
.build();
|
|
92
|
+
return this.http.get(url, {
|
|
93
|
+
context: new HttpContext().set(IS_LIBRARY_REQUEST, true),
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
getObjectByAddress(address, includeVersions, includeMeta) {
|
|
97
|
+
const url = new UrlFragmentBuilder(this.apiUrl())
|
|
98
|
+
.setFragment(`api/objects/${address}/`)
|
|
99
|
+
.setQuery(`all_versions=${includeVersions}&include_metadata=${includeMeta}&load_references=false&file_optimized=true`)
|
|
100
|
+
.build();
|
|
101
|
+
return this.http.get(url, {
|
|
102
|
+
context: new HttpContext().set(IS_LIBRARY_REQUEST, true),
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
executeTransaction(name, body, query = '') {
|
|
106
|
+
const url = new UrlFragmentBuilder(this.apiUrl())
|
|
107
|
+
.setFragment(`api/transactions/${name}/`)
|
|
108
|
+
.setQuery(query)
|
|
109
|
+
.build();
|
|
110
|
+
return this.http.post(url, body ?? {}, {
|
|
111
|
+
context: new HttpContext().set(IS_LIBRARY_REQUEST, true),
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
request(method, path, body) {
|
|
115
|
+
const url = new UrlFragmentBuilder(this.apiUrl()).setFragment(path).build();
|
|
116
|
+
const request = new HttpRequest(method, url, body, {
|
|
117
|
+
responseType: 'json',
|
|
118
|
+
context: new HttpContext().set(IS_LIBRARY_REQUEST, true),
|
|
119
|
+
});
|
|
120
|
+
return this.http.request(request);
|
|
121
|
+
}
|
|
122
|
+
getBlob(path) {
|
|
123
|
+
return this.http
|
|
124
|
+
.get(path, { responseType: 'blob', context: new HttpContext().set(IS_LIBRARY_REQUEST, true) })
|
|
125
|
+
.pipe(map((blob) => URL.createObjectURL(blob)));
|
|
126
|
+
}
|
|
127
|
+
normalizeApiUrl(url) {
|
|
128
|
+
if (url.endsWith('/')) {
|
|
129
|
+
return url.slice(0, -1);
|
|
130
|
+
}
|
|
131
|
+
return url;
|
|
132
|
+
}
|
|
133
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: LEApiService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
134
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: LEApiService });
|
|
135
|
+
}
|
|
136
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: LEApiService, decorators: [{
|
|
137
|
+
type: Injectable
|
|
138
|
+
}] });
|
|
139
|
+
|
|
140
|
+
class LEDataService {
|
|
141
|
+
apiService = inject(LEApiService);
|
|
142
|
+
_config = signal(null);
|
|
143
|
+
_view = signal(null);
|
|
144
|
+
_parentMenu = signal(null);
|
|
145
|
+
_customCss = signal(null);
|
|
146
|
+
view = this._view.asReadonly();
|
|
147
|
+
parentMenu = this._parentMenu.asReadonly();
|
|
148
|
+
config = this._config.asReadonly();
|
|
149
|
+
customCss = this._customCss.asReadonly();
|
|
150
|
+
setView(node) {
|
|
151
|
+
this._view.set(node);
|
|
152
|
+
}
|
|
153
|
+
requestConfig(force) {
|
|
154
|
+
if (this._config() && !force) {
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
this.apiService.getConfig().subscribe({
|
|
158
|
+
next: (config) => {
|
|
159
|
+
const normalizedConfig = normalizeConfig({ type: 'section', ...config });
|
|
160
|
+
this._config.set(normalizedConfig);
|
|
161
|
+
this._customCss.set(config.custom_css);
|
|
162
|
+
const initialView = this.getInitialView(normalizedConfig);
|
|
163
|
+
this._view.set(initialView.node);
|
|
164
|
+
this._parentMenu.set(initialView.parent);
|
|
165
|
+
},
|
|
166
|
+
error: (err) => {
|
|
167
|
+
console.error(err);
|
|
168
|
+
},
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
request(method, url, body) {
|
|
172
|
+
return this.apiService
|
|
173
|
+
.request(method, url, body)
|
|
174
|
+
.pipe(filter((event) => HttpEventType.Response === event.type));
|
|
175
|
+
}
|
|
176
|
+
getObjectByClassName(className) {
|
|
177
|
+
return this.apiService.getObject(className);
|
|
178
|
+
}
|
|
179
|
+
navigateByNodeId(id) {
|
|
180
|
+
const node = this.getNodeById(id);
|
|
181
|
+
if (node) {
|
|
182
|
+
this._view.set(node);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
getNodeById(id, node = this._config()) {
|
|
186
|
+
if (node?.id) {
|
|
187
|
+
if (node.id === id) {
|
|
188
|
+
return node;
|
|
189
|
+
}
|
|
190
|
+
if ('children' in node) {
|
|
191
|
+
for (const child of node.children) {
|
|
192
|
+
const childNode = this.getNodeById(id, child);
|
|
193
|
+
if (childNode) {
|
|
194
|
+
return childNode;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
return null;
|
|
200
|
+
}
|
|
201
|
+
getInitialView(node) {
|
|
202
|
+
if ('children' in node) {
|
|
203
|
+
const child = node.children[0];
|
|
204
|
+
if ('isParentMenu' in child && child.isParentMenu) {
|
|
205
|
+
return this.getInitialView(child);
|
|
206
|
+
}
|
|
207
|
+
else {
|
|
208
|
+
return {
|
|
209
|
+
node: child,
|
|
210
|
+
parent: node
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
throw new Error(`${node.type} is not a section`);
|
|
215
|
+
}
|
|
216
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: LEDataService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
217
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: LEDataService });
|
|
218
|
+
}
|
|
219
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: LEDataService, decorators: [{
|
|
220
|
+
type: Injectable
|
|
221
|
+
}] });
|
|
222
|
+
|
|
223
|
+
class DrawerContentDirective {
|
|
224
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: DrawerContentDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
225
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.21", type: DrawerContentDirective, isStandalone: true, selector: "[leDrawerContent]", host: { properties: { "class.le-drawer-content": "true" } }, ngImport: i0 });
|
|
226
|
+
}
|
|
227
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: DrawerContentDirective, decorators: [{
|
|
228
|
+
type: Directive,
|
|
229
|
+
args: [{
|
|
230
|
+
selector: '[leDrawerContent]',
|
|
231
|
+
host: {
|
|
232
|
+
'[class.le-drawer-content]': 'true',
|
|
233
|
+
}
|
|
234
|
+
}]
|
|
235
|
+
}] });
|
|
236
|
+
|
|
237
|
+
class DrawerContainerDirective {
|
|
238
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: DrawerContainerDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
239
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.21", type: DrawerContainerDirective, isStandalone: true, selector: "[leDrawerContainer]", host: { properties: { "class.le-drawer-container": "true" } }, ngImport: i0 });
|
|
240
|
+
}
|
|
241
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: DrawerContainerDirective, decorators: [{
|
|
242
|
+
type: Directive,
|
|
243
|
+
args: [{
|
|
244
|
+
selector: '[leDrawerContainer]',
|
|
245
|
+
host: {
|
|
246
|
+
'[class.le-drawer-container]': 'true'
|
|
247
|
+
}
|
|
248
|
+
}]
|
|
249
|
+
}] });
|
|
250
|
+
|
|
251
|
+
const DRAWER_OPENED_WIDTH = 300;
|
|
252
|
+
const DRAWER_CLOSED_WIDTH = 60;
|
|
253
|
+
class LeDrawerDirective {
|
|
254
|
+
opened = input(false);
|
|
255
|
+
width = input(DRAWER_OPENED_WIDTH);
|
|
256
|
+
hideOnClose = input(false);
|
|
257
|
+
_width = computed(() => {
|
|
258
|
+
if (this.opened()) {
|
|
259
|
+
return this.width();
|
|
260
|
+
}
|
|
261
|
+
if (this.hideOnClose()) {
|
|
262
|
+
return 0;
|
|
263
|
+
}
|
|
264
|
+
return DRAWER_CLOSED_WIDTH;
|
|
265
|
+
});
|
|
266
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: LeDrawerDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
267
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "19.2.21", type: LeDrawerDirective, isStandalone: true, selector: "[leDrawer]", inputs: { opened: { classPropertyName: "opened", publicName: "opened", isSignal: true, isRequired: false, transformFunction: null }, width: { classPropertyName: "width", publicName: "width", isSignal: true, isRequired: false, transformFunction: null }, hideOnClose: { classPropertyName: "hideOnClose", publicName: "hideOnClose", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class.le-drawer": "true", "class.le-drawer--open": "opened()", "style.width.px": "_width()" } }, ngImport: i0 });
|
|
268
|
+
}
|
|
269
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: LeDrawerDirective, decorators: [{
|
|
270
|
+
type: Directive,
|
|
271
|
+
args: [{
|
|
272
|
+
selector: '[leDrawer]',
|
|
273
|
+
host: {
|
|
274
|
+
'[class.le-drawer]': 'true',
|
|
275
|
+
'[class.le-drawer--open]': 'opened()',
|
|
276
|
+
'[style.width.px]': '_width()'
|
|
277
|
+
},
|
|
278
|
+
}]
|
|
279
|
+
}] });
|
|
280
|
+
|
|
281
|
+
const chevron = {
|
|
282
|
+
name: 'chevron',
|
|
283
|
+
viewBox: '0 -960 960 960',
|
|
284
|
+
content: [
|
|
285
|
+
'M504-480 320-664l56-56 240 240-240 240-56-56 184-184Z'
|
|
286
|
+
]
|
|
287
|
+
};
|
|
288
|
+
|
|
289
|
+
const arrowDown = {
|
|
290
|
+
name: 'arrow-down',
|
|
291
|
+
viewBox: '0 -960 960 960',
|
|
292
|
+
content: [
|
|
293
|
+
'M480-360 280-560h400L480-360Z'
|
|
294
|
+
]
|
|
295
|
+
};
|
|
296
|
+
|
|
297
|
+
const sort = {
|
|
298
|
+
name: 'sort',
|
|
299
|
+
viewBox: '0 -960 960 960',
|
|
300
|
+
content: [
|
|
301
|
+
'M120-240v-80h240v80H120Zm0-200v-80h480v80H120Zm0-200v-80h720v80H120Z'
|
|
302
|
+
]
|
|
303
|
+
};
|
|
304
|
+
|
|
305
|
+
const ICONS_MAP = {
|
|
306
|
+
'chevron': chevron,
|
|
307
|
+
'arrow-down': arrowDown,
|
|
308
|
+
'sort': sort
|
|
309
|
+
};
|
|
310
|
+
|
|
311
|
+
class LeIconComponent {
|
|
312
|
+
name = input.required();
|
|
313
|
+
size = input(24);
|
|
314
|
+
icon = computed(() => ({
|
|
315
|
+
...ICONS_MAP[this.name()],
|
|
316
|
+
size: coerceNumberProperty(this.size()),
|
|
317
|
+
}));
|
|
318
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: LeIconComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
319
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.21", type: LeIconComponent, isStandalone: true, selector: "le-icon", inputs: { name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: true, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "style.width.px": "size()", "style.height.px": "size()", "style.display": "\"block\"" } }, ngImport: i0, template: `
|
|
320
|
+
@if (icon(); as icon) {
|
|
321
|
+
<svg
|
|
322
|
+
[attr.viewBox]="icon.viewBox"
|
|
323
|
+
[style.width.px]="icon.size"
|
|
324
|
+
[style.height.px]="icon.size"
|
|
325
|
+
fill="currentColor"
|
|
326
|
+
>
|
|
327
|
+
@for (path of icon.content; track path) {
|
|
328
|
+
<path [attr.d]="path"></path>
|
|
329
|
+
}
|
|
330
|
+
</svg>
|
|
331
|
+
}
|
|
332
|
+
`, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
333
|
+
}
|
|
334
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: LeIconComponent, decorators: [{
|
|
335
|
+
type: Component,
|
|
336
|
+
args: [{
|
|
337
|
+
selector: 'le-icon',
|
|
338
|
+
template: `
|
|
339
|
+
@if (icon(); as icon) {
|
|
340
|
+
<svg
|
|
341
|
+
[attr.viewBox]="icon.viewBox"
|
|
342
|
+
[style.width.px]="icon.size"
|
|
343
|
+
[style.height.px]="icon.size"
|
|
344
|
+
fill="currentColor"
|
|
345
|
+
>
|
|
346
|
+
@for (path of icon.content; track path) {
|
|
347
|
+
<path [attr.d]="path"></path>
|
|
348
|
+
}
|
|
349
|
+
</svg>
|
|
350
|
+
}
|
|
351
|
+
`,
|
|
352
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
353
|
+
host: {
|
|
354
|
+
'[style.width.px]': 'size()',
|
|
355
|
+
'[style.height.px]': 'size()',
|
|
356
|
+
'[style.display]': '"block"',
|
|
357
|
+
}
|
|
358
|
+
}]
|
|
359
|
+
}] });
|
|
360
|
+
|
|
361
|
+
class SidebarComponent {
|
|
362
|
+
breakpointObserver = inject(BreakpointObserver);
|
|
363
|
+
config = input.required();
|
|
364
|
+
view = input.required();
|
|
365
|
+
selectionChange = output();
|
|
366
|
+
_expanded = signal(new Set());
|
|
367
|
+
_width = signal(300);
|
|
368
|
+
_isDrawerOpen = signal(true);
|
|
369
|
+
_isSmallScreen = signal(false);
|
|
370
|
+
menu = computed(() => {
|
|
371
|
+
const config = this.config();
|
|
372
|
+
return 'children' in config ? config.children : [];
|
|
373
|
+
});
|
|
374
|
+
expanded = this._expanded.asReadonly();
|
|
375
|
+
width = this._width.asReadonly();
|
|
376
|
+
isDrawerOpen = this._isDrawerOpen.asReadonly();
|
|
377
|
+
isSmallScreen = this._isSmallScreen.asReadonly();
|
|
378
|
+
constructor() {
|
|
379
|
+
this.breakpointObserver
|
|
380
|
+
.observe([Breakpoints.XSmall])
|
|
381
|
+
.pipe(map((state) => state.matches), distinctUntilChanged(), takeUntilDestroyed())
|
|
382
|
+
.subscribe({
|
|
383
|
+
next: (matches) => {
|
|
384
|
+
this._isSmallScreen.set(matches);
|
|
385
|
+
this._isDrawerOpen.set(!matches);
|
|
386
|
+
},
|
|
387
|
+
});
|
|
388
|
+
}
|
|
389
|
+
isSection(item) {
|
|
390
|
+
return item.type === 'section' && item.isParentMenu;
|
|
391
|
+
}
|
|
392
|
+
toggleExpanded(event, item) {
|
|
393
|
+
event.preventDefault();
|
|
394
|
+
event.stopPropagation();
|
|
395
|
+
this._expanded.update((expanded) => {
|
|
396
|
+
if (expanded.has(item)) {
|
|
397
|
+
expanded.delete(item);
|
|
398
|
+
}
|
|
399
|
+
else {
|
|
400
|
+
expanded.add(item);
|
|
401
|
+
}
|
|
402
|
+
return new Set(expanded);
|
|
403
|
+
});
|
|
404
|
+
}
|
|
405
|
+
setExpanded(item) {
|
|
406
|
+
this._expanded.update((expanded) => {
|
|
407
|
+
expanded.add(item);
|
|
408
|
+
return new Set(expanded);
|
|
409
|
+
});
|
|
410
|
+
}
|
|
411
|
+
onSidebarItemClick(event, item) {
|
|
412
|
+
event.preventDefault();
|
|
413
|
+
event.stopPropagation();
|
|
414
|
+
this.selectionChange.emit(item);
|
|
415
|
+
}
|
|
416
|
+
onDrawerToggleClick(event) {
|
|
417
|
+
event.preventDefault();
|
|
418
|
+
event.stopPropagation();
|
|
419
|
+
this._isDrawerOpen.update((val) => !val);
|
|
420
|
+
}
|
|
421
|
+
onDragMoved(event) {
|
|
422
|
+
this._width.set(event.pointerPosition.x);
|
|
423
|
+
const element = event.source.element.nativeElement;
|
|
424
|
+
element.style.transform = 'none';
|
|
425
|
+
}
|
|
426
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: SidebarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
427
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.21", type: SidebarComponent, isStandalone: true, selector: "le-sidebar", inputs: { config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: true, transformFunction: null }, view: { classPropertyName: "view", publicName: "view", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { selectionChange: "selectionChange" }, ngImport: i0, template: "<div leDrawerContainer>\n <aside leDrawer [opened]=\"isDrawerOpen()\" [width]=\"width()\" [hideOnClose]=\"isSmallScreen()\">\n <h3 class=\"le-sidebar-title\">\n <button\n class=\"le-sidebar-toggle\"\n (click)=\"onDrawerToggleClick($event)\"\n (keydown.enter)=\"onDrawerToggleClick($event)\"\n >\n @if (isDrawerOpen()) {\n {{ config().title }}\n }\n\n <le-icon name=\"chevron\"></le-icon>\n </button>\n </h3>\n\n @if (isDrawerOpen()) {\n <menu>\n @for (item of menu(); track item) {\n @if (isSection(item)) {\n <a\n class=\"le-menu-item\"\n tabindex=\"0\"\n [class.le-menu-item--expanded]=\"expanded().has(item)\"\n (click)=\"toggleExpanded($event, item)\"\n (keydown.enter)=\"toggleExpanded($event, item)\"\n >\n <div class=\"le-menu-title\">\n {{ item.title }}\n </div>\n\n <le-icon class=\"le-menu-chevron\" name=\"chevron\"></le-icon>\n </a>\n\n <div class=\"le-menu-group\" [class.le-menu-group--expanded]=\"expanded().has(item)\">\n @for (child of item.children; track child) {\n <a\n [tabindex]=\"expanded().has(item) ? 0 : -1\"\n class=\"le-menu-item\"\n [class.le-menu-item--selected]=\"view().id === child.id\"\n (click)=\"onSidebarItemClick($event, child)\"\n (keydown.enter)=\"onSidebarItemClick($event, child)\"\n >\n <div class=\"le-menu-title\">\n {{ child.title }}\n </div>\n </a>\n }\n </div>\n } @else {\n <a\n tabindex=\"0\"\n class=\"le-menu-item\"\n [class.le-menu-item--selected]=\"view().id === item.id\"\n (click)=\"onSidebarItemClick($event, item)\"\n (keydown.enter)=\"onSidebarItemClick($event, item)\"\n >\n <div class=\"le-menu-title\">\n {{ item.title }}\n </div>\n </a>\n }\n }\n </menu>\n\n <div class=\"le-drawer-resizer\" cdkDrag (cdkDragMoved)=\"onDragMoved($event)\">\n <span class=\"le-drag-icon\">\u283F</span>\n </div>\n }\n </aside>\n\n <main leDrawerContent>\n <ng-content></ng-content>\n </main>\n</div>\n", dependencies: [{ kind: "directive", type: DrawerContentDirective, selector: "[leDrawerContent]" }, { kind: "directive", type: DrawerContainerDirective, selector: "[leDrawerContainer]" }, { kind: "directive", type: LeDrawerDirective, selector: "[leDrawer]", inputs: ["opened", "width", "hideOnClose"] }, { kind: "directive", type: CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "component", type: LeIconComponent, selector: "le-icon", inputs: ["name", "size"] }] });
|
|
428
|
+
}
|
|
429
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: SidebarComponent, decorators: [{
|
|
430
|
+
type: Component,
|
|
431
|
+
args: [{ selector: 'le-sidebar', imports: [DrawerContentDirective, DrawerContainerDirective, LeDrawerDirective, CdkDrag, LeIconComponent], template: "<div leDrawerContainer>\n <aside leDrawer [opened]=\"isDrawerOpen()\" [width]=\"width()\" [hideOnClose]=\"isSmallScreen()\">\n <h3 class=\"le-sidebar-title\">\n <button\n class=\"le-sidebar-toggle\"\n (click)=\"onDrawerToggleClick($event)\"\n (keydown.enter)=\"onDrawerToggleClick($event)\"\n >\n @if (isDrawerOpen()) {\n {{ config().title }}\n }\n\n <le-icon name=\"chevron\"></le-icon>\n </button>\n </h3>\n\n @if (isDrawerOpen()) {\n <menu>\n @for (item of menu(); track item) {\n @if (isSection(item)) {\n <a\n class=\"le-menu-item\"\n tabindex=\"0\"\n [class.le-menu-item--expanded]=\"expanded().has(item)\"\n (click)=\"toggleExpanded($event, item)\"\n (keydown.enter)=\"toggleExpanded($event, item)\"\n >\n <div class=\"le-menu-title\">\n {{ item.title }}\n </div>\n\n <le-icon class=\"le-menu-chevron\" name=\"chevron\"></le-icon>\n </a>\n\n <div class=\"le-menu-group\" [class.le-menu-group--expanded]=\"expanded().has(item)\">\n @for (child of item.children; track child) {\n <a\n [tabindex]=\"expanded().has(item) ? 0 : -1\"\n class=\"le-menu-item\"\n [class.le-menu-item--selected]=\"view().id === child.id\"\n (click)=\"onSidebarItemClick($event, child)\"\n (keydown.enter)=\"onSidebarItemClick($event, child)\"\n >\n <div class=\"le-menu-title\">\n {{ child.title }}\n </div>\n </a>\n }\n </div>\n } @else {\n <a\n tabindex=\"0\"\n class=\"le-menu-item\"\n [class.le-menu-item--selected]=\"view().id === item.id\"\n (click)=\"onSidebarItemClick($event, item)\"\n (keydown.enter)=\"onSidebarItemClick($event, item)\"\n >\n <div class=\"le-menu-title\">\n {{ item.title }}\n </div>\n </a>\n }\n }\n </menu>\n\n <div class=\"le-drawer-resizer\" cdkDrag (cdkDragMoved)=\"onDragMoved($event)\">\n <span class=\"le-drag-icon\">\u283F</span>\n </div>\n }\n </aside>\n\n <main leDrawerContent>\n <ng-content></ng-content>\n </main>\n</div>\n" }]
|
|
432
|
+
}], ctorParameters: () => [] });
|
|
433
|
+
|
|
434
|
+
class ChartViewComponent {
|
|
435
|
+
node = input.required();
|
|
436
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: ChartViewComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
437
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "19.2.21", type: ChartViewComponent, isStandalone: true, selector: "chart-view", inputs: { node: { classPropertyName: "node", publicName: "node", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<h2>{{ node()?.title }}</h2>\n" });
|
|
438
|
+
}
|
|
439
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: ChartViewComponent, decorators: [{
|
|
440
|
+
type: Component,
|
|
441
|
+
args: [{ selector: 'chart-view', template: "<h2>{{ node()?.title }}</h2>\n" }]
|
|
442
|
+
}] });
|
|
443
|
+
|
|
444
|
+
class GridComponent {
|
|
445
|
+
node = input.required();
|
|
446
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: GridComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
447
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.21", type: GridComponent, isStandalone: true, selector: "grid-view", inputs: { node: { classPropertyName: "node", publicName: "node", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "@for (child of node().children; track child.id) {\n <le-node [node]=\"child\"></le-node>\n}\n", dependencies: [{ kind: "component", type: i0.forwardRef(() => NodeComponent), selector: "le-node", inputs: ["node"] }] });
|
|
448
|
+
}
|
|
449
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: GridComponent, decorators: [{
|
|
450
|
+
type: Component,
|
|
451
|
+
args: [{ selector: 'grid-view', imports: [forwardRef(() => NodeComponent)], template: "@for (child of node().children; track child.id) {\n <le-node [node]=\"child\"></le-node>\n}\n" }]
|
|
452
|
+
}] });
|
|
453
|
+
|
|
454
|
+
class TableDataSource extends DataSource {
|
|
455
|
+
data;
|
|
456
|
+
get count() {
|
|
457
|
+
return this.data.value.length;
|
|
458
|
+
}
|
|
459
|
+
constructor(data = []) {
|
|
460
|
+
super();
|
|
461
|
+
this.data = new BehaviorSubject(data);
|
|
462
|
+
}
|
|
463
|
+
connect() {
|
|
464
|
+
return this.data;
|
|
465
|
+
}
|
|
466
|
+
disconnect() { }
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
class TableViewPaginationComponent {
|
|
470
|
+
pageSize = input.required();
|
|
471
|
+
pageSizeOptions = input.required();
|
|
472
|
+
entriesCount = input.required();
|
|
473
|
+
pageChange = output();
|
|
474
|
+
selectedPageSize = signal(0);
|
|
475
|
+
selectedPageIndex = signal(0);
|
|
476
|
+
entriesRange = computed(() => {
|
|
477
|
+
const selectedPageIndex = this.selectedPageIndex();
|
|
478
|
+
const pageSize = this.pageSize();
|
|
479
|
+
const count = this.entriesCount();
|
|
480
|
+
const rangeStart = selectedPageIndex * pageSize;
|
|
481
|
+
const rangeEnd = rangeStart + pageSize;
|
|
482
|
+
return {
|
|
483
|
+
start: rangeStart,
|
|
484
|
+
end: rangeEnd > count ? count : rangeEnd,
|
|
485
|
+
};
|
|
486
|
+
});
|
|
487
|
+
constructor() {
|
|
488
|
+
this.setEffects();
|
|
489
|
+
}
|
|
490
|
+
onPageSizeChange(option) {
|
|
491
|
+
this.selectedPageSize.set(option);
|
|
492
|
+
}
|
|
493
|
+
onNavigateClick(param) {
|
|
494
|
+
this.selectedPageIndex.update((index) => {
|
|
495
|
+
if (param === 'prev' && this.canNavigatePrev(index)) {
|
|
496
|
+
return index - 1;
|
|
497
|
+
}
|
|
498
|
+
if (param === 'next' && this.canNavigateNext(index)) {
|
|
499
|
+
return index + 1;
|
|
500
|
+
}
|
|
501
|
+
return index;
|
|
502
|
+
});
|
|
503
|
+
}
|
|
504
|
+
canNavigatePrev(index = this.selectedPageIndex()) {
|
|
505
|
+
return index > 0;
|
|
506
|
+
}
|
|
507
|
+
canNavigateNext(index = this.selectedPageIndex()) {
|
|
508
|
+
return index < this.getLastPageIndex();
|
|
509
|
+
}
|
|
510
|
+
setEffects() {
|
|
511
|
+
effect(() => {
|
|
512
|
+
const pageSize = this.pageSize();
|
|
513
|
+
untracked(() => {
|
|
514
|
+
this.selectedPageSize.set(pageSize);
|
|
515
|
+
});
|
|
516
|
+
});
|
|
517
|
+
effect(() => {
|
|
518
|
+
const pageSize = this.selectedPageSize();
|
|
519
|
+
untracked(() => {
|
|
520
|
+
const selectedPageIndex = this.selectedPageIndex();
|
|
521
|
+
const pageIndex = this.getPageIndexOnPageSizeChange();
|
|
522
|
+
if (selectedPageIndex !== pageIndex) {
|
|
523
|
+
this.selectedPageIndex.set(pageIndex);
|
|
524
|
+
}
|
|
525
|
+
else {
|
|
526
|
+
this.pageChange.emit({
|
|
527
|
+
pageSize: pageSize,
|
|
528
|
+
pageIndex: pageIndex,
|
|
529
|
+
});
|
|
530
|
+
}
|
|
531
|
+
});
|
|
532
|
+
});
|
|
533
|
+
effect(() => {
|
|
534
|
+
const index = this.selectedPageIndex();
|
|
535
|
+
untracked(() => {
|
|
536
|
+
this.pageChange.emit({
|
|
537
|
+
pageSize: this.selectedPageSize(),
|
|
538
|
+
pageIndex: index,
|
|
539
|
+
});
|
|
540
|
+
});
|
|
541
|
+
});
|
|
542
|
+
}
|
|
543
|
+
/**
|
|
544
|
+
* @return page index or last available page index for selected page size
|
|
545
|
+
*/
|
|
546
|
+
getPageIndexOnPageSizeChange() {
|
|
547
|
+
const selectedPageIndex = this.selectedPageIndex();
|
|
548
|
+
const lasPageIndex = this.getLastPageIndex();
|
|
549
|
+
return selectedPageIndex > lasPageIndex ? lasPageIndex : selectedPageIndex;
|
|
550
|
+
}
|
|
551
|
+
/**
|
|
552
|
+
* @return last available page index
|
|
553
|
+
*/
|
|
554
|
+
getLastPageIndex() {
|
|
555
|
+
const count = this.entriesCount();
|
|
556
|
+
if (count === 0)
|
|
557
|
+
return 0;
|
|
558
|
+
return Math.ceil(count / this.selectedPageSize()) - 1;
|
|
559
|
+
}
|
|
560
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: TableViewPaginationComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
561
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.21", type: TableViewPaginationComponent, isStandalone: true, selector: "table-view-pagination", inputs: { pageSize: { classPropertyName: "pageSize", publicName: "pageSize", isSignal: true, isRequired: true, transformFunction: null }, pageSizeOptions: { classPropertyName: "pageSizeOptions", publicName: "pageSizeOptions", isSignal: true, isRequired: true, transformFunction: null }, entriesCount: { classPropertyName: "entriesCount", publicName: "entriesCount", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { pageChange: "pageChange" }, ngImport: i0, template: "<div class=\"le-pagination\">\n <div class=\"le-pagination-options\">\n <span>Items per page:</span>\n\n <button [cdkMenuTriggerFor]=\"optionsMenu\" class=\"le-button\">\n {{ selectedPageSize() }}\n\n <le-icon name=\"arrow-down\"></le-icon>\n </button>\n\n <ng-template #optionsMenu>\n <div class=\"le-pagination-option-list\" cdkMenu>\n @for (option of pageSizeOptions(); track option) {\n <button cdkMenuItem class=\"le-pagination-option-item\" (click)=\"onPageSizeChange(option)\">\n {{ option }}\n </button>\n }\n </div>\n </ng-template>\n </div>\n\n <div class=\"spacer\"></div>\n\n <div class=\"le-pagination-range\">\n {{ entriesRange().start }} - {{ entriesRange().end }} of {{ entriesCount() }}\n </div>\n\n <div class=\"le-pagination-navigation\">\n <button\n class=\"le-navigation le-navigation-prev\"\n [tabindex]=\"canNavigatePrev() ? 0 : -1\"\n [disabled]=\"!canNavigatePrev()\"\n (click)=\"onNavigateClick('prev')\"\n >\n <le-icon class=\"le-chevron le-chevron--left\" name=\"chevron\"></le-icon>\n </button>\n\n <button\n class=\"le-navigation le-navigation-next\"\n [tabindex]=\"canNavigateNext() ? 0 : -1\"\n [disabled]=\"!canNavigateNext()\"\n (click)=\"onNavigateClick('next')\"\n >\n <le-icon class=\"le-chevron le-chevron--right\" name=\"chevron\"></le-icon>\n </button>\n </div>\n</div>\n", dependencies: [{ kind: "directive", type: CdkMenuTrigger, selector: "[cdkMenuTriggerFor]", inputs: ["cdkMenuTriggerFor", "cdkMenuPosition", "cdkMenuTriggerData"], outputs: ["cdkMenuOpened", "cdkMenuClosed"], exportAs: ["cdkMenuTriggerFor"] }, { kind: "directive", type: CdkMenu, selector: "[cdkMenu]", outputs: ["closed"], exportAs: ["cdkMenu"] }, { kind: "directive", type: CdkMenuItem, selector: "[cdkMenuItem]", inputs: ["cdkMenuItemDisabled", "cdkMenuitemTypeaheadLabel"], outputs: ["cdkMenuItemTriggered"], exportAs: ["cdkMenuItem"] }, { kind: "ngmodule", type: A11yModule }, { kind: "component", type: LeIconComponent, selector: "le-icon", inputs: ["name", "size"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
562
|
+
}
|
|
563
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: TableViewPaginationComponent, decorators: [{
|
|
564
|
+
type: Component,
|
|
565
|
+
args: [{ selector: 'table-view-pagination', imports: [CdkMenuTrigger, CdkMenu, CdkMenuItem, A11yModule, LeIconComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"le-pagination\">\n <div class=\"le-pagination-options\">\n <span>Items per page:</span>\n\n <button [cdkMenuTriggerFor]=\"optionsMenu\" class=\"le-button\">\n {{ selectedPageSize() }}\n\n <le-icon name=\"arrow-down\"></le-icon>\n </button>\n\n <ng-template #optionsMenu>\n <div class=\"le-pagination-option-list\" cdkMenu>\n @for (option of pageSizeOptions(); track option) {\n <button cdkMenuItem class=\"le-pagination-option-item\" (click)=\"onPageSizeChange(option)\">\n {{ option }}\n </button>\n }\n </div>\n </ng-template>\n </div>\n\n <div class=\"spacer\"></div>\n\n <div class=\"le-pagination-range\">\n {{ entriesRange().start }} - {{ entriesRange().end }} of {{ entriesCount() }}\n </div>\n\n <div class=\"le-pagination-navigation\">\n <button\n class=\"le-navigation le-navigation-prev\"\n [tabindex]=\"canNavigatePrev() ? 0 : -1\"\n [disabled]=\"!canNavigatePrev()\"\n (click)=\"onNavigateClick('prev')\"\n >\n <le-icon class=\"le-chevron le-chevron--left\" name=\"chevron\"></le-icon>\n </button>\n\n <button\n class=\"le-navigation le-navigation-next\"\n [tabindex]=\"canNavigateNext() ? 0 : -1\"\n [disabled]=\"!canNavigateNext()\"\n (click)=\"onNavigateClick('next')\"\n >\n <le-icon class=\"le-chevron le-chevron--right\" name=\"chevron\"></le-icon>\n </button>\n </div>\n</div>\n" }]
|
|
566
|
+
}], ctorParameters: () => [] });
|
|
567
|
+
|
|
568
|
+
const isPlaceholder$1 = (value) => {
|
|
569
|
+
return value.startsWith('{') && value.endsWith('}');
|
|
570
|
+
};
|
|
571
|
+
const mapSortStringToSort = (sort) => {
|
|
572
|
+
return sort.startsWith('-') ? [sort.slice(1), 'desc'] : [sort, 'desc'];
|
|
573
|
+
};
|
|
574
|
+
const mapSortStringListToSortMap = (sortList) => {
|
|
575
|
+
return sortList.reduce((acc, sort) => {
|
|
576
|
+
const { 0: key, 1: value } = mapSortStringToSort(sort);
|
|
577
|
+
acc.set(key, value);
|
|
578
|
+
return acc;
|
|
579
|
+
}, new Map());
|
|
580
|
+
};
|
|
581
|
+
const mapSortMapToSortStringList = (sortMap) => {
|
|
582
|
+
return [...sortMap].reduce((acc, sort) => {
|
|
583
|
+
const prefix = sort[1] === 'asc' ? '' : '-';
|
|
584
|
+
acc.push(`${prefix}${sort[0]}`);
|
|
585
|
+
return acc;
|
|
586
|
+
}, []);
|
|
587
|
+
};
|
|
588
|
+
const mapFiltersToFilterString = (filters) => {
|
|
589
|
+
return Object.entries(filters)
|
|
590
|
+
.reduce((acc, filter) => {
|
|
591
|
+
return acc.concat(`filter[${filter[0]}]=${filter[1]}`);
|
|
592
|
+
}, [])
|
|
593
|
+
.join('&');
|
|
594
|
+
};
|
|
595
|
+
const buildRequestContext = (params, ctx) => {
|
|
596
|
+
const requestContext = {};
|
|
597
|
+
if (ctx.hasPagination && params.pageIndex !== undefined) {
|
|
598
|
+
requestContext['pageIndex'] = params.pageIndex;
|
|
599
|
+
requestContext['pageSize'] = params.pageSize;
|
|
600
|
+
}
|
|
601
|
+
if (ctx.isSortable && params.sort) {
|
|
602
|
+
requestContext['sort'] = params.sort;
|
|
603
|
+
}
|
|
604
|
+
if (params.filters && Object.keys(params.filters).length > 0) {
|
|
605
|
+
requestContext['filters'] = params.filters;
|
|
606
|
+
}
|
|
607
|
+
return requestContext;
|
|
608
|
+
};
|
|
609
|
+
const buildRequestBody = (params) => {
|
|
610
|
+
const body = {};
|
|
611
|
+
if (params.sort?.length) {
|
|
612
|
+
body['ordering'] = params.sort;
|
|
613
|
+
}
|
|
614
|
+
if (params.filters && Object.keys(params.filters).length > 0) {
|
|
615
|
+
body['filters'] = params.filters;
|
|
616
|
+
}
|
|
617
|
+
if (params.pageIndex !== undefined) {
|
|
618
|
+
body['page'] = params.pageIndex + 1;
|
|
619
|
+
}
|
|
620
|
+
if (params.pageSize) {
|
|
621
|
+
body['page_size'] = params.pageSize;
|
|
622
|
+
}
|
|
623
|
+
return body;
|
|
624
|
+
};
|
|
625
|
+
const buildQueryString = (params) => {
|
|
626
|
+
const query = [];
|
|
627
|
+
if (params.pageIndex !== undefined) {
|
|
628
|
+
query.push(`page=${params.pageIndex + 1}`);
|
|
629
|
+
}
|
|
630
|
+
if (params.pageSize) {
|
|
631
|
+
query.push(`page_size=${params.pageSize}`);
|
|
632
|
+
}
|
|
633
|
+
if (params.sort?.length) {
|
|
634
|
+
query.push(`ordering=${params.sort.join(',')}`);
|
|
635
|
+
}
|
|
636
|
+
if (params.filters && Object.keys(params.filters).length > 0) {
|
|
637
|
+
query.push(mapFiltersToFilterString(params.filters));
|
|
638
|
+
}
|
|
639
|
+
return query.filter((item) => !!item).join('&');
|
|
640
|
+
};
|
|
641
|
+
|
|
642
|
+
class LoadingViewComponent {
|
|
643
|
+
headerHeight = input(0);
|
|
644
|
+
rowHeight = input(40);
|
|
645
|
+
rowCount = input(1);
|
|
646
|
+
rows = computed(() => {
|
|
647
|
+
return new Array(this.rowCount()).fill(null).map((_, i) => i);
|
|
648
|
+
});
|
|
649
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: LoadingViewComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
650
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.21", type: LoadingViewComponent, isStandalone: true, selector: "app-loading-view", inputs: { headerHeight: { classPropertyName: "headerHeight", publicName: "headerHeight", isSignal: true, isRequired: false, transformFunction: null }, rowHeight: { classPropertyName: "rowHeight", publicName: "rowHeight", isSignal: true, isRequired: false, transformFunction: null }, rowCount: { classPropertyName: "rowCount", publicName: "rowCount", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div class=\"preloader\">\n @if (headerHeight()) {\n <div class=\"preloader-row\" [style.height.px]=\"headerHeight()\"></div>\n }\n\n @for (row of rows(); track row) {\n <div class=\"preloader-row\" [style.height.px]=\"rowHeight()\"></div>\n }\n</div>\n", styles: [".preloader{display:flex;flex-direction:column;width:100%;gap:8px}.preloader-row{background:#f5f5f5 no-repeat;animation:pulse 1.5s cubic-bezier(.4,0,.2,1) infinite;animation-delay:.5s}@keyframes pulse{0%{opacity:1}50%{opacity:.5}to{opacity:1}}\n"] });
|
|
651
|
+
}
|
|
652
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: LoadingViewComponent, decorators: [{
|
|
653
|
+
type: Component,
|
|
654
|
+
args: [{ selector: 'app-loading-view', template: "<div class=\"preloader\">\n @if (headerHeight()) {\n <div class=\"preloader-row\" [style.height.px]=\"headerHeight()\"></div>\n }\n\n @for (row of rows(); track row) {\n <div class=\"preloader-row\" [style.height.px]=\"rowHeight()\"></div>\n }\n</div>\n", styles: [".preloader{display:flex;flex-direction:column;width:100%;gap:8px}.preloader-row{background:#f5f5f5 no-repeat;animation:pulse 1.5s cubic-bezier(.4,0,.2,1) infinite;animation-delay:.5s}@keyframes pulse{0%{opacity:1}50%{opacity:.5}to{opacity:1}}\n"] }]
|
|
655
|
+
}] });
|
|
656
|
+
|
|
657
|
+
class TableViewActions {
|
|
658
|
+
actions = input();
|
|
659
|
+
actionClicked = output();
|
|
660
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: TableViewActions, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
661
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.21", type: TableViewActions, isStandalone: true, selector: "table-view-actions", inputs: { actions: { classPropertyName: "actions", publicName: "actions", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { actionClicked: "actionClicked" }, host: { properties: { "class.le-table-view-actions": "true" } }, ngImport: i0, template: `
|
|
662
|
+
@for (action of actions(); track action) {
|
|
663
|
+
<button
|
|
664
|
+
class="le-button le-button-flat le-button--success"
|
|
665
|
+
(click)="actionClicked.emit(action)"
|
|
666
|
+
>
|
|
667
|
+
{{ action.label }}
|
|
668
|
+
</button>
|
|
669
|
+
}
|
|
670
|
+
`, isInline: true });
|
|
671
|
+
}
|
|
672
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: TableViewActions, decorators: [{
|
|
673
|
+
type: Component,
|
|
674
|
+
args: [{
|
|
675
|
+
selector: 'table-view-actions',
|
|
676
|
+
template: `
|
|
677
|
+
@for (action of actions(); track action) {
|
|
678
|
+
<button
|
|
679
|
+
class="le-button le-button-flat le-button--success"
|
|
680
|
+
(click)="actionClicked.emit(action)"
|
|
681
|
+
>
|
|
682
|
+
{{ action.label }}
|
|
683
|
+
</button>
|
|
684
|
+
}
|
|
685
|
+
`,
|
|
686
|
+
host: {
|
|
687
|
+
'[class.le-table-view-actions]': 'true',
|
|
688
|
+
},
|
|
689
|
+
}]
|
|
690
|
+
}] });
|
|
691
|
+
|
|
692
|
+
class StringTemplate {
|
|
693
|
+
data = input.required();
|
|
694
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: StringTemplate, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
695
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "19.2.21", type: StringTemplate, isStandalone: true, selector: "ng-component", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: `<span class="le-table-template le-template-string">{{ data() ?? '–' }}</span>`, isInline: true });
|
|
696
|
+
}
|
|
697
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: StringTemplate, decorators: [{
|
|
698
|
+
type: Component,
|
|
699
|
+
args: [{
|
|
700
|
+
template: `<span class="le-table-template le-template-string">{{ data() ?? '–' }}</span>`,
|
|
701
|
+
}]
|
|
702
|
+
}] });
|
|
703
|
+
|
|
704
|
+
class ReferenceTemplate {
|
|
705
|
+
data = input.required();
|
|
706
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: ReferenceTemplate, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
707
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "19.2.21", type: ReferenceTemplate, isStandalone: true, selector: "ng-component", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: `<span class="le-table-template le-template-reference"></span>`, isInline: true });
|
|
708
|
+
}
|
|
709
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: ReferenceTemplate, decorators: [{
|
|
710
|
+
type: Component,
|
|
711
|
+
args: [{
|
|
712
|
+
template: `<span class="le-table-template le-template-reference"></span>`,
|
|
713
|
+
}]
|
|
714
|
+
}] });
|
|
715
|
+
|
|
716
|
+
class JSONTemplate {
|
|
717
|
+
data = input.required();
|
|
718
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: JSONTemplate, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
719
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "19.2.21", type: JSONTemplate, isStandalone: true, selector: "ng-component", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: `<pre class="le-table-template le-template-json">{{
|
|
720
|
+
data() ? (data() | json) : '–'
|
|
721
|
+
}}</pre>`, isInline: true, dependencies: [{ kind: "pipe", type: JsonPipe, name: "json" }] });
|
|
722
|
+
}
|
|
723
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: JSONTemplate, decorators: [{
|
|
724
|
+
type: Component,
|
|
725
|
+
args: [{
|
|
726
|
+
template: `<pre class="le-table-template le-template-json">{{
|
|
727
|
+
data() ? (data() | json) : '–'
|
|
728
|
+
}}</pre>`,
|
|
729
|
+
imports: [JsonPipe],
|
|
730
|
+
}]
|
|
731
|
+
}] });
|
|
732
|
+
|
|
733
|
+
const TABLE_SELL_TEMPLATE_NAMES = {
|
|
734
|
+
StringTemplate: 'StringTemplate',
|
|
735
|
+
ReferenceTemplate: 'ReferenceTemplate',
|
|
736
|
+
JsonTemplate: 'JsonTemplate',
|
|
737
|
+
};
|
|
738
|
+
const TABLE_CELL_TEMPLATES = {
|
|
739
|
+
StringTemplate: StringTemplate,
|
|
740
|
+
ReferenceTemplate: ReferenceTemplate,
|
|
741
|
+
JsonTemplate: JSONTemplate,
|
|
742
|
+
};
|
|
743
|
+
|
|
744
|
+
class TableViewCellDirective {
|
|
745
|
+
vcr = inject(ViewContainerRef);
|
|
746
|
+
componentRef;
|
|
747
|
+
type = input();
|
|
748
|
+
data = input.required();
|
|
749
|
+
constructor() {
|
|
750
|
+
this.setEffects();
|
|
751
|
+
}
|
|
752
|
+
setEffects() {
|
|
753
|
+
effect(() => {
|
|
754
|
+
const type = this.type();
|
|
755
|
+
const data = this.data();
|
|
756
|
+
untracked(() => {
|
|
757
|
+
const component = (type && TABLE_CELL_TEMPLATES[type]) || TABLE_CELL_TEMPLATES['StringTemplate'];
|
|
758
|
+
if (this.componentRef) {
|
|
759
|
+
this.componentRef.destroy();
|
|
760
|
+
}
|
|
761
|
+
this.componentRef = this.vcr.createComponent(component);
|
|
762
|
+
this.componentRef?.setInput('data', data);
|
|
763
|
+
});
|
|
764
|
+
});
|
|
765
|
+
}
|
|
766
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: TableViewCellDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
767
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "19.2.21", type: TableViewCellDirective, isStandalone: true, selector: "[tableViewCell]", inputs: { type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: false, transformFunction: null }, data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0 });
|
|
768
|
+
}
|
|
769
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: TableViewCellDirective, decorators: [{
|
|
770
|
+
type: Directive,
|
|
771
|
+
args: [{
|
|
772
|
+
selector: '[tableViewCell]',
|
|
773
|
+
}]
|
|
774
|
+
}], ctorParameters: () => [] });
|
|
775
|
+
|
|
776
|
+
class TableViewComponent {
|
|
777
|
+
apiService = inject(LEApiService);
|
|
778
|
+
dataService = inject(LEDataService);
|
|
779
|
+
node = input.required();
|
|
780
|
+
_columns = signal([]);
|
|
781
|
+
_data = signal(new TableDataSource());
|
|
782
|
+
_total = signal(0);
|
|
783
|
+
_isLoading = signal(false);
|
|
784
|
+
_pageIndex = signal(0);
|
|
785
|
+
_pageSize = signal(0);
|
|
786
|
+
_pageSizeOptions = signal([]);
|
|
787
|
+
_sortConfig = signal(null);
|
|
788
|
+
_sortMap = signal(new Map());
|
|
789
|
+
_sortOrder = signal(new Map());
|
|
790
|
+
_cancelRequest$ = new Subject();
|
|
791
|
+
columns = this._columns.asReadonly();
|
|
792
|
+
data = this._data.asReadonly();
|
|
793
|
+
displayedColumns = computed(() => {
|
|
794
|
+
return this.columns().map((column) => column.key);
|
|
795
|
+
});
|
|
796
|
+
isLoading = this._isLoading.asReadonly();
|
|
797
|
+
pageIndex = this._pageIndex.asReadonly();
|
|
798
|
+
pageSize = this._pageSize.asReadonly();
|
|
799
|
+
pageSizeOptions = this._pageSizeOptions.asReadonly();
|
|
800
|
+
entriesCount = this._total.asReadonly();
|
|
801
|
+
sortMap = this._sortMap.asReadonly();
|
|
802
|
+
sortOrder = this._sortOrder.asReadonly();
|
|
803
|
+
isSortingEnabled = computed(() => {
|
|
804
|
+
return !!this._sortConfig()?.fields.length;
|
|
805
|
+
});
|
|
806
|
+
sortColumnKeys = computed(() => {
|
|
807
|
+
return new Set(this._sortConfig()?.fields ?? []);
|
|
808
|
+
});
|
|
809
|
+
hasRowClickAction = computed(() => {
|
|
810
|
+
return !!this.node()?.actions?.onRowClick?.length;
|
|
811
|
+
});
|
|
812
|
+
constructor() {
|
|
813
|
+
this.setEffects();
|
|
814
|
+
}
|
|
815
|
+
onPageChange(pageChange) {
|
|
816
|
+
this._pageSize.set(pageChange.pageSize);
|
|
817
|
+
this._pageIndex.set(pageChange.pageIndex);
|
|
818
|
+
}
|
|
819
|
+
onSortClick(event, column) {
|
|
820
|
+
event.stopPropagation();
|
|
821
|
+
this._sortMap.update((sortMap) => {
|
|
822
|
+
const direction = sortMap.get(column.key);
|
|
823
|
+
if (direction === 'desc') {
|
|
824
|
+
sortMap.delete(column.key);
|
|
825
|
+
}
|
|
826
|
+
else if (direction === 'asc') {
|
|
827
|
+
sortMap.set(column.key, 'desc');
|
|
828
|
+
}
|
|
829
|
+
else {
|
|
830
|
+
sortMap.set(column.key, 'asc');
|
|
831
|
+
}
|
|
832
|
+
return new Map(sortMap);
|
|
833
|
+
});
|
|
834
|
+
}
|
|
835
|
+
onToolbarActionClick({ actions }) {
|
|
836
|
+
actions.forEach((action) => this.processTableAction(action));
|
|
837
|
+
}
|
|
838
|
+
onRowClick(row) {
|
|
839
|
+
const actions = this.node().actions?.onRowClick ?? [];
|
|
840
|
+
actions.forEach((action) => this.processTableAction(action, row));
|
|
841
|
+
}
|
|
842
|
+
processTableAction(action, row) {
|
|
843
|
+
if (action.type === 'update_form') {
|
|
844
|
+
const dataSource = action.dataSource;
|
|
845
|
+
this.dataService.setView({
|
|
846
|
+
id: action.type,
|
|
847
|
+
type: 'form',
|
|
848
|
+
controlSource: {
|
|
849
|
+
kind: dataSource.kind,
|
|
850
|
+
entity: dataSource.entity,
|
|
851
|
+
params: dataSource?.params
|
|
852
|
+
? this.interpolateRowValues(dataSource.params, row)
|
|
853
|
+
: undefined,
|
|
854
|
+
},
|
|
855
|
+
});
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
setPagination(pagination) {
|
|
859
|
+
this._pageSize.set(pagination?.pageSize ?? 0);
|
|
860
|
+
this._pageSizeOptions.set(pagination?.options ?? []);
|
|
861
|
+
}
|
|
862
|
+
getTableData(node, ctx) {
|
|
863
|
+
this._isLoading.set(true);
|
|
864
|
+
this._cancelRequest$.next();
|
|
865
|
+
this.buildRequest(node, ctx).subscribe({
|
|
866
|
+
next: (response) => {
|
|
867
|
+
this.handleTableDataSuccessResponse(response);
|
|
868
|
+
},
|
|
869
|
+
error: (error) => {
|
|
870
|
+
this.handleTableDataErrorResponse(error);
|
|
871
|
+
},
|
|
872
|
+
});
|
|
873
|
+
}
|
|
874
|
+
buildRequest(node, ctx) {
|
|
875
|
+
if (node.dataSource?.kind === 'class') {
|
|
876
|
+
const query = buildQueryString(ctx);
|
|
877
|
+
return this.apiService.getObject(node.dataSource.entity, query);
|
|
878
|
+
}
|
|
879
|
+
if (node.dataSource?.kind === 'transaction') {
|
|
880
|
+
const body = Object.assign({}, node.dataSource.params, buildRequestBody(ctx));
|
|
881
|
+
this.apiService.executeTransaction(node.dataSource.entity, body);
|
|
882
|
+
}
|
|
883
|
+
throw new Error(`Datasource type should be class or transaction. Received: ${node.dataSource?.kind}`);
|
|
884
|
+
}
|
|
885
|
+
handleTableDataSuccessResponse(response) {
|
|
886
|
+
this._columns.set(response.columns);
|
|
887
|
+
this._data.set(new TableDataSource(response.rows));
|
|
888
|
+
this._total.set(response.total ?? response.rows.length);
|
|
889
|
+
this._isLoading.set(false);
|
|
890
|
+
}
|
|
891
|
+
handleTableDataErrorResponse(error) {
|
|
892
|
+
console.error(error);
|
|
893
|
+
this._columns.set([]);
|
|
894
|
+
this._data.set(new TableDataSource());
|
|
895
|
+
this._total.set(0);
|
|
896
|
+
this._isLoading.set(false);
|
|
897
|
+
}
|
|
898
|
+
interpolateRowValues(body, row = {}) {
|
|
899
|
+
const result = {};
|
|
900
|
+
Object.entries(body).forEach(([key, value]) => {
|
|
901
|
+
if (typeof value === 'string' && isPlaceholder$1(value)) {
|
|
902
|
+
const valueKey = value.replace(/\{row\.(\w+)\}/g, '$1');
|
|
903
|
+
if (row[valueKey]) {
|
|
904
|
+
result[key] = row[valueKey];
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
else {
|
|
908
|
+
result[key] = value;
|
|
909
|
+
}
|
|
910
|
+
});
|
|
911
|
+
return result;
|
|
912
|
+
}
|
|
913
|
+
setEffects() {
|
|
914
|
+
effect(() => {
|
|
915
|
+
const node = this.node();
|
|
916
|
+
this.setPagination(node.ui?.pagination);
|
|
917
|
+
this._sortConfig.set(node?.ui?.sort ?? null);
|
|
918
|
+
this._sortMap.set(mapSortStringListToSortMap(node?.ui?.sort?.default ?? []));
|
|
919
|
+
});
|
|
920
|
+
effect(() => {
|
|
921
|
+
const node = this.node();
|
|
922
|
+
const pageSize = this.pageSize();
|
|
923
|
+
const pageIndex = this.pageIndex();
|
|
924
|
+
const sort = this._sortMap();
|
|
925
|
+
untracked(() => {
|
|
926
|
+
if (node?.dataSource) {
|
|
927
|
+
const ctx = buildRequestContext({
|
|
928
|
+
pageSize,
|
|
929
|
+
pageIndex,
|
|
930
|
+
sort: mapSortMapToSortStringList(sort),
|
|
931
|
+
// filters,
|
|
932
|
+
}, {
|
|
933
|
+
isSortable: this.isSortingEnabled(),
|
|
934
|
+
hasPagination: !!this.pageSize(),
|
|
935
|
+
});
|
|
936
|
+
this.getTableData(node, ctx);
|
|
937
|
+
}
|
|
938
|
+
});
|
|
939
|
+
});
|
|
940
|
+
effect(() => {
|
|
941
|
+
const sortMap = this._sortMap();
|
|
942
|
+
untracked(() => {
|
|
943
|
+
this._sortOrder.update(() => {
|
|
944
|
+
return [...sortMap].reduce((acc, item, index) => {
|
|
945
|
+
return acc.set(item[0], index + 1);
|
|
946
|
+
}, new Map());
|
|
947
|
+
});
|
|
948
|
+
});
|
|
949
|
+
});
|
|
950
|
+
}
|
|
951
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: TableViewComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
952
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.21", type: TableViewComponent, isStandalone: true, selector: "table-view", inputs: { node: { classPropertyName: "node", publicName: "node", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<div class=\"le-toolbar\">\n @if (node(); as node) {\n <h2>{{ node?.title }}</h2>\n\n @if (node.actions?.tableActions) {\n <table-view-actions\n [actions]=\"node.actions!.tableActions\"\n (actionClicked)=\"onToolbarActionClick($event)\"\n ></table-view-actions>\n }\n }\n</div>\n\n@if (pageSize()) {\n <table-view-pagination\n [pageSize]=\"pageSize()\"\n [pageSizeOptions]=\"pageSizeOptions()\"\n [entriesCount]=\"entriesCount()\"\n (pageChange)=\"onPageChange($event)\"\n ></table-view-pagination>\n}\n\n<div class=\"le-table-container\">\n @if (displayedColumns().length) {\n <table cdk-table [dataSource]=\"data()\" class=\"le-table\" [class.le-table--loading]=\"isLoading()\">\n @for (column of columns(); track column) {\n <ng-container [cdkColumnDef]=\"column.key\">\n <th\n class=\"le-table-header-cell\"\n cdk-header-cell\n *cdkHeaderCellDef\n [tabindex]=\"sortColumnKeys().has(column.key) ? 0 : -1\"\n [class.le-table-header-cell--sortable]=\"sortColumnKeys().has(column.key)\"\n (click)=\"sortColumnKeys().has(column.key) && onSortClick($event, column)\"\n >\n <div class=\"le-cell-content\">\n <ng-template\n tableViewCell\n [data]=\"column.label\"\n [type]=\"column.column_format?.headerTemplate\"\n ></ng-template>\n\n @if (sortColumnKeys().has(column.key)) {\n <div class=\"le-sort-container\">\n @if (sortMap().has(column.key)) {\n <div class=\"le-sort-icon\">\n <i\n class=\"le-sort-arrow\"\n [class.le-sort-arrow--asc]=\"sortMap().get(column.key) === 'asc'\"\n [class.le-sort-arrow--desc]=\"sortMap().get(column.key) === 'desc'\"\n ></i>\n </div>\n\n <div class=\"le-sort-order\">\n @if (sortOrder().has(column.key)) {\n <span>\n {{ sortOrder().get(column.key) }}\n </span>\n }\n </div>\n } @else {\n<!-- <div class=\"le-sort-icon le-sort-icon--unfold\">-->\n<!-- <span>⇅</span>-->\n<!-- </div>-->\n\n <le-icon name=\"sort\" class=\"le-sort-icon le-sort-icon--unfold\"></le-icon>\n }\n </div>\n }\n </div>\n </th>\n\n <td class=\"le-table-cell\" cdk-cell *cdkCellDef=\"let row\">\n <ng-template\n tableViewCell\n [data]=\"row[column.key]\"\n [type]=\"column.column_format?.cellTemplate\"\n ></ng-template>\n </td>\n </ng-container>\n }\n\n <tr cdk-header-row class=\"le-header-row\" *cdkHeaderRowDef=\"displayedColumns()\"></tr>\n <tr\n cdk-row\n class=\"le-table-row\"\n [tabindex]=\"0\"\n [class.le-table-row--clickable]=\"hasRowClickAction()\"\n *cdkRowDef=\"let row; columns: displayedColumns()\"\n (click)=\"onRowClick(row)\"\n ></tr>\n </table>\n }\n</div>\n\n@if (data().count === 0) {\n @if (isLoading()) {\n <app-loading-view [headerHeight]=\"65\" [rowCount]=\"pageSize() || 10\"></app-loading-view>\n } @else {\n <div class=\"no-entities\">\n <span>No Entities</span>\n </div>\n }\n}\n", dependencies: [{ kind: "component", type: CdkTable, selector: "cdk-table, table[cdk-table]", inputs: ["trackBy", "dataSource", "multiTemplateDataRows", "fixedLayout"], outputs: ["contentChanged"], exportAs: ["cdkTable"] }, { kind: "directive", type: CdkColumnDef, selector: "[cdkColumnDef]", inputs: ["cdkColumnDef", "sticky", "stickyEnd"] }, { kind: "directive", type: CdkHeaderCell, selector: "cdk-header-cell, th[cdk-header-cell]" }, { kind: "directive", type: CdkHeaderCellDef, selector: "[cdkHeaderCellDef]" }, { kind: "directive", type: CdkCell, selector: "cdk-cell, td[cdk-cell]" }, { kind: "directive", type: CdkCellDef, selector: "[cdkCellDef]" }, { kind: "directive", type: CdkHeaderRowDef, selector: "[cdkHeaderRowDef]", inputs: ["cdkHeaderRowDef", "cdkHeaderRowDefSticky"] }, { kind: "component", type: CdkHeaderRow, selector: "cdk-header-row, tr[cdk-header-row]" }, { kind: "component", type: CdkRow, selector: "cdk-row, tr[cdk-row]" }, { kind: "directive", type: CdkRowDef, selector: "[cdkRowDef]", inputs: ["cdkRowDefColumns", "cdkRowDefWhen"] }, { kind: "component", type: TableViewPaginationComponent, selector: "table-view-pagination", inputs: ["pageSize", "pageSizeOptions", "entriesCount"], outputs: ["pageChange"] }, { kind: "component", type: LoadingViewComponent, selector: "app-loading-view", inputs: ["headerHeight", "rowHeight", "rowCount"] }, { kind: "component", type: TableViewActions, selector: "table-view-actions", inputs: ["actions"], outputs: ["actionClicked"] }, { kind: "directive", type: TableViewCellDirective, selector: "[tableViewCell]", inputs: ["type", "data"] }, { kind: "component", type: LeIconComponent, selector: "le-icon", inputs: ["name", "size"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
953
|
+
}
|
|
954
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: TableViewComponent, decorators: [{
|
|
955
|
+
type: Component,
|
|
956
|
+
args: [{ selector: 'table-view', imports: [
|
|
957
|
+
CdkTable,
|
|
958
|
+
CdkColumnDef,
|
|
959
|
+
CdkHeaderCell,
|
|
960
|
+
CdkHeaderCellDef,
|
|
961
|
+
CdkCell,
|
|
962
|
+
CdkCellDef,
|
|
963
|
+
CdkHeaderRowDef,
|
|
964
|
+
CdkHeaderRow,
|
|
965
|
+
CdkRow,
|
|
966
|
+
CdkRowDef,
|
|
967
|
+
TableViewPaginationComponent,
|
|
968
|
+
LoadingViewComponent,
|
|
969
|
+
TableViewActions,
|
|
970
|
+
TableViewCellDirective,
|
|
971
|
+
LeIconComponent,
|
|
972
|
+
], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"le-toolbar\">\n @if (node(); as node) {\n <h2>{{ node?.title }}</h2>\n\n @if (node.actions?.tableActions) {\n <table-view-actions\n [actions]=\"node.actions!.tableActions\"\n (actionClicked)=\"onToolbarActionClick($event)\"\n ></table-view-actions>\n }\n }\n</div>\n\n@if (pageSize()) {\n <table-view-pagination\n [pageSize]=\"pageSize()\"\n [pageSizeOptions]=\"pageSizeOptions()\"\n [entriesCount]=\"entriesCount()\"\n (pageChange)=\"onPageChange($event)\"\n ></table-view-pagination>\n}\n\n<div class=\"le-table-container\">\n @if (displayedColumns().length) {\n <table cdk-table [dataSource]=\"data()\" class=\"le-table\" [class.le-table--loading]=\"isLoading()\">\n @for (column of columns(); track column) {\n <ng-container [cdkColumnDef]=\"column.key\">\n <th\n class=\"le-table-header-cell\"\n cdk-header-cell\n *cdkHeaderCellDef\n [tabindex]=\"sortColumnKeys().has(column.key) ? 0 : -1\"\n [class.le-table-header-cell--sortable]=\"sortColumnKeys().has(column.key)\"\n (click)=\"sortColumnKeys().has(column.key) && onSortClick($event, column)\"\n >\n <div class=\"le-cell-content\">\n <ng-template\n tableViewCell\n [data]=\"column.label\"\n [type]=\"column.column_format?.headerTemplate\"\n ></ng-template>\n\n @if (sortColumnKeys().has(column.key)) {\n <div class=\"le-sort-container\">\n @if (sortMap().has(column.key)) {\n <div class=\"le-sort-icon\">\n <i\n class=\"le-sort-arrow\"\n [class.le-sort-arrow--asc]=\"sortMap().get(column.key) === 'asc'\"\n [class.le-sort-arrow--desc]=\"sortMap().get(column.key) === 'desc'\"\n ></i>\n </div>\n\n <div class=\"le-sort-order\">\n @if (sortOrder().has(column.key)) {\n <span>\n {{ sortOrder().get(column.key) }}\n </span>\n }\n </div>\n } @else {\n<!-- <div class=\"le-sort-icon le-sort-icon--unfold\">-->\n<!-- <span>⇅</span>-->\n<!-- </div>-->\n\n <le-icon name=\"sort\" class=\"le-sort-icon le-sort-icon--unfold\"></le-icon>\n }\n </div>\n }\n </div>\n </th>\n\n <td class=\"le-table-cell\" cdk-cell *cdkCellDef=\"let row\">\n <ng-template\n tableViewCell\n [data]=\"row[column.key]\"\n [type]=\"column.column_format?.cellTemplate\"\n ></ng-template>\n </td>\n </ng-container>\n }\n\n <tr cdk-header-row class=\"le-header-row\" *cdkHeaderRowDef=\"displayedColumns()\"></tr>\n <tr\n cdk-row\n class=\"le-table-row\"\n [tabindex]=\"0\"\n [class.le-table-row--clickable]=\"hasRowClickAction()\"\n *cdkRowDef=\"let row; columns: displayedColumns()\"\n (click)=\"onRowClick(row)\"\n ></tr>\n </table>\n }\n</div>\n\n@if (data().count === 0) {\n @if (isLoading()) {\n <app-loading-view [headerHeight]=\"65\" [rowCount]=\"pageSize() || 10\"></app-loading-view>\n } @else {\n <div class=\"no-entities\">\n <span>No Entities</span>\n </div>\n }\n}\n" }]
|
|
973
|
+
}], ctorParameters: () => [] });
|
|
974
|
+
|
|
975
|
+
const isSectionsSchema = (raw) => {
|
|
976
|
+
if (!raw || typeof raw !== 'object')
|
|
977
|
+
return false;
|
|
978
|
+
const r = raw;
|
|
979
|
+
return Boolean(r.sections || // direct sections array
|
|
980
|
+
r.control?.type === 'sections' || // control.type === 'sections'
|
|
981
|
+
r.control?.sections || // control.sections
|
|
982
|
+
r.meta?.sections);
|
|
983
|
+
};
|
|
984
|
+
const adaptForm = (raw) => {
|
|
985
|
+
if (isSectionsSchema(raw)) {
|
|
986
|
+
return adaptSections(raw);
|
|
987
|
+
}
|
|
988
|
+
return adaptOld(raw);
|
|
989
|
+
};
|
|
990
|
+
|
|
991
|
+
class FormRendererComponent {
|
|
992
|
+
renderer = inject(Renderer2);
|
|
993
|
+
ref = inject(ElementRef);
|
|
994
|
+
destroyRef = inject(DestroyRef);
|
|
995
|
+
styleRef = this.renderer.createElement('style');
|
|
996
|
+
engine = input.required();
|
|
997
|
+
sections = input.required();
|
|
998
|
+
topLevelControls = input([]);
|
|
999
|
+
customCss = input();
|
|
1000
|
+
constructor() {
|
|
1001
|
+
this.renderer.appendChild(this.ref.nativeElement, this.styleRef);
|
|
1002
|
+
this.destroyRef.onDestroy(() => {
|
|
1003
|
+
this.renderer.removeChild(this.ref.nativeElement, this.styleRef);
|
|
1004
|
+
});
|
|
1005
|
+
effect(() => {
|
|
1006
|
+
this.styleRef.textContent = this.customCss() ?? '';
|
|
1007
|
+
});
|
|
1008
|
+
}
|
|
1009
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: FormRendererComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1010
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.21", type: FormRendererComponent, isStandalone: true, selector: "le-form-renderer", inputs: { engine: { classPropertyName: "engine", publicName: "engine", isSignal: true, isRequired: true, transformFunction: null }, sections: { classPropertyName: "sections", publicName: "sections", isSignal: true, isRequired: true, transformFunction: null }, topLevelControls: { classPropertyName: "topLevelControls", publicName: "topLevelControls", isSignal: true, isRequired: false, transformFunction: null }, customCss: { classPropertyName: "customCss", publicName: "customCss", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div class=\"le-form-container\">\n @for (section of sections(); track section.id) {\n <section class=\"le-section\">\n <div class=\"le-section-title\">\n @if (section.label) {\n <h3>{{ section.label }}</h3>\n }\n </div>\n\n <div class=\"le-section-controls\">\n @for (control of section.controls; track control) {\n <fe-field [engine]=\"engine()\" [control]=\"control\"></fe-field>\n }\n </div>\n </section>\n }\n\n @if (topLevelControls()?.length) {\n <section class=\"le-top-level-controls\">\n @for (control of topLevelControls(); track control) {\n <fe-field [engine]=\"engine()\" [control]=\"control\"></fe-field>\n }\n </section>\n }\n</div>\n", dependencies: [{ kind: "component", type: FeFieldHost, selector: "fe-field", inputs: ["engine", "control"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1011
|
+
}
|
|
1012
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: FormRendererComponent, decorators: [{
|
|
1013
|
+
type: Component,
|
|
1014
|
+
args: [{ selector: 'le-form-renderer', imports: [FeFieldHost], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"le-form-container\">\n @for (section of sections(); track section.id) {\n <section class=\"le-section\">\n <div class=\"le-section-title\">\n @if (section.label) {\n <h3>{{ section.label }}</h3>\n }\n </div>\n\n <div class=\"le-section-controls\">\n @for (control of section.controls; track control) {\n <fe-field [engine]=\"engine()\" [control]=\"control\"></fe-field>\n }\n </div>\n </section>\n }\n\n @if (topLevelControls()?.length) {\n <section class=\"le-top-level-controls\">\n @for (control of topLevelControls(); track control) {\n <fe-field [engine]=\"engine()\" [control]=\"control\"></fe-field>\n }\n </section>\n }\n</div>\n" }]
|
|
1015
|
+
}], ctorParameters: () => [] });
|
|
1016
|
+
|
|
1017
|
+
/**
|
|
1018
|
+
* Handle placeholders in onSuccess callback.
|
|
1019
|
+
*/
|
|
1020
|
+
const isPlaceholder = (value) => {
|
|
1021
|
+
return typeof value === 'string' && value.startsWith('{') && value.endsWith('}');
|
|
1022
|
+
};
|
|
1023
|
+
/**
|
|
1024
|
+
* @param value "{email_verification_code_field}"
|
|
1025
|
+
* @returns "email_verification_code_field"
|
|
1026
|
+
*/
|
|
1027
|
+
const getPlaceholderValue = (value) => {
|
|
1028
|
+
return value.slice(1, -1);
|
|
1029
|
+
};
|
|
1030
|
+
/**
|
|
1031
|
+
* @param body {"email_verification_code": "{email_verification_code_field}"}
|
|
1032
|
+
* @returns ["email_verification_code_field"]
|
|
1033
|
+
*/
|
|
1034
|
+
const mapActionBodyToFieldsArray = (body) => {
|
|
1035
|
+
const result = [];
|
|
1036
|
+
for (const placeholder of Object.values(body)) {
|
|
1037
|
+
if (isPlaceholder(placeholder)) {
|
|
1038
|
+
result.push(getPlaceholderValue(placeholder));
|
|
1039
|
+
}
|
|
1040
|
+
}
|
|
1041
|
+
return result;
|
|
1042
|
+
};
|
|
1043
|
+
/**
|
|
1044
|
+
* @param body {"email_verification_code": "{email_verification_code_field}"}
|
|
1045
|
+
* @param errors {"email_verification_code": "Invalid email verification code"}
|
|
1046
|
+
* @returns true if body fields have errors
|
|
1047
|
+
*/
|
|
1048
|
+
const isErrorCorrespondActionBody = (body, errors) => {
|
|
1049
|
+
const bodyFields = mapActionBodyToFieldsArray(body);
|
|
1050
|
+
return bodyFields.some((field) => errors[field] !== undefined);
|
|
1051
|
+
};
|
|
1052
|
+
const getValueByPath = (obj = {}, path) => {
|
|
1053
|
+
if (path.includes('.')) {
|
|
1054
|
+
return path.split('.').reduce((acc, key) => acc && acc[key], obj);
|
|
1055
|
+
}
|
|
1056
|
+
return obj[path];
|
|
1057
|
+
};
|
|
1058
|
+
const mapResponseToRequestBody = (bodyModel = {}, values = {}) => {
|
|
1059
|
+
const result = {};
|
|
1060
|
+
for (const [key, placeholder] of Object.entries(bodyModel)) {
|
|
1061
|
+
if (isPlaceholder(placeholder)) {
|
|
1062
|
+
const path = getPlaceholderValue(placeholder);
|
|
1063
|
+
const value = getValueByPath(values, path);
|
|
1064
|
+
if (value !== null && value !== undefined && value !== '') {
|
|
1065
|
+
result[key] = value;
|
|
1066
|
+
}
|
|
1067
|
+
}
|
|
1068
|
+
else {
|
|
1069
|
+
result[key] = placeholder;
|
|
1070
|
+
}
|
|
1071
|
+
}
|
|
1072
|
+
return result;
|
|
1073
|
+
};
|
|
1074
|
+
|
|
1075
|
+
class ToastListComponent {
|
|
1076
|
+
toastService = inject(LeToastService);
|
|
1077
|
+
toasts = this.toastService.toasts;
|
|
1078
|
+
onButtonClick(actions) {
|
|
1079
|
+
actions.forEach((action) => this.toastService.processAction(action));
|
|
1080
|
+
}
|
|
1081
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: ToastListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1082
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.21", type: ToastListComponent, isStandalone: true, selector: "ng-component", ngImport: i0, template: "@if (toasts().length) {\n <div class=\"le-toast-list\">\n @for (toast of toasts(); track toast.id) {\n <div\n class=\"le-toast\"\n [class.le-toast--success]=\"toast.type === 'success'\"\n [class.le-toast--info]=\"toast.type === 'info'\"\n [class.le-toast--warning]=\"toast.type === 'warning'\"\n [class.le-toast--error]=\"toast.type === 'error'\"\n >\n <div class=\"le-toast-text-list\">\n @for (control of toast.controls; track control) {\n @if (control.type === 'text') {\n <p class=\"le-toast-text\">\n {{ control.value }}\n </p>\n }\n }\n </div>\n\n <div class=\"le-toast-button-list\">\n @for (control of toast.controls; track control) {\n @if (control.type === 'button') {\n <button\n class=\"le-button le-button-stroked\"\n [class.le-button--success]=\"toast.type === 'success'\"\n [class.le-button--info]=\"toast.type === 'info'\"\n [class.le-button--warning]=\"toast.type === 'warning'\"\n [class.le-button--error]=\"toast.type === 'error'\"\n (click)=\"onButtonClick(control.actions)\"\n >\n {{ control.label }}\n </button>\n }\n }\n </div>\n </div>\n }\n </div>\n}\n" });
|
|
1083
|
+
}
|
|
1084
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: ToastListComponent, decorators: [{
|
|
1085
|
+
type: Component,
|
|
1086
|
+
args: [{ template: "@if (toasts().length) {\n <div class=\"le-toast-list\">\n @for (toast of toasts(); track toast.id) {\n <div\n class=\"le-toast\"\n [class.le-toast--success]=\"toast.type === 'success'\"\n [class.le-toast--info]=\"toast.type === 'info'\"\n [class.le-toast--warning]=\"toast.type === 'warning'\"\n [class.le-toast--error]=\"toast.type === 'error'\"\n >\n <div class=\"le-toast-text-list\">\n @for (control of toast.controls; track control) {\n @if (control.type === 'text') {\n <p class=\"le-toast-text\">\n {{ control.value }}\n </p>\n }\n }\n </div>\n\n <div class=\"le-toast-button-list\">\n @for (control of toast.controls; track control) {\n @if (control.type === 'button') {\n <button\n class=\"le-button le-button-stroked\"\n [class.le-button--success]=\"toast.type === 'success'\"\n [class.le-button--info]=\"toast.type === 'info'\"\n [class.le-button--warning]=\"toast.type === 'warning'\"\n [class.le-button--error]=\"toast.type === 'error'\"\n (click)=\"onButtonClick(control.actions)\"\n >\n {{ control.label }}\n </button>\n }\n }\n </div>\n </div>\n }\n </div>\n}\n" }]
|
|
1087
|
+
}] });
|
|
1088
|
+
|
|
1089
|
+
let ID = 100_000_000;
|
|
1090
|
+
class LeToastService {
|
|
1091
|
+
overlayRef;
|
|
1092
|
+
overlay = inject(Overlay);
|
|
1093
|
+
_toasts = signal([]);
|
|
1094
|
+
toasts = this._toasts.asReadonly();
|
|
1095
|
+
constructor() {
|
|
1096
|
+
effect(() => {
|
|
1097
|
+
const toasts = this._toasts();
|
|
1098
|
+
if (toasts.length > 0) {
|
|
1099
|
+
this.show();
|
|
1100
|
+
}
|
|
1101
|
+
else {
|
|
1102
|
+
this.hide();
|
|
1103
|
+
}
|
|
1104
|
+
});
|
|
1105
|
+
}
|
|
1106
|
+
notify(toast) {
|
|
1107
|
+
this._toasts.update((toasts) => [...toasts, toast]);
|
|
1108
|
+
}
|
|
1109
|
+
warn(...messages) {
|
|
1110
|
+
this.notify(this.buildToast('warning', messages));
|
|
1111
|
+
}
|
|
1112
|
+
info(...messages) {
|
|
1113
|
+
this.notify(this.buildToast('info', messages));
|
|
1114
|
+
}
|
|
1115
|
+
success(...messages) {
|
|
1116
|
+
this.notify(this.buildToast('success', messages));
|
|
1117
|
+
}
|
|
1118
|
+
error(...messages) {
|
|
1119
|
+
this.notify(this.buildToast('error', messages));
|
|
1120
|
+
}
|
|
1121
|
+
remove(id) {
|
|
1122
|
+
this._toasts.update((toasts) => toasts.filter((toast) => toast.id !== id));
|
|
1123
|
+
}
|
|
1124
|
+
processAction(action) {
|
|
1125
|
+
if (action.type === 'close_popup') {
|
|
1126
|
+
this.remove(action.target);
|
|
1127
|
+
}
|
|
1128
|
+
}
|
|
1129
|
+
show() {
|
|
1130
|
+
if (this.overlayRef)
|
|
1131
|
+
return;
|
|
1132
|
+
this.overlayRef = this.overlay.create({
|
|
1133
|
+
positionStrategy: this.overlay.position().global().right().top(),
|
|
1134
|
+
scrollStrategy: this.overlay.scrollStrategies.reposition(),
|
|
1135
|
+
});
|
|
1136
|
+
this.overlayRef.attach(new ComponentPortal(ToastListComponent));
|
|
1137
|
+
}
|
|
1138
|
+
hide() {
|
|
1139
|
+
this.overlayRef?.dispose();
|
|
1140
|
+
this.overlayRef = undefined;
|
|
1141
|
+
}
|
|
1142
|
+
buildToast(type, messages) {
|
|
1143
|
+
const id = `${type}_${ID++}`;
|
|
1144
|
+
const textControls = messages.map((message) => ({
|
|
1145
|
+
type: 'text',
|
|
1146
|
+
value: message,
|
|
1147
|
+
}));
|
|
1148
|
+
const buttonControl = {
|
|
1149
|
+
type: 'button',
|
|
1150
|
+
label: 'Ok',
|
|
1151
|
+
actions: [{ type: 'close_popup', target: id }],
|
|
1152
|
+
};
|
|
1153
|
+
return {
|
|
1154
|
+
id,
|
|
1155
|
+
type,
|
|
1156
|
+
controls: [...textControls, buttonControl],
|
|
1157
|
+
};
|
|
1158
|
+
}
|
|
1159
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: LeToastService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
1160
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: LeToastService, providedIn: 'root' });
|
|
1161
|
+
}
|
|
1162
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: LeToastService, decorators: [{
|
|
1163
|
+
type: Injectable,
|
|
1164
|
+
args: [{
|
|
1165
|
+
providedIn: 'root',
|
|
1166
|
+
}]
|
|
1167
|
+
}], ctorParameters: () => [] });
|
|
1168
|
+
|
|
1169
|
+
/**
|
|
1170
|
+
* Add or update URL parameter
|
|
1171
|
+
*/
|
|
1172
|
+
const addUrlParameter = (url, paramName, paramValue) => {
|
|
1173
|
+
try {
|
|
1174
|
+
const urlObj = new URL(url);
|
|
1175
|
+
urlObj.searchParams.set(paramName, paramValue);
|
|
1176
|
+
return urlObj.toString();
|
|
1177
|
+
}
|
|
1178
|
+
catch {
|
|
1179
|
+
// If URL parsing fails, try simple string manipulation
|
|
1180
|
+
const separator = url.includes('?') ? '&' : '?';
|
|
1181
|
+
return `${url}${separator}${paramName}=${encodeURIComponent(paramValue)}`;
|
|
1182
|
+
}
|
|
1183
|
+
};
|
|
1184
|
+
/**
|
|
1185
|
+
* Get preview URL for image (with disposition_type=inline)
|
|
1186
|
+
*/
|
|
1187
|
+
const getPreviewUrl = (downloadUrl) => {
|
|
1188
|
+
return addUrlParameter(downloadUrl, 'disposition_type', 'inline');
|
|
1189
|
+
};
|
|
1190
|
+
/**
|
|
1191
|
+
* Clear file data from 'unsafe:' prefix
|
|
1192
|
+
*/
|
|
1193
|
+
const clearFileData = (data) => {
|
|
1194
|
+
return data.startsWith('unsafe:') ? data.substring(7) : data;
|
|
1195
|
+
};
|
|
1196
|
+
/**
|
|
1197
|
+
* If attachment is an image
|
|
1198
|
+
*/
|
|
1199
|
+
const isImageAttachment = (attachment) => {
|
|
1200
|
+
return !!(attachment.mimetype && attachment.mimetype.toLowerCase().includes('image'));
|
|
1201
|
+
};
|
|
1202
|
+
const isDownloadFileString = (str) => {
|
|
1203
|
+
return isUrlString(str) && str.includes('/download-file/');
|
|
1204
|
+
};
|
|
1205
|
+
const isUrlString = (str) => {
|
|
1206
|
+
return str.startsWith('http://') || str.startsWith('https://');
|
|
1207
|
+
};
|
|
1208
|
+
const isBase64String = (str) => {
|
|
1209
|
+
return str.startsWith('base64,');
|
|
1210
|
+
};
|
|
1211
|
+
const isDataUrlString = (str) => {
|
|
1212
|
+
return str.startsWith('data:');
|
|
1213
|
+
};
|
|
1214
|
+
/**
|
|
1215
|
+
* Is attachment reference
|
|
1216
|
+
*/
|
|
1217
|
+
const isAttachmentRef = (attachment) => {
|
|
1218
|
+
return (!!attachment.ref &&
|
|
1219
|
+
!!attachment.ref.resource &&
|
|
1220
|
+
!!attachment.ref.class_name &&
|
|
1221
|
+
!!attachment.ref.object_id &&
|
|
1222
|
+
!!attachment.ref.object_version);
|
|
1223
|
+
};
|
|
1224
|
+
/**
|
|
1225
|
+
* Get attachment url
|
|
1226
|
+
*/
|
|
1227
|
+
const getAttachmentUrl = (attachment) => {
|
|
1228
|
+
return `${attachment.ref.resource}%23${attachment.ref.class_name}%3A${attachment.ref.class_version}%3A${attachment.ref.object_id}%3A${attachment.ref.object_version}`;
|
|
1229
|
+
};
|
|
1230
|
+
|
|
1231
|
+
class FormViewAttachmentService {
|
|
1232
|
+
apiService = inject(LEApiService);
|
|
1233
|
+
_cache = new Map();
|
|
1234
|
+
async resolve(attachment) {
|
|
1235
|
+
if (!attachment.ref)
|
|
1236
|
+
return '';
|
|
1237
|
+
const objectId = attachment.ref.object_id;
|
|
1238
|
+
if (!this._cache.has(objectId)) {
|
|
1239
|
+
const fileInfo = await this.fetchAttachmentData(attachment);
|
|
1240
|
+
if (typeof fileInfo?.data === 'string') {
|
|
1241
|
+
const normalized = await this.normalizeFileData(fileInfo.data, fileInfo.filename, attachment);
|
|
1242
|
+
this._cache.set(objectId, normalized);
|
|
1243
|
+
}
|
|
1244
|
+
}
|
|
1245
|
+
return this._cache.get(objectId)?.data ?? '';
|
|
1246
|
+
}
|
|
1247
|
+
async download(attachment) {
|
|
1248
|
+
const fileInfo = await this.resolveAttachmentData(attachment);
|
|
1249
|
+
if (!fileInfo)
|
|
1250
|
+
return;
|
|
1251
|
+
const file = await firstValueFrom(this.apiService.getBlob(fileInfo.data));
|
|
1252
|
+
this.downloadWithAnchor(file, fileInfo.filename);
|
|
1253
|
+
}
|
|
1254
|
+
async resolveAttachmentData(attachment) {
|
|
1255
|
+
if (!attachment?.ref?.object_id)
|
|
1256
|
+
return null;
|
|
1257
|
+
if (this._cache.has(attachment.ref.object_id)) {
|
|
1258
|
+
const cached = this._cache.get(attachment.ref.object_id);
|
|
1259
|
+
return {
|
|
1260
|
+
data: cached.originalUrl || cached.data,
|
|
1261
|
+
filename: cached.filename,
|
|
1262
|
+
};
|
|
1263
|
+
}
|
|
1264
|
+
if (isAttachmentRef(attachment)) {
|
|
1265
|
+
return this.fetchAttachmentData(attachment);
|
|
1266
|
+
}
|
|
1267
|
+
return null;
|
|
1268
|
+
}
|
|
1269
|
+
async fetchAttachmentData(attachment) {
|
|
1270
|
+
const response = await firstValueFrom(this.apiService.getObjectByAddress(getAttachmentUrl(attachment), false, false));
|
|
1271
|
+
const row = response?.rows?.[0];
|
|
1272
|
+
if (!row?.data)
|
|
1273
|
+
return null;
|
|
1274
|
+
return {
|
|
1275
|
+
data: row.data,
|
|
1276
|
+
filename: row.filename || attachment.filename || 'file',
|
|
1277
|
+
};
|
|
1278
|
+
}
|
|
1279
|
+
async normalizeFileData(data, filename, attachment) {
|
|
1280
|
+
const cleanData = clearFileData(data);
|
|
1281
|
+
const result = {
|
|
1282
|
+
data: '',
|
|
1283
|
+
filename: filename,
|
|
1284
|
+
isUrl: false,
|
|
1285
|
+
};
|
|
1286
|
+
if (isDownloadFileString(cleanData) && isImageAttachment(attachment)) {
|
|
1287
|
+
// For images with download-file URLs, create preview URL with disposition_type=inline
|
|
1288
|
+
result.data = await firstValueFrom(this.apiService.getBlob(getPreviewUrl(cleanData)));
|
|
1289
|
+
result.isUrl = true;
|
|
1290
|
+
result.originalUrl = cleanData;
|
|
1291
|
+
}
|
|
1292
|
+
else if (isUrlString(cleanData)) {
|
|
1293
|
+
// Regular URL (not download-file) - use directly
|
|
1294
|
+
result.data = cleanData;
|
|
1295
|
+
result.originalUrl = cleanData;
|
|
1296
|
+
result.isUrl = true;
|
|
1297
|
+
}
|
|
1298
|
+
else if (isDataUrlString(cleanData)) {
|
|
1299
|
+
// Already a data URL
|
|
1300
|
+
result.data = cleanData;
|
|
1301
|
+
}
|
|
1302
|
+
else if (isBase64String(cleanData)) {
|
|
1303
|
+
// Legacy format "base64,actualdata" (for backward compatibility)
|
|
1304
|
+
result.data = `data:${attachment.mimetype ?? 'application/octet-stream'};${cleanData}`;
|
|
1305
|
+
}
|
|
1306
|
+
else {
|
|
1307
|
+
// New format: pure base64 data without prefix (like in old integration)
|
|
1308
|
+
result.data = `data:${attachment.mimetype ?? 'application/octet-stream'};base64,${cleanData}`;
|
|
1309
|
+
}
|
|
1310
|
+
return result;
|
|
1311
|
+
}
|
|
1312
|
+
downloadWithAnchor(file, filename) {
|
|
1313
|
+
const anchor = document.createElement('a');
|
|
1314
|
+
anchor.href = file;
|
|
1315
|
+
anchor.download = filename || 'File';
|
|
1316
|
+
anchor.click();
|
|
1317
|
+
URL.revokeObjectURL(file);
|
|
1318
|
+
}
|
|
1319
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: FormViewAttachmentService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
1320
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: FormViewAttachmentService });
|
|
1321
|
+
}
|
|
1322
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: FormViewAttachmentService, decorators: [{
|
|
1323
|
+
type: Injectable
|
|
1324
|
+
}] });
|
|
1325
|
+
|
|
1326
|
+
class FormViewComponent {
|
|
1327
|
+
apiService = inject(LEApiService);
|
|
1328
|
+
dataService = inject(LEDataService);
|
|
1329
|
+
attachmentService = inject(FormViewAttachmentService);
|
|
1330
|
+
viewportScroller = inject(ViewportScroller);
|
|
1331
|
+
toastService = inject(LeToastService);
|
|
1332
|
+
_isLoading = signal(false);
|
|
1333
|
+
_form = signal(null);
|
|
1334
|
+
_sections = signal([]);
|
|
1335
|
+
_topLevelControls = signal([]);
|
|
1336
|
+
_engine = signal(null);
|
|
1337
|
+
_actionHandlers = {
|
|
1338
|
+
invoke: (action) => {
|
|
1339
|
+
const engine = this._engine();
|
|
1340
|
+
let body = {};
|
|
1341
|
+
if (!engine) {
|
|
1342
|
+
return of(null);
|
|
1343
|
+
}
|
|
1344
|
+
if (!action.async) {
|
|
1345
|
+
engine.markAllTouched();
|
|
1346
|
+
}
|
|
1347
|
+
engine.validate();
|
|
1348
|
+
const hasError = isErrorCorrespondActionBody(action.body ?? {}, engine.status.errors);
|
|
1349
|
+
if (hasError) {
|
|
1350
|
+
return of(null);
|
|
1351
|
+
}
|
|
1352
|
+
if (action.body) {
|
|
1353
|
+
body = mapResponseToRequestBody(action.body, engine.values.getAll());
|
|
1354
|
+
}
|
|
1355
|
+
if (!action.async) {
|
|
1356
|
+
this._isLoading.set(true);
|
|
1357
|
+
}
|
|
1358
|
+
return this.dataService
|
|
1359
|
+
.request(action.method, action.url, body)
|
|
1360
|
+
.pipe(tap((response) => {
|
|
1361
|
+
if (action.onSuccess && response.ok) {
|
|
1362
|
+
this.processActionList(action.onSuccess, response.body);
|
|
1363
|
+
}
|
|
1364
|
+
else if (action.onError && !response.ok) {
|
|
1365
|
+
this.processActionList(action.onError);
|
|
1366
|
+
}
|
|
1367
|
+
else {
|
|
1368
|
+
this._isLoading.set(false);
|
|
1369
|
+
}
|
|
1370
|
+
}), map(() => null), catchError(() => {
|
|
1371
|
+
if (action.onError) {
|
|
1372
|
+
this.processActionList(action.onError);
|
|
1373
|
+
}
|
|
1374
|
+
return of(null);
|
|
1375
|
+
}));
|
|
1376
|
+
},
|
|
1377
|
+
update_form: (action) => {
|
|
1378
|
+
const node = this.mapUpdateFormActionToFormNode(action.control_source);
|
|
1379
|
+
if (node) {
|
|
1380
|
+
this.dataService.setView(node);
|
|
1381
|
+
}
|
|
1382
|
+
return of(null);
|
|
1383
|
+
},
|
|
1384
|
+
update_value: (action, response) => {
|
|
1385
|
+
return of(action).pipe(filter((action) => isPlaceholder(action.value)), map((action) => mapResponseToRequestBody({ [action.field_id]: action.value }, { response })), tap((result) => {
|
|
1386
|
+
if (result[action.field_id]) {
|
|
1387
|
+
this._engine()?.values.set(action.field_id, result[action.field_id]);
|
|
1388
|
+
}
|
|
1389
|
+
}), map(() => null));
|
|
1390
|
+
},
|
|
1391
|
+
scroll_top: () => {
|
|
1392
|
+
this.viewportScroller.scrollToPosition([0, 0]);
|
|
1393
|
+
return of(null);
|
|
1394
|
+
},
|
|
1395
|
+
show_popup: (action) => {
|
|
1396
|
+
this.toastService.notify({
|
|
1397
|
+
...action.item,
|
|
1398
|
+
type: 'success',
|
|
1399
|
+
});
|
|
1400
|
+
return of(null);
|
|
1401
|
+
},
|
|
1402
|
+
open_url: (action) => {
|
|
1403
|
+
window.open(action.url, '_blank');
|
|
1404
|
+
return of(null);
|
|
1405
|
+
},
|
|
1406
|
+
download: (action) => {
|
|
1407
|
+
this.attachmentService.download(action.payload);
|
|
1408
|
+
return of(null);
|
|
1409
|
+
},
|
|
1410
|
+
navigate_to_section: (action) => {
|
|
1411
|
+
this.dataService.navigateByNodeId(action.section_id);
|
|
1412
|
+
return of(null);
|
|
1413
|
+
},
|
|
1414
|
+
};
|
|
1415
|
+
node = input.required();
|
|
1416
|
+
isLoading = this._isLoading.asReadonly();
|
|
1417
|
+
data = computed(() => {
|
|
1418
|
+
const engine = this._engine();
|
|
1419
|
+
const sections = this._sections();
|
|
1420
|
+
const topLevelControls = this._topLevelControls();
|
|
1421
|
+
const customCss = this.dataService.customCss() ?? '';
|
|
1422
|
+
if (!engine || !sections)
|
|
1423
|
+
return null;
|
|
1424
|
+
return {
|
|
1425
|
+
engine,
|
|
1426
|
+
sections,
|
|
1427
|
+
customCss,
|
|
1428
|
+
topLevelControls,
|
|
1429
|
+
};
|
|
1430
|
+
});
|
|
1431
|
+
constructor() {
|
|
1432
|
+
effect(() => {
|
|
1433
|
+
const node = this.node();
|
|
1434
|
+
if (node) {
|
|
1435
|
+
this.getFormData(node).subscribe();
|
|
1436
|
+
}
|
|
1437
|
+
});
|
|
1438
|
+
effect(() => {
|
|
1439
|
+
const form = this._form();
|
|
1440
|
+
if (!form)
|
|
1441
|
+
return;
|
|
1442
|
+
untracked(() => {
|
|
1443
|
+
this.init(form);
|
|
1444
|
+
});
|
|
1445
|
+
});
|
|
1446
|
+
}
|
|
1447
|
+
init(form) {
|
|
1448
|
+
this._sections.set(this.sortSections(form.sections));
|
|
1449
|
+
this._topLevelControls.set(form.controls ?? []);
|
|
1450
|
+
const resolvers = {
|
|
1451
|
+
attachment: (value) => this.attachmentService.resolve(value),
|
|
1452
|
+
objectLatest: (className) => firstValueFrom(this.dataService.getObjectByClassName(className)),
|
|
1453
|
+
};
|
|
1454
|
+
this._engine.set(createEngine(form, {}, resolvers));
|
|
1455
|
+
// this._engine()?.on('valueChanges', (value) => {
|
|
1456
|
+
// console.log('Value Changes', value);
|
|
1457
|
+
// // this.cdr.markForCheck();
|
|
1458
|
+
// });
|
|
1459
|
+
// this._engine()?.on('fieldStateChanges', (state) => {
|
|
1460
|
+
// console.log('Field State Changes', state);
|
|
1461
|
+
// // this.cdr.markForCheck();
|
|
1462
|
+
// });
|
|
1463
|
+
this._engine()?.on('action', ({ action }) => {
|
|
1464
|
+
this.processActionList(action.actions);
|
|
1465
|
+
});
|
|
1466
|
+
}
|
|
1467
|
+
processAction(action, response) {
|
|
1468
|
+
return this._actionHandlers[action.type](action, response);
|
|
1469
|
+
}
|
|
1470
|
+
sortSections(sections) {
|
|
1471
|
+
return [...sections].sort((a, b) => {
|
|
1472
|
+
const orderA = a.order ?? 0;
|
|
1473
|
+
const orderB = b.order ?? 0;
|
|
1474
|
+
return orderA - orderB;
|
|
1475
|
+
});
|
|
1476
|
+
}
|
|
1477
|
+
getFormData(node) {
|
|
1478
|
+
if (node.controlSource?.kind === 'transaction') {
|
|
1479
|
+
this._isLoading.set(true);
|
|
1480
|
+
return this.apiService
|
|
1481
|
+
.executeTransaction(node.controlSource.entity, node.controlSource.params ?? {})
|
|
1482
|
+
.pipe(tap((response) => {
|
|
1483
|
+
this._form.set(adaptForm(response));
|
|
1484
|
+
this._isLoading.set(false);
|
|
1485
|
+
}), map(() => null), catchError((error) => {
|
|
1486
|
+
console.error(error);
|
|
1487
|
+
this._isLoading.set(false);
|
|
1488
|
+
return of(null);
|
|
1489
|
+
}));
|
|
1490
|
+
}
|
|
1491
|
+
throw new Error(`Unsupported control source kind ${node.controlSource?.kind}`);
|
|
1492
|
+
}
|
|
1493
|
+
mapUpdateFormActionToFormNode(source) {
|
|
1494
|
+
if (source.dynamic_value) {
|
|
1495
|
+
return {
|
|
1496
|
+
id: source.dynamic_value.entity_name,
|
|
1497
|
+
type: 'form',
|
|
1498
|
+
controlSource: {
|
|
1499
|
+
kind: source.dynamic_value.type,
|
|
1500
|
+
entity: source.dynamic_value.entity_name,
|
|
1501
|
+
params: source.dynamic_value.body ?? {},
|
|
1502
|
+
},
|
|
1503
|
+
};
|
|
1504
|
+
}
|
|
1505
|
+
return null;
|
|
1506
|
+
}
|
|
1507
|
+
processActionList(items, response) {
|
|
1508
|
+
from(items)
|
|
1509
|
+
.pipe(concatMap((a) => this.processAction(a, response)), finalize(() => {
|
|
1510
|
+
this._isLoading.set(false);
|
|
1511
|
+
}))
|
|
1512
|
+
.subscribe();
|
|
1513
|
+
}
|
|
1514
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: FormViewComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1515
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.21", type: FormViewComponent, isStandalone: true, selector: "form-view", inputs: { node: { classPropertyName: "node", publicName: "node", isSignal: true, isRequired: true, transformFunction: null } }, providers: [FormViewAttachmentService], ngImport: i0, template: "<h2>{{ node()?.title }}</h2>\n\n@if (isLoading()) {\n <app-loading-view [rowCount]=\"5\"></app-loading-view>\n} @else {\n @if (data(); as data) {\n <le-form-renderer\n [engine]=\"data.engine\"\n [sections]=\"data.sections\"\n [customCss]=\"data.customCss\"\n [topLevelControls]=\"data.topLevelControls\"\n ></le-form-renderer>\n }\n}\n", dependencies: [{ kind: "component", type: LoadingViewComponent, selector: "app-loading-view", inputs: ["headerHeight", "rowHeight", "rowCount"] }, { kind: "component", type: FormRendererComponent, selector: "le-form-renderer", inputs: ["engine", "sections", "topLevelControls", "customCss"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1516
|
+
}
|
|
1517
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: FormViewComponent, decorators: [{
|
|
1518
|
+
type: Component,
|
|
1519
|
+
args: [{ selector: 'form-view', imports: [LoadingViewComponent, FormRendererComponent], changeDetection: ChangeDetectionStrategy.OnPush, providers: [FormViewAttachmentService], template: "<h2>{{ node()?.title }}</h2>\n\n@if (isLoading()) {\n <app-loading-view [rowCount]=\"5\"></app-loading-view>\n} @else {\n @if (data(); as data) {\n <le-form-renderer\n [engine]=\"data.engine\"\n [sections]=\"data.sections\"\n [customCss]=\"data.customCss\"\n [topLevelControls]=\"data.topLevelControls\"\n ></le-form-renderer>\n }\n}\n" }]
|
|
1520
|
+
}], ctorParameters: () => [] });
|
|
1521
|
+
|
|
1522
|
+
class SectionComponent {
|
|
1523
|
+
node = input.required();
|
|
1524
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: SectionComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1525
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.21", type: SectionComponent, isStandalone: true, selector: "section-view", inputs: { node: { classPropertyName: "node", publicName: "node", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "@for (child of node().children; track child.id) {\n <le-node [node]=\"child\"></le-node>\n}\n", dependencies: [{ kind: "component", type: i0.forwardRef(() => NodeComponent), selector: "le-node", inputs: ["node"] }] });
|
|
1526
|
+
}
|
|
1527
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: SectionComponent, decorators: [{
|
|
1528
|
+
type: Component,
|
|
1529
|
+
args: [{ selector: 'section-view', imports: [forwardRef(() => NodeComponent)], template: "@for (child of node().children; track child.id) {\n <le-node [node]=\"child\"></le-node>\n}\n" }]
|
|
1530
|
+
}] });
|
|
1531
|
+
|
|
1532
|
+
class GridColViewComponent {
|
|
1533
|
+
node = input.required();
|
|
1534
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: GridColViewComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1535
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.21", type: GridColViewComponent, isStandalone: true, selector: "grid-col-view", inputs: { node: { classPropertyName: "node", publicName: "node", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "@for (child of node().children; track child.id) {\n <le-node [node]=\"child\"></le-node>\n}\n", dependencies: [{ kind: "component", type: i0.forwardRef(() => NodeComponent), selector: "le-node", inputs: ["node"] }] });
|
|
1536
|
+
}
|
|
1537
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: GridColViewComponent, decorators: [{
|
|
1538
|
+
type: Component,
|
|
1539
|
+
args: [{ selector: 'grid-col-view', imports: [forwardRef(() => NodeComponent)], template: "@for (child of node().children; track child.id) {\n <le-node [node]=\"child\"></le-node>\n}\n" }]
|
|
1540
|
+
}] });
|
|
1541
|
+
|
|
1542
|
+
class NodeComponent {
|
|
1543
|
+
node = input.required();
|
|
1544
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: NodeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1545
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.21", type: NodeComponent, isStandalone: true, selector: "le-node", inputs: { node: { classPropertyName: "node", publicName: "node", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "@if (node(); as node) {\n @switch (node.type) {\n @case ('section') {\n <section-view [node]=\"node\"></section-view>\n }\n @case ('grid') {\n <grid-view [node]=\"node\"></grid-view>\n }\n @case ('grid_col') {\n <grid-col-view [node]=\"node\"></grid-col-view>\n }\n @case ('table') {\n <table-view [node]=\"node\"></table-view>\n }\n @case ('chart') {\n <chart-view [node]=\"node\"></chart-view>\n }\n @case ('form') {\n <form-view [node]=\"node\"></form-view>\n }\n }\n}\n", dependencies: [{ kind: "component", type: i0.forwardRef(() => ChartViewComponent), selector: "chart-view", inputs: ["node"] }, { kind: "component", type: i0.forwardRef(() => GridComponent), selector: "grid-view", inputs: ["node"] }, { kind: "component", type: i0.forwardRef(() => TableViewComponent), selector: "table-view", inputs: ["node"] }, { kind: "component", type: i0.forwardRef(() => FormViewComponent), selector: "form-view", inputs: ["node"] }, { kind: "component", type: i0.forwardRef(() => GridColViewComponent), selector: "grid-col-view", inputs: ["node"] }, { kind: "component", type: i0.forwardRef(() => SectionComponent), selector: "section-view", inputs: ["node"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1546
|
+
}
|
|
1547
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: NodeComponent, decorators: [{
|
|
1548
|
+
type: Component,
|
|
1549
|
+
args: [{ selector: 'le-node', imports: [
|
|
1550
|
+
ChartViewComponent,
|
|
1551
|
+
GridComponent,
|
|
1552
|
+
TableViewComponent,
|
|
1553
|
+
FormViewComponent,
|
|
1554
|
+
GridColViewComponent,
|
|
1555
|
+
forwardRef(() => SectionComponent),
|
|
1556
|
+
], changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (node(); as node) {\n @switch (node.type) {\n @case ('section') {\n <section-view [node]=\"node\"></section-view>\n }\n @case ('grid') {\n <grid-view [node]=\"node\"></grid-view>\n }\n @case ('grid_col') {\n <grid-col-view [node]=\"node\"></grid-col-view>\n }\n @case ('table') {\n <table-view [node]=\"node\"></table-view>\n }\n @case ('chart') {\n <chart-view [node]=\"node\"></chart-view>\n }\n @case ('form') {\n <form-view [node]=\"node\"></form-view>\n }\n }\n}\n" }]
|
|
1557
|
+
}] });
|
|
1558
|
+
|
|
1559
|
+
class LeContainerComponent {
|
|
1560
|
+
auth = inject(LEAuthService);
|
|
1561
|
+
dataService = inject(LEDataService);
|
|
1562
|
+
sidebar = viewChild(SidebarComponent);
|
|
1563
|
+
data = computed(() => {
|
|
1564
|
+
const config = this.dataService.config();
|
|
1565
|
+
const view = this.dataService.view();
|
|
1566
|
+
if (!config || !view)
|
|
1567
|
+
return null;
|
|
1568
|
+
return {
|
|
1569
|
+
config,
|
|
1570
|
+
view,
|
|
1571
|
+
};
|
|
1572
|
+
});
|
|
1573
|
+
constructor() {
|
|
1574
|
+
this.setEffects();
|
|
1575
|
+
}
|
|
1576
|
+
onSelectionChange(view) {
|
|
1577
|
+
this.dataService.setView(view);
|
|
1578
|
+
}
|
|
1579
|
+
setEffects() {
|
|
1580
|
+
effect(() => {
|
|
1581
|
+
const token = this.auth.token();
|
|
1582
|
+
const isGuest = this.auth.isGuest();
|
|
1583
|
+
if (!token && !isGuest)
|
|
1584
|
+
return;
|
|
1585
|
+
untracked(() => {
|
|
1586
|
+
this.dataService.requestConfig();
|
|
1587
|
+
});
|
|
1588
|
+
});
|
|
1589
|
+
effect(() => {
|
|
1590
|
+
const parentMenu = this.dataService.parentMenu();
|
|
1591
|
+
const sidebar = this.sidebar();
|
|
1592
|
+
if (!(parentMenu && sidebar))
|
|
1593
|
+
return;
|
|
1594
|
+
untracked(() => {
|
|
1595
|
+
sidebar.setExpanded(parentMenu);
|
|
1596
|
+
});
|
|
1597
|
+
});
|
|
1598
|
+
}
|
|
1599
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: LeContainerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1600
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.21", type: LeContainerComponent, isStandalone: true, selector: "le-container", providers: [LEDataService, LEApiService], viewQueries: [{ propertyName: "sidebar", first: true, predicate: SidebarComponent, descendants: true, isSignal: true }], ngImport: i0, template: "@if (data(); as data) {\n <le-sidebar\n [config]=\"data.config\"\n [view]=\"data.view\"\n (selectionChange)=\"onSelectionChange($event)\"\n >\n <le-node [node]=\"data.view\"></le-node>\n </le-sidebar>\n}\n", dependencies: [{ kind: "component", type: SidebarComponent, selector: "le-sidebar", inputs: ["config", "view"], outputs: ["selectionChange"] }, { kind: "component", type: NodeComponent, selector: "le-node", inputs: ["node"] }] });
|
|
1601
|
+
}
|
|
1602
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: LeContainerComponent, decorators: [{
|
|
1603
|
+
type: Component,
|
|
1604
|
+
args: [{ selector: 'le-container', imports: [SidebarComponent, NodeComponent], providers: [LEDataService, LEApiService], template: "@if (data(); as data) {\n <le-sidebar\n [config]=\"data.config\"\n [view]=\"data.view\"\n (selectionChange)=\"onSelectionChange($event)\"\n >\n <le-node [node]=\"data.view\"></le-node>\n </le-sidebar>\n}\n" }]
|
|
1605
|
+
}], ctorParameters: () => [] });
|
|
1606
|
+
|
|
1607
|
+
const provideConfig = (config) => {
|
|
1608
|
+
return {
|
|
1609
|
+
provide: CONFIG_TOKEN,
|
|
1610
|
+
useValue: {
|
|
1611
|
+
...defaultConfig,
|
|
1612
|
+
...config,
|
|
1613
|
+
},
|
|
1614
|
+
};
|
|
1615
|
+
};
|
|
1616
|
+
|
|
1617
|
+
const LEAuthInterceptor = (req, next) => {
|
|
1618
|
+
const authService = inject(LEAuthService);
|
|
1619
|
+
if (authService.isGuest()) {
|
|
1620
|
+
return next(req);
|
|
1621
|
+
}
|
|
1622
|
+
if (req.context.get(IS_LIBRARY_REQUEST)) {
|
|
1623
|
+
try {
|
|
1624
|
+
authService.validateToken();
|
|
1625
|
+
return next(req.clone({ setHeaders: { Authorization: authService.token() } }));
|
|
1626
|
+
}
|
|
1627
|
+
catch (e) {
|
|
1628
|
+
inject(LeToastService).error(e.message);
|
|
1629
|
+
console.error(e);
|
|
1630
|
+
}
|
|
1631
|
+
}
|
|
1632
|
+
return next(req);
|
|
1633
|
+
};
|
|
1634
|
+
|
|
1635
|
+
/**
|
|
1636
|
+
* Generated bundle index. Do not edit.
|
|
1637
|
+
*/
|
|
1638
|
+
|
|
1639
|
+
export { CONFIG_TOKEN, LEAuthInterceptor, LEAuthService, LeContainerComponent, LeToastService, provideConfig };
|
|
1640
|
+
//# sourceMappingURL=planeasyinc-le-angular.mjs.map
|