@rosoftlab/rdict 1.0.3-alpha-2 → 1.0.4-alpha-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/fesm2022/rosoftlab-rdict.mjs +441 -57
- package/fesm2022/rosoftlab-rdict.mjs.map +1 -1
- package/lib/components/rdict-generic-table/rdict-generic-table.component.d.ts +22 -4
- package/lib/components/rdict-generic-table/rdict-kendo.d.ts +4 -0
- package/lib/reactive-dictionary.d.ts +1 -1
- package/lib/services/socket.service.d.ts +7 -1
- package/package.json +2 -2
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import * as
|
|
1
|
+
import * as i7$1 from '@angular/common';
|
|
2
2
|
import { CommonModule } from '@angular/common';
|
|
3
3
|
import * as i0 from '@angular/core';
|
|
4
4
|
import { Inject, Injectable, Component, NgModule, HostBinding, forwardRef, Input, ViewChild, EventEmitter, ElementRef, Output, ViewEncapsulation, InjectionToken } from '@angular/core';
|
|
@@ -11,11 +11,11 @@ import { ButtonsModule, KENDO_BUTTONS } from '@progress/kendo-angular-buttons';
|
|
|
11
11
|
import { KENDO_SVGICON } from '@progress/kendo-angular-icons';
|
|
12
12
|
import * as i6 from '@progress/kendo-angular-layout';
|
|
13
13
|
import { LayoutModule } from '@progress/kendo-angular-layout';
|
|
14
|
-
import * as
|
|
14
|
+
import * as i9 from '@progress/kendo-angular-toolbar';
|
|
15
15
|
import { ToolBarModule, KENDO_TOOLBAR, ToolBarToolComponent } from '@progress/kendo-angular-toolbar';
|
|
16
16
|
import * as allIcons from '@progress/kendo-svg-icons';
|
|
17
17
|
import { menuIcon, saveIcon, arrowLeftIcon, pencilIcon, trashIcon, plusIcon } from '@progress/kendo-svg-icons';
|
|
18
|
-
import { Observable,
|
|
18
|
+
import { Subject, fromEvent, Observable, defer, mergeMap, filter, race, first, map, timeout, from, tap, catchError, throwError, BehaviorSubject } from 'rxjs';
|
|
19
19
|
import { v4 } from 'uuid';
|
|
20
20
|
import { io } from 'socket.io-client';
|
|
21
21
|
import * as i2$1 from '@progress/kendo-angular-dialog';
|
|
@@ -29,13 +29,15 @@ import { FormGroup, FormControl, ReactiveFormsModule } from '@angular/forms';
|
|
|
29
29
|
import * as i6$1 from '@ngx-formly/core';
|
|
30
30
|
import { FORMLY_CONFIG, FormlyModule } from '@ngx-formly/core';
|
|
31
31
|
import { FormlyKendoModule } from '@ngx-formly/kendo';
|
|
32
|
-
import * as
|
|
32
|
+
import * as i8 from '@progress/kendo-angular-grid';
|
|
33
33
|
import { KENDO_GRID } from '@progress/kendo-angular-grid';
|
|
34
34
|
import * as i1$1 from '@progress/kendo-angular-label';
|
|
35
35
|
import { KENDO_LABEL } from '@progress/kendo-angular-label';
|
|
36
|
+
import * as i6$2 from '@progress/kendo-angular-intl';
|
|
36
37
|
|
|
37
38
|
class SocketService {
|
|
38
39
|
constructor(socketUrl) {
|
|
40
|
+
this.disconnect$ = new Subject();
|
|
39
41
|
this.socketUrl = socketUrl;
|
|
40
42
|
// Replace with your actual server URL
|
|
41
43
|
// this.socket.on("connect", () => {
|
|
@@ -50,12 +52,22 @@ class SocketService {
|
|
|
50
52
|
initSocket(authToken) {
|
|
51
53
|
if (this.socket == null && authToken !== null) {
|
|
52
54
|
this.socket = io(this.socketUrl, {
|
|
55
|
+
reconnectionDelayMax: 10000,
|
|
56
|
+
transports: ['websocket'],
|
|
53
57
|
withCredentials: true,
|
|
58
|
+
//ackTimeout: 60000,
|
|
59
|
+
timeout: 60000,
|
|
60
|
+
//retries: 50,
|
|
54
61
|
// parser: msgpackParser,
|
|
55
62
|
auth: {
|
|
56
63
|
token: authToken // Include the authentication token
|
|
57
64
|
}
|
|
58
65
|
});
|
|
66
|
+
this.result$ = fromEvent(this.socket, 'function_result');
|
|
67
|
+
this.error$ = fromEvent(this.socket, 'function_error');
|
|
68
|
+
this.disconnected$ = fromEvent(this.socket, 'disconnect');
|
|
69
|
+
// When socket disconnects, push to our teardown subject
|
|
70
|
+
this.disconnected$.subscribe(() => this.disconnect$.next());
|
|
59
71
|
}
|
|
60
72
|
}
|
|
61
73
|
getInitialData() {
|
|
@@ -121,7 +133,8 @@ class SocketService {
|
|
|
121
133
|
observer.error(response.error);
|
|
122
134
|
}
|
|
123
135
|
else {
|
|
124
|
-
|
|
136
|
+
const transformedResponse = this.convertDates(response);
|
|
137
|
+
observer.next(transformedResponse);
|
|
125
138
|
observer.complete();
|
|
126
139
|
}
|
|
127
140
|
});
|
|
@@ -132,29 +145,27 @@ class SocketService {
|
|
|
132
145
|
};
|
|
133
146
|
});
|
|
134
147
|
}
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
148
|
+
convertDates(obj) {
|
|
149
|
+
if (obj === null || obj === undefined)
|
|
150
|
+
return obj;
|
|
151
|
+
if (Array.isArray(obj)) {
|
|
152
|
+
return obj.map((item) => this.convertDates(item));
|
|
153
|
+
}
|
|
154
|
+
if (typeof obj === 'object') {
|
|
155
|
+
const newObj = {};
|
|
156
|
+
for (const key of Object.keys(obj)) {
|
|
157
|
+
const value = obj[key];
|
|
158
|
+
// detect ISO date strings
|
|
159
|
+
if (typeof value === 'string' && /^\d{4}-\d{2}-\d{2}[ T]\d/.test(value)) {
|
|
160
|
+
newObj[key] = new Date(value.replace(' ', 'T')); // replace space with T for safety
|
|
146
161
|
}
|
|
147
162
|
else {
|
|
148
|
-
|
|
149
|
-
observer.complete();
|
|
163
|
+
newObj[key] = this.convertDates(value); // recurse
|
|
150
164
|
}
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
// but you could optionally remove a listener here if you used on(...)
|
|
156
|
-
};
|
|
157
|
-
});
|
|
165
|
+
}
|
|
166
|
+
return newObj;
|
|
167
|
+
}
|
|
168
|
+
return obj;
|
|
158
169
|
}
|
|
159
170
|
// Emit the 'set' event to update the data on the server
|
|
160
171
|
emitSet(did, key, value) {
|
|
@@ -209,6 +220,67 @@ class SocketService {
|
|
|
209
220
|
}
|
|
210
221
|
return obj;
|
|
211
222
|
}
|
|
223
|
+
//#region executeFunction
|
|
224
|
+
executeFunction_old(did, functionName, args = [], kwargs = {}) {
|
|
225
|
+
const payload = {
|
|
226
|
+
did,
|
|
227
|
+
function_name: functionName,
|
|
228
|
+
...(args && args.length ? { args } : {}),
|
|
229
|
+
...(kwargs && Object.keys(kwargs).length ? { kwargs } : {})
|
|
230
|
+
};
|
|
231
|
+
return new Observable((observer) => {
|
|
232
|
+
this.socket.emit('execute_function', payload, (response) => {
|
|
233
|
+
if (response && response.error) {
|
|
234
|
+
observer.error(response.error);
|
|
235
|
+
}
|
|
236
|
+
else {
|
|
237
|
+
observer.next(response);
|
|
238
|
+
observer.complete();
|
|
239
|
+
}
|
|
240
|
+
});
|
|
241
|
+
// teardown logic if subscriber unsubscribes before callback fires
|
|
242
|
+
return () => {
|
|
243
|
+
// no direct way to cancel a single emit/callback in socket.io,
|
|
244
|
+
// but you could optionally remove a listener here if you used on(...)
|
|
245
|
+
};
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
executeFunction(did, functionName, args = [], kwargs = {}, waitMs = 120_000, awaitResult = true) {
|
|
249
|
+
const payload = {
|
|
250
|
+
did,
|
|
251
|
+
function_name: functionName,
|
|
252
|
+
...(args?.length ? { args } : {}),
|
|
253
|
+
...(kwargs && Object.keys(kwargs).length ? { kwargs } : {})
|
|
254
|
+
};
|
|
255
|
+
const ack$ = new Observable((observer) => {
|
|
256
|
+
this.socket.emit('execute_function', payload, (ack) => {
|
|
257
|
+
observer.next(ack);
|
|
258
|
+
observer.complete();
|
|
259
|
+
});
|
|
260
|
+
return () => { };
|
|
261
|
+
});
|
|
262
|
+
if (!awaitResult) {
|
|
263
|
+
// Return immediately with the server ACK
|
|
264
|
+
return ack$;
|
|
265
|
+
}
|
|
266
|
+
// Wait for function_result / function_error matching the job_id
|
|
267
|
+
return defer(() => ack$).pipe(mergeMap((ack) => {
|
|
268
|
+
if (!ack?.ok || !ack.job_id) {
|
|
269
|
+
const msg = ack?.error ?? 'Bad ACK or missing job_id';
|
|
270
|
+
throw new Error(typeof msg === 'string' ? msg : JSON.stringify(msg));
|
|
271
|
+
}
|
|
272
|
+
const jobId = ack.job_id;
|
|
273
|
+
const jobResult$ = this.result$.pipe(filter((e) => e.job_id === jobId));
|
|
274
|
+
const jobError$ = this.error$.pipe(filter((e) => e.job_id === jobId));
|
|
275
|
+
return race(jobResult$, jobError$).pipe(first(), map((evt) => {
|
|
276
|
+
if (evt?.ok === false) {
|
|
277
|
+
const msg = evt.error ?? `Server error for ${functionName} (job ${jobId})`;
|
|
278
|
+
throw new Error(typeof msg === 'string' ? msg : JSON.stringify(msg));
|
|
279
|
+
}
|
|
280
|
+
return evt.result;
|
|
281
|
+
}));
|
|
282
|
+
}), timeout(waitMs));
|
|
283
|
+
}
|
|
212
284
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.8", ngImport: i0, type: SocketService, deps: [{ token: SOCKET_URL }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
213
285
|
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.8", ngImport: i0, type: SocketService, providedIn: 'root' }); }
|
|
214
286
|
}
|
|
@@ -494,24 +566,22 @@ class ReactiveDictionary extends Map {
|
|
|
494
566
|
}
|
|
495
567
|
getFilteredView(key, request) {
|
|
496
568
|
const guid = this.get('__guid'); // however you’re retrieving it
|
|
497
|
-
return this._socketService.requestFilteredData(guid, key, request).pipe(
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
// }),
|
|
502
|
-
catchError((err) => {
|
|
569
|
+
return this._socketService.requestFilteredData(guid, key, request).pipe(tap((data) => {
|
|
570
|
+
// you can still inspect/log the data here if you like
|
|
571
|
+
// console.log('received filtered view:', data);
|
|
572
|
+
}), catchError((err) => {
|
|
503
573
|
console.error('Error fetching filtered view:', err);
|
|
504
574
|
// re-throw so subscribers can handle it
|
|
505
575
|
return throwError(() => err);
|
|
506
576
|
}));
|
|
507
577
|
}
|
|
508
|
-
executeFunction(functionName, args = [], kwargs = {}) {
|
|
578
|
+
executeFunction(functionName, args = [], kwargs = {}, waitMs = 120_000, awaitResult = true) {
|
|
509
579
|
const guid = this.get('__guid'); // however you’re retrieving it
|
|
510
|
-
return this._socketService.executeFunction(guid, functionName, args, kwargs).pipe(tap((data) => {
|
|
580
|
+
return this._socketService.executeFunction(guid, functionName, args, kwargs, waitMs, awaitResult).pipe(tap((data) => {
|
|
511
581
|
// you can still inspect/log the data here if you like
|
|
512
|
-
console.log('received
|
|
582
|
+
console.log('received execute function:', data);
|
|
513
583
|
}), catchError((err) => {
|
|
514
|
-
console.error('Error
|
|
584
|
+
console.error('Error execute function:', err);
|
|
515
585
|
// re-throw so subscribers can handle it
|
|
516
586
|
return throwError(() => err);
|
|
517
587
|
}));
|
|
@@ -1123,7 +1193,7 @@ class RdictCrudComponent {
|
|
|
1123
1193
|
}
|
|
1124
1194
|
}
|
|
1125
1195
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.8", ngImport: i0, type: RdictCrudComponent, deps: [{ token: i1.Router }, { token: i1.ActivatedRoute }, { token: i2.TranslateService }, { token: ReactiveDictionary }, { token: i4.LocalFileService }, { token: MaterialDialogService }, { token: i4.RouteHistoryService }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1126
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.8", type: RdictCrudComponent, isStandalone: true, selector: "app-rdict-crud", host: { properties: { "class": "this.hostClasses" } }, ngImport: i0, template: "<kendo-toolbar>\r\n <kendo-toolbar-button text=\"Back\" showText=\"both\" [svgIcon]=\"backIcon\" showIcon=\"both\" themeColor=\"primary\"\r\n [disabled]=\"false\" (click)=\"onBack()\">\r\n </kendo-toolbar-button>\r\n <kendo-toolbar-spacer></kendo-toolbar-spacer>\r\n <kendo-toolbar-button text=\"Save\" showText=\"both\" [svgIcon]=\"saveIcon\" showIcon=\"both\" themeColor=\"success\"\r\n [disabled]=\"false\" (click)=\"onSave()\">\r\n </kendo-toolbar-button>\r\n</kendo-toolbar>\r\n\r\n <form [formGroup]=\"baseForm\" (ngSubmit)=\"onSubmit(model)\">\r\n <formly-form [form]=\"baseForm\" [fields]=\"fields\" [model]=\"model\" [options]=\"options\"></formly-form>\r\n </form>\r\n<div kendoDialogContainer></div>", styles: ["::ng-deep formly-field{padding:.3rem;display:block}\n"], dependencies: [{ kind: "ngmodule", type: FormlyModule }, { kind: "component", type: i6$1.FormlyForm, selector: "formly-form", inputs: ["form", "model", "fields", "options"], outputs: ["modelChange"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i7.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i7.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i7.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: FormlyKendoModule }, { kind: "ngmodule", type: TranslateModule }, { kind: "ngmodule", type: CrudFormlyTransaltionModule }, { kind: "component", type:
|
|
1196
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.8", type: RdictCrudComponent, isStandalone: true, selector: "app-rdict-crud", host: { properties: { "class": "this.hostClasses" } }, ngImport: i0, template: "<kendo-toolbar>\r\n <kendo-toolbar-button text=\"Back\" showText=\"both\" [svgIcon]=\"backIcon\" showIcon=\"both\" themeColor=\"primary\"\r\n [disabled]=\"false\" (click)=\"onBack()\">\r\n </kendo-toolbar-button>\r\n <kendo-toolbar-spacer></kendo-toolbar-spacer>\r\n <kendo-toolbar-button text=\"Save\" showText=\"both\" [svgIcon]=\"saveIcon\" showIcon=\"both\" themeColor=\"success\"\r\n [disabled]=\"false\" (click)=\"onSave()\">\r\n </kendo-toolbar-button>\r\n</kendo-toolbar>\r\n\r\n <form [formGroup]=\"baseForm\" (ngSubmit)=\"onSubmit(model)\">\r\n <formly-form [form]=\"baseForm\" [fields]=\"fields\" [model]=\"model\" [options]=\"options\"></formly-form>\r\n </form>\r\n<div kendoDialogContainer></div>", styles: ["::ng-deep formly-field{padding:.3rem;display:block}\n"], dependencies: [{ kind: "ngmodule", type: FormlyModule }, { kind: "component", type: i6$1.FormlyForm, selector: "formly-form", inputs: ["form", "model", "fields", "options"], outputs: ["modelChange"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i7.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i7.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i7.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: FormlyKendoModule }, { kind: "ngmodule", type: TranslateModule }, { kind: "ngmodule", type: CrudFormlyTransaltionModule }, { kind: "component", type: i9.ToolBarComponent, selector: "kendo-toolbar", inputs: ["overflow", "resizable", "popupSettings", "fillMode", "tabindex", "size", "tabIndex"], outputs: ["open", "close"], exportAs: ["kendoToolBar"] }, { kind: "component", type: i9.ToolBarButtonComponent, selector: "kendo-toolbar-button", inputs: ["showText", "showIcon", "text", "style", "className", "title", "disabled", "toggleable", "look", "togglable", "selected", "fillMode", "themeColor", "icon", "iconClass", "svgIcon", "imageUrl"], outputs: ["click", "pointerdown", "selectedChange"], exportAs: ["kendoToolBarButton"] }, { kind: "component", type: i9.ToolBarSpacerComponent, selector: "kendo-toolbar-spacer", exportAs: ["kendoToolBarSpacer"] }, { kind: "directive", type: i2$1.DialogContainerDirective, selector: "[kendoDialogContainer]" }] }); }
|
|
1127
1197
|
}
|
|
1128
1198
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.8", ngImport: i0, type: RdictCrudComponent, decorators: [{
|
|
1129
1199
|
type: Component,
|
|
@@ -1144,6 +1214,205 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.8", ngImpor
|
|
|
1144
1214
|
args: ['class']
|
|
1145
1215
|
}] } });
|
|
1146
1216
|
|
|
1217
|
+
/** Main mapper */
|
|
1218
|
+
function kendoToFilterRequest(e) {
|
|
1219
|
+
const { skip = 0, take = 0, sort, filter, group } = e ?? e;
|
|
1220
|
+
const page_size = take || undefined;
|
|
1221
|
+
const page = take ? Math.floor(skip / take) + 1 : undefined;
|
|
1222
|
+
return {
|
|
1223
|
+
page,
|
|
1224
|
+
page_size,
|
|
1225
|
+
sorts: kendoSortsToDict(sort),
|
|
1226
|
+
filters: kendoFilterToSieve(filter),
|
|
1227
|
+
group_by: kendoGroupToArray(group)
|
|
1228
|
+
// distinctColumns: fill if you use a “distinct” mode in your API
|
|
1229
|
+
};
|
|
1230
|
+
}
|
|
1231
|
+
/* ------------------------------- Sorts ---------------------------------- */
|
|
1232
|
+
function kendoSortsToDict(sorts) {
|
|
1233
|
+
if (!sorts?.length)
|
|
1234
|
+
return undefined;
|
|
1235
|
+
const result = {};
|
|
1236
|
+
for (const s of sorts) {
|
|
1237
|
+
if (!s.field)
|
|
1238
|
+
continue;
|
|
1239
|
+
result[s.field] = (s.dir ?? 'asc');
|
|
1240
|
+
}
|
|
1241
|
+
return result;
|
|
1242
|
+
}
|
|
1243
|
+
/* ---------------- GroupBy as array ---------------- */
|
|
1244
|
+
function kendoGroupToArray(group) {
|
|
1245
|
+
if (!group?.length)
|
|
1246
|
+
return undefined;
|
|
1247
|
+
return group.map((g) => g.field);
|
|
1248
|
+
}
|
|
1249
|
+
/* ------------------------------ Filters --------------------------------- */
|
|
1250
|
+
/**
|
|
1251
|
+
* Converts Kendo filter tree to a Sieve filter string.
|
|
1252
|
+
* Notes (Sieve):
|
|
1253
|
+
* - Clause is {Name}{Operator}{Value}, AND with commas, simple OR via:
|
|
1254
|
+
* - multiple names: (Field1|Field2)opValue
|
|
1255
|
+
* - multiple values: Field@=a|b
|
|
1256
|
+
* - Operators: ==, !=, >, <, >=, <=, @= (contains), _= (starts), _-= (ends),
|
|
1257
|
+
* and case-insensitive variants like @=* etc. :contentReference[oaicite:1]{index=1}
|
|
1258
|
+
*/
|
|
1259
|
+
function kendoFilterToSieve(node) {
|
|
1260
|
+
if (!node)
|
|
1261
|
+
return undefined;
|
|
1262
|
+
if (isLeaf(node)) {
|
|
1263
|
+
const op = mapOperator(node.operator, !!node.ignoreCase, node.value);
|
|
1264
|
+
if (!op)
|
|
1265
|
+
return undefined; // unsupported operator (e.g., isnull/isnotnull)
|
|
1266
|
+
const name = node.field;
|
|
1267
|
+
const value = formatSieveValue(node.value);
|
|
1268
|
+
return `${name}${op}${value}`;
|
|
1269
|
+
}
|
|
1270
|
+
// Composite: best-effort mapping.
|
|
1271
|
+
// AND → comma-join
|
|
1272
|
+
// OR → try to compress same-field same-op OR into value pipes; otherwise fall back to (Field1|Field2)opValue when viable.
|
|
1273
|
+
const parts = node.filters.map((f) => kendoFilterToSieve(f)).filter(Boolean);
|
|
1274
|
+
if (!parts.length)
|
|
1275
|
+
return undefined;
|
|
1276
|
+
if (node.logic === 'and') {
|
|
1277
|
+
return parts.join(',');
|
|
1278
|
+
}
|
|
1279
|
+
// OR logic – try simple compressions; if not possible, return a comma-joined set of grouped OR chunks when possible.
|
|
1280
|
+
// Heuristic: if all parts share the same {field,op} with different values → merge via value pipes.
|
|
1281
|
+
const parsed = parts.map(parseClause).filter(Boolean);
|
|
1282
|
+
if (parsed.length && allSame(parsed, (c) => `${c.name}|${c.op}`)) {
|
|
1283
|
+
const { name, op } = parsed[0];
|
|
1284
|
+
const pipedValues = parsed.map((c) => c.value).join('|');
|
|
1285
|
+
return `${name}${op}${pipedValues}`;
|
|
1286
|
+
}
|
|
1287
|
+
// If all parts share same {op,value} but different fields → (A|B)opV
|
|
1288
|
+
if (parsed.length && allSame(parsed, (c) => `${c.op}|${c.value}`)) {
|
|
1289
|
+
const fields = parsed.map((c) => c.name).join('|');
|
|
1290
|
+
const { op, value } = parsed[0];
|
|
1291
|
+
return `(${fields})${op}${value}`;
|
|
1292
|
+
}
|
|
1293
|
+
// Fallback: join with Sieve’s AND (comma). (General mixed OR trees can’t always be represented in Sieve DSL.
|
|
1294
|
+
// If you need exact semantics, consider adding a custom Sieve filter.) :contentReference[oaicite:2]{index=2}
|
|
1295
|
+
return parts.join(',');
|
|
1296
|
+
}
|
|
1297
|
+
/* ----------------------------- Helpers ---------------------------------- */
|
|
1298
|
+
function isLeaf(f) {
|
|
1299
|
+
return f.filters === undefined;
|
|
1300
|
+
}
|
|
1301
|
+
// Map Kendo operators to Sieve operators (case-insensitive variants when ignoreCase=true)
|
|
1302
|
+
function mapOperator(kendoOp, ignoreCase, value) {
|
|
1303
|
+
// Kendo operators list: eq, neq, lt, lte, gt, gte, contains, doesnotcontain, startswith, endswith,
|
|
1304
|
+
// isnull, isnotnull, isempty, isnotempty
|
|
1305
|
+
// Sieve operators: ==, !=, <, <=, >, >=, @=, !@=, _=, _-=, and their * variants for case-insensitive. :contentReference[oaicite:3]{index=3}
|
|
1306
|
+
const strOps = {
|
|
1307
|
+
contains: '@=',
|
|
1308
|
+
doesnotcontain: '!@=',
|
|
1309
|
+
startswith: '_=',
|
|
1310
|
+
endswith: '_-='
|
|
1311
|
+
};
|
|
1312
|
+
const base = (() => {
|
|
1313
|
+
switch (kendoOp) {
|
|
1314
|
+
case 'eq':
|
|
1315
|
+
return '==';
|
|
1316
|
+
case 'neq':
|
|
1317
|
+
return '!=';
|
|
1318
|
+
case 'lt':
|
|
1319
|
+
return '<';
|
|
1320
|
+
case 'lte':
|
|
1321
|
+
return '<=';
|
|
1322
|
+
case 'gt':
|
|
1323
|
+
return '>';
|
|
1324
|
+
case 'gte':
|
|
1325
|
+
return '>=';
|
|
1326
|
+
case 'contains':
|
|
1327
|
+
return strOps.contains;
|
|
1328
|
+
case 'doesnotcontain':
|
|
1329
|
+
return strOps.doesnotcontain;
|
|
1330
|
+
case 'startswith':
|
|
1331
|
+
return strOps.startswith;
|
|
1332
|
+
case 'endswith':
|
|
1333
|
+
return strOps.endswith;
|
|
1334
|
+
case 'isempty':
|
|
1335
|
+
return '=='; // value should be ''
|
|
1336
|
+
case 'isnotempty':
|
|
1337
|
+
return '!='; // value should be ''
|
|
1338
|
+
// isnull / isnotnull don’t have a native Sieve op. Recommend a custom filter on the API.
|
|
1339
|
+
case 'isnull':
|
|
1340
|
+
case 'isnotnull':
|
|
1341
|
+
return undefined;
|
|
1342
|
+
default:
|
|
1343
|
+
return undefined;
|
|
1344
|
+
}
|
|
1345
|
+
})();
|
|
1346
|
+
if (!base)
|
|
1347
|
+
return undefined;
|
|
1348
|
+
// Promote to case-insensitive *only* for string-y ops when requested
|
|
1349
|
+
const isStringy = ['@=', '!@=', '_=', '_-='].includes(base) || typeof value === 'string';
|
|
1350
|
+
if (ignoreCase && isStringy) {
|
|
1351
|
+
// Sieve: case-insensitive variants add a trailing * (e.g., @=*). :contentReference[oaicite:4]{index=4}
|
|
1352
|
+
return base.endsWith('*') ? base : `${base}*`;
|
|
1353
|
+
}
|
|
1354
|
+
return base;
|
|
1355
|
+
}
|
|
1356
|
+
function formatSieveValue(v) {
|
|
1357
|
+
if (v === '' || v === null || v === undefined)
|
|
1358
|
+
return '';
|
|
1359
|
+
if (v instanceof Date)
|
|
1360
|
+
return toISO(v);
|
|
1361
|
+
// Kendo may send dates as strings – try to detect ISO-like and pass through
|
|
1362
|
+
if (typeof v === 'string' && isDateLike(v))
|
|
1363
|
+
return v;
|
|
1364
|
+
if (typeof v === 'string')
|
|
1365
|
+
return escapeSieve(v);
|
|
1366
|
+
if (typeof v === 'number' || typeof v === 'bigint' || typeof v === 'boolean')
|
|
1367
|
+
return String(v);
|
|
1368
|
+
// Arrays can appear with “in” like semantics via OR; join with pipes
|
|
1369
|
+
if (Array.isArray(v))
|
|
1370
|
+
return v.map(formatSieveValue).join('|');
|
|
1371
|
+
// Fallback to JSON (rare)
|
|
1372
|
+
return escapeSieve(JSON.stringify(v));
|
|
1373
|
+
}
|
|
1374
|
+
function toISO(d) {
|
|
1375
|
+
// Prefer full ISO so the API can parse reliably
|
|
1376
|
+
// return new Date(d).toISOString();
|
|
1377
|
+
const y = d.getFullYear();
|
|
1378
|
+
const m = String(d.getMonth() + 1).padStart(2, '0');
|
|
1379
|
+
const day = String(d.getDate()).padStart(2, '0');
|
|
1380
|
+
const hh = String(d.getHours()).padStart(2, '0');
|
|
1381
|
+
const mm = String(d.getMinutes()).padStart(2, '0');
|
|
1382
|
+
const ss = String(d.getSeconds()).padStart(2, '0');
|
|
1383
|
+
return `${y}-${m}-${day}T${hh}:${mm}:${ss}`;
|
|
1384
|
+
}
|
|
1385
|
+
function isDateLike(s) {
|
|
1386
|
+
// very lenient check
|
|
1387
|
+
return /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}/.test(s);
|
|
1388
|
+
}
|
|
1389
|
+
function escapeSieve(s) {
|
|
1390
|
+
// Sieve escaping: backslash to escape commas and pipes (and the backslash itself). :contentReference[oaicite:5]{index=5}
|
|
1391
|
+
return s.replace(/([\\,|])/g, '\\$1');
|
|
1392
|
+
}
|
|
1393
|
+
/** Parses "NameOPValue" (no commas) into {name,op,value} */
|
|
1394
|
+
function parseClause(clause) {
|
|
1395
|
+
// Operators (longer first)
|
|
1396
|
+
const ops = ['==*', '!=*', '@=*', '!@=*', '_=*', '!_=*', '_-=*', '==', '!=', '>=', '<=', '>', '<', '@=', '!@=', '_=', '_-='];
|
|
1397
|
+
for (const op of ops) {
|
|
1398
|
+
const idx = clause.indexOf(op);
|
|
1399
|
+
if (idx > 0) {
|
|
1400
|
+
return {
|
|
1401
|
+
name: clause.slice(0, idx),
|
|
1402
|
+
op,
|
|
1403
|
+
value: clause.slice(idx + op.length)
|
|
1404
|
+
};
|
|
1405
|
+
}
|
|
1406
|
+
}
|
|
1407
|
+
return null;
|
|
1408
|
+
}
|
|
1409
|
+
function allSame(arr, key) {
|
|
1410
|
+
if (!arr.length)
|
|
1411
|
+
return true;
|
|
1412
|
+
const k0 = key(arr[0]);
|
|
1413
|
+
return arr.every((a) => key(a) === k0);
|
|
1414
|
+
}
|
|
1415
|
+
|
|
1147
1416
|
class RdictTableTitle extends ToolBarToolComponent {
|
|
1148
1417
|
constructor() {
|
|
1149
1418
|
super();
|
|
@@ -1179,7 +1448,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.8", ngImpor
|
|
|
1179
1448
|
}] } });
|
|
1180
1449
|
|
|
1181
1450
|
class GenericRdictTableComponent {
|
|
1182
|
-
constructor(router, route, translate, injector, localFileService, rdict, dialogService) {
|
|
1451
|
+
constructor(router, route, translate, injector, localFileService, rdict, dialogService, intl) {
|
|
1183
1452
|
this.router = router;
|
|
1184
1453
|
this.route = route;
|
|
1185
1454
|
this.translate = translate;
|
|
@@ -1187,6 +1456,7 @@ class GenericRdictTableComponent {
|
|
|
1187
1456
|
this.localFileService = localFileService;
|
|
1188
1457
|
this.rdict = rdict;
|
|
1189
1458
|
this.dialogService = dialogService;
|
|
1459
|
+
this.intl = intl;
|
|
1190
1460
|
this.editOnClick = false;
|
|
1191
1461
|
this.editOnDblClick = false;
|
|
1192
1462
|
this.data = [];
|
|
@@ -1211,6 +1481,11 @@ class GenericRdictTableComponent {
|
|
|
1211
1481
|
this.svgEdit = pencilIcon;
|
|
1212
1482
|
this.svgDelete = trashIcon;
|
|
1213
1483
|
this.svgAdd = plusIcon;
|
|
1484
|
+
this.state = {
|
|
1485
|
+
skip: 0,
|
|
1486
|
+
take: 30
|
|
1487
|
+
};
|
|
1488
|
+
this.stateChange = new BehaviorSubject(this.state);
|
|
1214
1489
|
}
|
|
1215
1490
|
async ngOnInit() {
|
|
1216
1491
|
this.setValueFromSnapshot(this, this.route.snapshot, 'model', null);
|
|
@@ -1219,7 +1494,7 @@ class GenericRdictTableComponent {
|
|
|
1219
1494
|
this.setValueFromSnapshot(this, this.route.snapshot, 'searchFields', null);
|
|
1220
1495
|
this.setValueFromSnapshot(this, this.route.snapshot, 'customInclude', null);
|
|
1221
1496
|
this.setValueFromSnapshot(this, this.route.snapshot, 'defaultSort', null);
|
|
1222
|
-
this.setValueFromSnapshot(this, this.route.snapshot, 'defaultSortDirection',
|
|
1497
|
+
this.setValueFromSnapshot(this, this.route.snapshot, 'defaultSortDirection', null);
|
|
1223
1498
|
this.setValueFromSnapshot(this, this.route.snapshot, 'deletePropertyName', 'name');
|
|
1224
1499
|
this.setValueFromSnapshot(this, this.route.snapshot, 'defaultFilter', null);
|
|
1225
1500
|
this.setValueFromSnapshot(this, this.route.snapshot, 'showHeader', true);
|
|
@@ -1231,6 +1506,9 @@ class GenericRdictTableComponent {
|
|
|
1231
1506
|
this.setValueFromSnapshot(this, this.route.snapshot, 'editOnDblClick', false);
|
|
1232
1507
|
this.setValueFromSnapshot(this, this.route.snapshot, 'editColumn', null);
|
|
1233
1508
|
this.setValueFromSnapshot(this, this.route.snapshot, 'fileLayout', '');
|
|
1509
|
+
this.setValueFromSnapshot(this, this.route.snapshot, 'useView', false);
|
|
1510
|
+
this.setValueFromSnapshot(this, this.route.snapshot, 'pageable', false);
|
|
1511
|
+
this.setValueFromSnapshot(this, this.route.snapshot, 'pageSizes ', [10, 20, 30, 50, 100]);
|
|
1234
1512
|
const currentUrlSegments = this.router.url.split('/').map((segment) => new UrlSegment(segment, {}));
|
|
1235
1513
|
this.basePath = currentUrlSegments.map((segment) => segment.path).join('/');
|
|
1236
1514
|
const filteredSegments = currentUrlSegments.filter((segment) => segment.path !== '');
|
|
@@ -1244,9 +1522,20 @@ class GenericRdictTableComponent {
|
|
|
1244
1522
|
// Perform actions or update component as needed
|
|
1245
1523
|
}
|
|
1246
1524
|
});
|
|
1525
|
+
if (this.useView) {
|
|
1526
|
+
if (this.defaultSort) {
|
|
1527
|
+
this.state.sort = this.defaultSort;
|
|
1528
|
+
}
|
|
1529
|
+
await this.getParentDict();
|
|
1530
|
+
}
|
|
1247
1531
|
this.getListLayout();
|
|
1248
1532
|
this.loadData();
|
|
1249
1533
|
}
|
|
1534
|
+
async getParentDict() {
|
|
1535
|
+
const lastDotIndex = this.dictPath.lastIndexOf('.');
|
|
1536
|
+
const parentPath = lastDotIndex !== -1 ? this.dictPath.substring(0, lastDotIndex) : this.dictPath;
|
|
1537
|
+
this.parentDict = await this.rdict.asyncGet(parentPath);
|
|
1538
|
+
}
|
|
1250
1539
|
setValueFromSnapshot(component, snapshot, key, defaultValue) {
|
|
1251
1540
|
if (component[key] === undefined) {
|
|
1252
1541
|
let dataFromSnapshot = snapshot.data[key];
|
|
@@ -1256,7 +1545,11 @@ class GenericRdictTableComponent {
|
|
|
1256
1545
|
component[key] = dataFromSnapshot !== undefined ? dataFromSnapshot : defaultValue;
|
|
1257
1546
|
}
|
|
1258
1547
|
}
|
|
1259
|
-
|
|
1548
|
+
loadData() {
|
|
1549
|
+
if (this.useView) {
|
|
1550
|
+
this.loadDataView();
|
|
1551
|
+
return;
|
|
1552
|
+
}
|
|
1260
1553
|
this.rdict.get$(this.dictPath).subscribe({
|
|
1261
1554
|
next: (rdictData) => {
|
|
1262
1555
|
this.tableRdict = rdictData;
|
|
@@ -1282,23 +1575,61 @@ class GenericRdictTableComponent {
|
|
|
1282
1575
|
error: (err) => console.error('Error:', err.message)
|
|
1283
1576
|
});
|
|
1284
1577
|
}
|
|
1578
|
+
loadDataView() {
|
|
1579
|
+
//Get the parent path
|
|
1580
|
+
// const request = {
|
|
1581
|
+
// filters: '',
|
|
1582
|
+
// sorts: { import_date: 'desc' },
|
|
1583
|
+
// page: Math.floor(this.state.skip / this.state.take) + 1,
|
|
1584
|
+
// page_size: this.state.take
|
|
1585
|
+
// };
|
|
1586
|
+
const request = kendoToFilterRequest(this.state);
|
|
1587
|
+
this.parentDict.getFilteredView(this.model, request).subscribe({
|
|
1588
|
+
next: (view) => {
|
|
1589
|
+
// console.log('View:', view);
|
|
1590
|
+
this.dataSource = view;
|
|
1591
|
+
}
|
|
1592
|
+
});
|
|
1593
|
+
}
|
|
1285
1594
|
onChangeEvent(changes) {
|
|
1286
1595
|
if (changes) {
|
|
1287
1596
|
const key = changes?.key;
|
|
1288
1597
|
const value = changes?.value;
|
|
1289
|
-
if (key
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1598
|
+
if (key == 'transactions') {
|
|
1599
|
+
//I have receibed transactions update
|
|
1600
|
+
//Update all transactions in the table
|
|
1601
|
+
const transactions = value;
|
|
1602
|
+
for (const [key, value] of Object.entries(transactions)) {
|
|
1603
|
+
const index = this.dataSource.findIndex((item) => item.__idx === key);
|
|
1604
|
+
if (index > -1) {
|
|
1605
|
+
this.dataSource[index] = value;
|
|
1606
|
+
}
|
|
1607
|
+
else {
|
|
1608
|
+
//get the object from rdict
|
|
1609
|
+
// this.tableRdict.get$(key).subscribe({
|
|
1610
|
+
// next: (value) => {
|
|
1611
|
+
// var dd = value.getPlainObject();
|
|
1612
|
+
this.dataSource.push(value);
|
|
1613
|
+
// }
|
|
1614
|
+
// });
|
|
1615
|
+
}
|
|
1293
1616
|
}
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1617
|
+
}
|
|
1618
|
+
else {
|
|
1619
|
+
if (key && value) {
|
|
1620
|
+
const index = this.dataSource.findIndex((item) => item.__idx === key);
|
|
1621
|
+
if (index > -1) {
|
|
1622
|
+
this.dataSource[index] = value;
|
|
1623
|
+
}
|
|
1624
|
+
else {
|
|
1625
|
+
//get the object from rdict
|
|
1626
|
+
this.tableRdict.get$(key).subscribe({
|
|
1627
|
+
next: (value) => {
|
|
1628
|
+
var dd = value.getPlainObject();
|
|
1629
|
+
this.dataSource.push(dd);
|
|
1630
|
+
}
|
|
1631
|
+
});
|
|
1632
|
+
}
|
|
1302
1633
|
}
|
|
1303
1634
|
}
|
|
1304
1635
|
}
|
|
@@ -1357,6 +1688,7 @@ class GenericRdictTableComponent {
|
|
|
1357
1688
|
}
|
|
1358
1689
|
return item;
|
|
1359
1690
|
});
|
|
1691
|
+
// console.log('All columns:', this.allColumns);
|
|
1360
1692
|
//Get reference columns
|
|
1361
1693
|
const referenceColumns = this.allColumns.filter((item) => item.reference !== undefined && item.reference !== null);
|
|
1362
1694
|
if (referenceColumns.length > 0) {
|
|
@@ -1417,17 +1749,69 @@ class GenericRdictTableComponent {
|
|
|
1417
1749
|
}
|
|
1418
1750
|
if (column.type == 'reference') {
|
|
1419
1751
|
const value = this.referenceData.get(column.reference)?.get(item[column.propertyName])?.[column.referenceProperty] ?? item[column.propertyName];
|
|
1752
|
+
return this.formatValue(value, column.format);
|
|
1420
1753
|
return value;
|
|
1421
1754
|
}
|
|
1422
1755
|
else {
|
|
1423
|
-
return item[column.propertyName];
|
|
1756
|
+
return this.formatValue(item[column.propertyName], column.format);
|
|
1757
|
+
}
|
|
1758
|
+
}
|
|
1759
|
+
filterChange(filter) {
|
|
1760
|
+
// console.log(filter);
|
|
1761
|
+
// this.loadData();
|
|
1762
|
+
}
|
|
1763
|
+
dataStateChange(state) {
|
|
1764
|
+
this.state = state;
|
|
1765
|
+
this.loadData();
|
|
1766
|
+
}
|
|
1767
|
+
pageChange(state) {
|
|
1768
|
+
console.log('State:', state);
|
|
1769
|
+
this.stateChange.next(state);
|
|
1770
|
+
}
|
|
1771
|
+
formatValue(value, format) {
|
|
1772
|
+
if (value === null || value === undefined || !format) {
|
|
1773
|
+
return value ?? '';
|
|
1424
1774
|
}
|
|
1775
|
+
// Accept both "{0:...}" and plain "..." patterns
|
|
1776
|
+
const inner = this.extractFormat(format);
|
|
1777
|
+
// Heuristics: date vs number
|
|
1778
|
+
if (this.looksLikeDateFormat(inner)) {
|
|
1779
|
+
const d = value instanceof Date ? value : new Date(value);
|
|
1780
|
+
return isNaN(d.getTime()) ? value : this.intl.formatDate(d, inner);
|
|
1781
|
+
}
|
|
1782
|
+
const num = typeof value === 'number' ? value : Number(value);
|
|
1783
|
+
if (!Number.isNaN(num)) {
|
|
1784
|
+
// supports "n", "n2", "c", "p", etc. and custom patterns
|
|
1785
|
+
return this.intl.formatNumber(num, inner);
|
|
1786
|
+
}
|
|
1787
|
+
// Fallback: return as-is if not a date/number
|
|
1788
|
+
return value;
|
|
1425
1789
|
}
|
|
1426
|
-
|
|
1427
|
-
|
|
1790
|
+
extractFormat(fmt) {
|
|
1791
|
+
const m = fmt.match(/^\{0:([^}]+)\}$/);
|
|
1792
|
+
return m ? m[1] : fmt;
|
|
1793
|
+
}
|
|
1794
|
+
looksLikeDateFormat(f) {
|
|
1795
|
+
// crude but effective: typical date tokens
|
|
1796
|
+
return /d|M|y|H|h|m|s|E|a/.test(f) && !/^[cnp]/i.test(f);
|
|
1797
|
+
}
|
|
1798
|
+
inferFilterType(col) {
|
|
1799
|
+
if (!col)
|
|
1800
|
+
return 'text';
|
|
1801
|
+
const f = this.extractFormat(col.format || '');
|
|
1802
|
+
if (this.looksLikeDateFormat(f))
|
|
1803
|
+
return 'date';
|
|
1804
|
+
if (/^(n\d*|c|p\d*|n)$/i.test(f))
|
|
1805
|
+
return 'numeric'; // Kendo number patterns
|
|
1806
|
+
if (col.type === 'boolean')
|
|
1807
|
+
return 'boolean';
|
|
1808
|
+
return 'text';
|
|
1809
|
+
}
|
|
1810
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.8", ngImport: i0, type: GenericRdictTableComponent, deps: [{ token: i1.Router }, { token: i1.ActivatedRoute }, { token: i2.TranslateService }, { token: i0.Injector }, { token: i4.LocalFileService }, { token: ReactiveDictionary }, { token: MaterialDialogService }, { token: i6$2.IntlService }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1811
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.8", type: GenericRdictTableComponent, isStandalone: true, selector: "rsl-rdict-generic-table", inputs: { showSerach: "showSerach", searchFields: "searchFields", customInclude: "customInclude", defaultSort: "defaultSort", deletePropertyName: "deletePropertyName", defaultFilter: "defaultFilter", showHeader: "showHeader", hasAdd: "hasAdd", canDelete: "canDelete", canEdit: "canEdit", editOnClick: "editOnClick", editOnDblClick: "editOnDblClick" }, outputs: { selectedObject: "selectedObject", click: "click", editModel: "editModel" }, providers: [], viewQueries: [{ propertyName: "filter", first: true, predicate: ElementRef, descendants: true }], ngImport: i0, template: "<kendo-grid [data]=\"dataSource\" [sortable]=\"true\" [filterable]=\"showSerach\" [resizable]=\"true\" (add)=\"addHandler()\"\r\n (edit)=\"editHandler($event)\" (remove)=\"removeHandler($event)\"\r\n (filterChange)=\"filterChange($event)\"\r\n (dataStateChange)=\"dataStateChange($event)\"\r\n \r\n [pageable]=\"{pageSizes:pageSizes}\" [pageSize]=\"state.take\"\r\n [skip]=\"state.skip\" [sort]=\"state.sort\" >\r\n <kendo-toolbar>\r\n <table-title text=\"{{title}}\"></table-title>\r\n <kendo-toolbar-messages>Test</kendo-toolbar-messages>\r\n <!-- <kendo-toolbar-separator></kendo-toolbar-separator> -->\r\n <kendo-toolbar-spacer></kendo-toolbar-spacer>\r\n <kendo-toolbar-button *ngIf=\"hasAdd\" kendoButton [svgIcon]=\"svgAdd\" text=\"Add new\" kendoGridAddTool></kendo-toolbar-button>\r\n </kendo-toolbar>\r\n\r\n <!-- <kendo-toolbar>\r\n \r\n <kendo-toolbar-spacer></kendo-toolbar-spacer>\r\n <button kendoGridAddCommand type=\"button\">Add new</button>\r\n </kendo-toolbar> -->\r\n <!-- <kendo-grid-column *ngFor=\"let column of allColumns\" field=\"{{ column.propertyName }}\"\r\n title=\" {{column.translateKey | translate}}\">\r\n </kendo-grid-column> -->\r\n\r\n <kendo-grid-column *ngFor=\"let column of allColumns\" [field]=\"column.propertyName\"\r\n [title]=\"column.translateKey | translate\" [format]=\"column.format\" [filter]=\"inferFilterType(column)\">\r\n <!-- Use ng-template to customize the column content -->\r\n <ng-template *ngIf=\"column.isEditLink; else defaultTemplate\" kendoGridCellTemplate let-dataItem>\r\n <!-- Create a link that calls editHandler(dataItem) -->\r\n <a href=\"javascript:void(0)\" (click)=\"edit(dataItem)\" class=\"edit-link\">\r\n {{ getCellValue(dataItem,column) }}\r\n </a>\r\n </ng-template>\r\n \r\n <!-- <ng-template *ngIf=\"column.type=='reference'; else defaultTemplate\" kendoGridCellTemplate let-dataItem>\r\n <a href=\"javascript:void(0)\" (click)=\"edit(dataItem)\" class=\"edit-link\">\r\n {{ getCellValue$(dataItem,column) | async }}\r\n </a>\r\n </ng-template> -->\r\n <!-- Default template for non-link columns -->\r\n <ng-template #defaultTemplate kendoGridCellTemplate let-dataItem>\r\n {{ getCellValue(dataItem,column) }}\r\n </ng-template>\r\n </kendo-grid-column>\r\n\r\n\r\n <kendo-grid-command-column *ngIf=\"canEdit && canDelete\" title=\"\" [width]=\"100\">\r\n <ng-template kendoGridCellTemplate>\r\n <!-- <button kendoButton kendoGridEditCommand [svgIcon]=\"svgEdit\" themeColor=\"light\" ></button>\r\n <button kendoButton kendoGridRemoveCommand [svgIcon]=\"svgDelete\" themeColor=\"error\"></button> -->\r\n <button *ngIf=\"canEdit\" kendoGridEditCommand [svgIcon]=\"svgEdit\" themeColor=\"light\"></button>\r\n <button *ngIf=\"canDelete\" kendoGridRemoveCommand [svgIcon]=\"svgDelete\" themeColor=\"error\"></button>\r\n </ng-template>\r\n </kendo-grid-command-column>\r\n</kendo-grid>\r\n<div kendoDialogContainer></div>", styles: [".edit-link{color:#00f!important;text-decoration:underline!important;cursor:pointer!important}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i7$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i7$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: RouterModule }, { kind: "ngmodule", type:
|
|
1428
1812
|
// MatPaginatorModule,
|
|
1429
1813
|
// MatTableModule,
|
|
1430
|
-
TranslateModule }, { kind: "pipe", type: i2.TranslatePipe, name: "translate" }, { kind: "component", type:
|
|
1814
|
+
TranslateModule }, { kind: "pipe", type: i2.TranslatePipe, name: "translate" }, { kind: "component", type: i8.GridComponent, selector: "kendo-grid", inputs: ["data", "pageSize", "height", "rowHeight", "detailRowHeight", "skip", "scrollable", "selectable", "sort", "size", "trackBy", "filter", "group", "virtualColumns", "filterable", "sortable", "pageable", "groupable", "gridResizable", "rowReorderable", "navigable", "navigatable", "autoSize", "rowClass", "rowSticky", "rowSelected", "isRowSelectable", "cellSelected", "resizable", "reorderable", "loading", "columnMenu", "hideHeader", "isDetailExpanded", "isGroupExpanded"], outputs: ["filterChange", "pageChange", "groupChange", "sortChange", "selectionChange", "rowReorder", "dataStateChange", "groupExpand", "groupCollapse", "detailExpand", "detailCollapse", "edit", "cancel", "save", "remove", "add", "cellClose", "cellClick", "pdfExport", "excelExport", "columnResize", "columnReorder", "columnVisibilityChange", "columnLockedChange", "columnStickyChange", "scrollBottom", "contentScroll"], exportAs: ["kendoGrid"] }, { kind: "directive", type: i8.GridToolbarFocusableDirective, selector: " [kendoGridToolbarFocusable], [kendoGridAddCommand], [kendoGridCancelCommand], [kendoGridEditCommand], [kendoGridRemoveCommand], [kendoGridSaveCommand], [kendoGridExcelCommand], [kendoGridPDFCommand] " }, { kind: "component", type: i8.ColumnComponent, selector: "kendo-grid-column", inputs: ["field", "format", "sortable", "groupable", "editor", "filter", "filterable", "editable"] }, { kind: "directive", type: i8.FocusableDirective, selector: "[kendoGridFocusable], [kendoGridEditCommand], [kendoGridRemoveCommand], [kendoGridSaveCommand], [kendoGridCancelCommand], [kendoGridSelectionCheckbox] ", inputs: ["kendoGridFocusable"] }, { kind: "component", type: i8.CommandColumnComponent, selector: "kendo-grid-command-column" }, { kind: "directive", type: i8.CellTemplateDirective, selector: "[kendoGridCellTemplate]" }, { kind: "component", type: i8.EditCommandDirective, selector: "[kendoGridEditCommand]" }, { kind: "component", type: i8.RemoveCommandDirective, selector: "[kendoGridRemoveCommand]" }, { kind: "directive", type: i8.AddCommandToolbarDirective, selector: "[kendoGridAddTool]" }, { kind: "component", type: i9.ToolBarComponent, selector: "kendo-toolbar", inputs: ["overflow", "resizable", "popupSettings", "fillMode", "tabindex", "size", "tabIndex"], outputs: ["open", "close"], exportAs: ["kendoToolBar"] }, { kind: "component", type: i9.ToolbarCustomMessagesComponent, selector: "kendo-toolbar-messages" }, { kind: "component", type: i9.ToolBarButtonComponent, selector: "kendo-toolbar-button", inputs: ["showText", "showIcon", "text", "style", "className", "title", "disabled", "toggleable", "look", "togglable", "selected", "fillMode", "themeColor", "icon", "iconClass", "svgIcon", "imageUrl"], outputs: ["click", "pointerdown", "selectedChange"], exportAs: ["kendoToolBarButton"] }, { kind: "component", type: i9.ToolBarSpacerComponent, selector: "kendo-toolbar-spacer", exportAs: ["kendoToolBarSpacer"] }, { kind: "directive", type: i2$1.DialogContainerDirective, selector: "[kendoDialogContainer]" }, { kind: "component", type: RdictTableTitle, selector: "table-title", inputs: ["text"] }], encapsulation: i0.ViewEncapsulation.None }); }
|
|
1431
1815
|
}
|
|
1432
1816
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.8", ngImport: i0, type: GenericRdictTableComponent, decorators: [{
|
|
1433
1817
|
type: Component,
|
|
@@ -1443,8 +1827,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.8", ngImpor
|
|
|
1443
1827
|
KENDO_BUTTONS,
|
|
1444
1828
|
KENDO_DIALOG,
|
|
1445
1829
|
RdictTableTitle
|
|
1446
|
-
], providers: [], template: "<kendo-grid
|
|
1447
|
-
}], ctorParameters: () => [{ type: i1.Router }, { type: i1.ActivatedRoute }, { type: i2.TranslateService }, { type: i0.Injector }, { type: i4.LocalFileService }, { type: ReactiveDictionary }, { type: MaterialDialogService }], propDecorators: { showSerach: [{
|
|
1830
|
+
], providers: [], template: "<kendo-grid [data]=\"dataSource\" [sortable]=\"true\" [filterable]=\"showSerach\" [resizable]=\"true\" (add)=\"addHandler()\"\r\n (edit)=\"editHandler($event)\" (remove)=\"removeHandler($event)\"\r\n (filterChange)=\"filterChange($event)\"\r\n (dataStateChange)=\"dataStateChange($event)\"\r\n \r\n [pageable]=\"{pageSizes:pageSizes}\" [pageSize]=\"state.take\"\r\n [skip]=\"state.skip\" [sort]=\"state.sort\" >\r\n <kendo-toolbar>\r\n <table-title text=\"{{title}}\"></table-title>\r\n <kendo-toolbar-messages>Test</kendo-toolbar-messages>\r\n <!-- <kendo-toolbar-separator></kendo-toolbar-separator> -->\r\n <kendo-toolbar-spacer></kendo-toolbar-spacer>\r\n <kendo-toolbar-button *ngIf=\"hasAdd\" kendoButton [svgIcon]=\"svgAdd\" text=\"Add new\" kendoGridAddTool></kendo-toolbar-button>\r\n </kendo-toolbar>\r\n\r\n <!-- <kendo-toolbar>\r\n \r\n <kendo-toolbar-spacer></kendo-toolbar-spacer>\r\n <button kendoGridAddCommand type=\"button\">Add new</button>\r\n </kendo-toolbar> -->\r\n <!-- <kendo-grid-column *ngFor=\"let column of allColumns\" field=\"{{ column.propertyName }}\"\r\n title=\" {{column.translateKey | translate}}\">\r\n </kendo-grid-column> -->\r\n\r\n <kendo-grid-column *ngFor=\"let column of allColumns\" [field]=\"column.propertyName\"\r\n [title]=\"column.translateKey | translate\" [format]=\"column.format\" [filter]=\"inferFilterType(column)\">\r\n <!-- Use ng-template to customize the column content -->\r\n <ng-template *ngIf=\"column.isEditLink; else defaultTemplate\" kendoGridCellTemplate let-dataItem>\r\n <!-- Create a link that calls editHandler(dataItem) -->\r\n <a href=\"javascript:void(0)\" (click)=\"edit(dataItem)\" class=\"edit-link\">\r\n {{ getCellValue(dataItem,column) }}\r\n </a>\r\n </ng-template>\r\n \r\n <!-- <ng-template *ngIf=\"column.type=='reference'; else defaultTemplate\" kendoGridCellTemplate let-dataItem>\r\n <a href=\"javascript:void(0)\" (click)=\"edit(dataItem)\" class=\"edit-link\">\r\n {{ getCellValue$(dataItem,column) | async }}\r\n </a>\r\n </ng-template> -->\r\n <!-- Default template for non-link columns -->\r\n <ng-template #defaultTemplate kendoGridCellTemplate let-dataItem>\r\n {{ getCellValue(dataItem,column) }}\r\n </ng-template>\r\n </kendo-grid-column>\r\n\r\n\r\n <kendo-grid-command-column *ngIf=\"canEdit && canDelete\" title=\"\" [width]=\"100\">\r\n <ng-template kendoGridCellTemplate>\r\n <!-- <button kendoButton kendoGridEditCommand [svgIcon]=\"svgEdit\" themeColor=\"light\" ></button>\r\n <button kendoButton kendoGridRemoveCommand [svgIcon]=\"svgDelete\" themeColor=\"error\"></button> -->\r\n <button *ngIf=\"canEdit\" kendoGridEditCommand [svgIcon]=\"svgEdit\" themeColor=\"light\"></button>\r\n <button *ngIf=\"canDelete\" kendoGridRemoveCommand [svgIcon]=\"svgDelete\" themeColor=\"error\"></button>\r\n </ng-template>\r\n </kendo-grid-command-column>\r\n</kendo-grid>\r\n<div kendoDialogContainer></div>", styles: [".edit-link{color:#00f!important;text-decoration:underline!important;cursor:pointer!important}\n"] }]
|
|
1831
|
+
}], ctorParameters: () => [{ type: i1.Router }, { type: i1.ActivatedRoute }, { type: i2.TranslateService }, { type: i0.Injector }, { type: i4.LocalFileService }, { type: ReactiveDictionary }, { type: MaterialDialogService }, { type: i6$2.IntlService }], propDecorators: { showSerach: [{
|
|
1448
1832
|
type: Input
|
|
1449
1833
|
}], searchFields: [{
|
|
1450
1834
|
type: Input
|