@rosoftlab/rdict 1.0.1-alpha-9 → 1.0.1-alpha-10
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 +539 -151
- package/fesm2022/rosoftlab-rdict.mjs.map +1 -1
- package/lib/components/rdict-crud/rdict-crud.component.d.ts +17 -3
- package/lib/components/rdict-generic-table/rdict-generic-table.component.d.ts +16 -4
- package/lib/reactive-dictionary.d.ts +11 -4
- package/lib/services/material-dialog.service.d.ts +17 -0
- package/lib/services/socket.service.d.ts +4 -0
- package/package.json +2 -2
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import * as
|
|
1
|
+
import * as i6$2 from '@angular/common';
|
|
2
2
|
import { CommonModule } from '@angular/common';
|
|
3
3
|
import * as i0 from '@angular/core';
|
|
4
4
|
import { Injectable, Inject, Component, NgModule, forwardRef, ViewChild, Input, EventEmitter, ElementRef, ViewEncapsulation, Output, InjectionToken } from '@angular/core';
|
|
@@ -11,24 +11,27 @@ 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 i8 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, pencilIcon, trashIcon, plusIcon } from '@progress/kendo-svg-icons';
|
|
18
|
-
import {
|
|
18
|
+
import { Subject, from, mergeMap, map, Observable } from 'rxjs';
|
|
19
19
|
import { v4 } from 'uuid';
|
|
20
20
|
import { io } from 'socket.io-client';
|
|
21
|
-
import * as msgpackParser from 'socket.io-msgpack-parser';
|
|
22
21
|
import * as i1 from '@rosoftlab/core';
|
|
23
22
|
import { BaseModel, Attribute, BaseModelConfig, BaseService } from '@rosoftlab/core';
|
|
24
23
|
import { __decorate, __metadata } from 'tslib';
|
|
25
|
-
import * as
|
|
24
|
+
import * as i7 from '@angular/forms';
|
|
26
25
|
import { FormGroup, FormControl, ReactiveFormsModule } from '@angular/forms';
|
|
27
|
-
import * as
|
|
26
|
+
import * as i6$1 from '@ngx-formly/core';
|
|
28
27
|
import { FORMLY_CONFIG, FormlyModule } from '@ngx-formly/core';
|
|
29
28
|
import { FormlyKendoModule } from '@ngx-formly/kendo';
|
|
30
|
-
import * as
|
|
29
|
+
import * as i2$1 from '@progress/kendo-angular-dialog';
|
|
30
|
+
import { DialogCloseResult, KENDO_DIALOG } from '@progress/kendo-angular-dialog';
|
|
31
|
+
import * as i3 from '@progress/kendo-angular-notification';
|
|
32
|
+
import * as i7$1 from '@progress/kendo-angular-grid';
|
|
31
33
|
import { KENDO_GRID } from '@progress/kendo-angular-grid';
|
|
34
|
+
import * as i1$2 from '@progress/kendo-angular-label';
|
|
32
35
|
import { KENDO_LABEL } from '@progress/kendo-angular-label';
|
|
33
36
|
|
|
34
37
|
class SocketService {
|
|
@@ -48,14 +51,27 @@ class SocketService {
|
|
|
48
51
|
if (this.socket == null && authToken !== null) {
|
|
49
52
|
this.socket = io(this.socketUrl, {
|
|
50
53
|
withCredentials: true,
|
|
51
|
-
parser: msgpackParser,
|
|
54
|
+
// parser: msgpackParser,
|
|
52
55
|
auth: {
|
|
53
56
|
token: authToken, // Include the authentication token
|
|
54
|
-
},
|
|
55
|
-
query: {
|
|
56
|
-
"access_token": authToken
|
|
57
57
|
}
|
|
58
|
+
// ,
|
|
59
|
+
// query: {
|
|
60
|
+
// "access_token": authToken
|
|
61
|
+
// }
|
|
58
62
|
});
|
|
63
|
+
// const originalEmit = this.socket.emit;
|
|
64
|
+
// this.socket.emit = (event, ...args) => {
|
|
65
|
+
// // Transform dates before sending
|
|
66
|
+
// const transformedData = this.transformDatesForEncoding(args[0]);
|
|
67
|
+
// originalEmit.call(this.socket, event, transformedData);
|
|
68
|
+
// return this.socket;
|
|
69
|
+
// };
|
|
70
|
+
// Intercept incoming data and apply date transformation
|
|
71
|
+
// this.socket.onAny((event, data) => {
|
|
72
|
+
// const transformedData = this.transformDatesForDecoding(data);
|
|
73
|
+
// this.socket.emit(event, transformedData); // Emit the transformed data back
|
|
74
|
+
// });
|
|
59
75
|
}
|
|
60
76
|
}
|
|
61
77
|
getInitialData() {
|
|
@@ -79,6 +95,15 @@ class SocketService {
|
|
|
79
95
|
}
|
|
80
96
|
});
|
|
81
97
|
}
|
|
98
|
+
getDeleteEvent(rdict) {
|
|
99
|
+
this.socket.on('delete', (data) => {
|
|
100
|
+
// (rdict.get('__guid'), data, this.socket.id)
|
|
101
|
+
if (rdict.get('__guid') === data.did) {
|
|
102
|
+
// ('Set the data')
|
|
103
|
+
rdict.asyncDelete(data.key, false);
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
}
|
|
82
107
|
// Emit the 'lazy_load' event with callback to get the response
|
|
83
108
|
requestLazyLoad(did, key) {
|
|
84
109
|
return new Promise((resolve, reject) => {
|
|
@@ -105,6 +130,46 @@ class SocketService {
|
|
|
105
130
|
});
|
|
106
131
|
});
|
|
107
132
|
}
|
|
133
|
+
// Emit the 'set' event to update the data on the server
|
|
134
|
+
emitDelete(did, key) {
|
|
135
|
+
return new Promise((resolve, reject) => {
|
|
136
|
+
this.socket.emit('delete', { did, key }, (response) => {
|
|
137
|
+
if (response && response.error) {
|
|
138
|
+
reject(response.error);
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
resolve();
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
transformDatesForEncoding(obj) {
|
|
147
|
+
if (obj instanceof Date) {
|
|
148
|
+
return { __date__: obj.toISOString() };
|
|
149
|
+
}
|
|
150
|
+
else if (Array.isArray(obj)) {
|
|
151
|
+
return obj.map(this.transformDatesForEncoding);
|
|
152
|
+
}
|
|
153
|
+
else if (obj !== null && typeof obj === "object") {
|
|
154
|
+
return Object.keys(obj).reduce((acc, key) => {
|
|
155
|
+
acc[key] = this.transformDatesForEncoding(obj[key]);
|
|
156
|
+
return acc;
|
|
157
|
+
}, {});
|
|
158
|
+
}
|
|
159
|
+
return obj;
|
|
160
|
+
}
|
|
161
|
+
transformDatesForDecoding(obj) {
|
|
162
|
+
if (typeof obj === "object" && obj !== null) {
|
|
163
|
+
if ("__date__" in obj) {
|
|
164
|
+
return new Date(obj.__date__);
|
|
165
|
+
}
|
|
166
|
+
return Object.keys(obj).reduce((acc, key) => {
|
|
167
|
+
acc[key] = this.transformDatesForDecoding(obj[key]);
|
|
168
|
+
return acc;
|
|
169
|
+
}, {});
|
|
170
|
+
}
|
|
171
|
+
return obj;
|
|
172
|
+
}
|
|
108
173
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.3", ngImport: i0, type: SocketService, deps: [{ token: SOCKET_URL }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
109
174
|
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.1.3", ngImport: i0, type: SocketService, providedIn: 'root' }); }
|
|
110
175
|
}
|
|
@@ -118,11 +183,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.3", ngImpor
|
|
|
118
183
|
args: [SOCKET_URL]
|
|
119
184
|
}] }] });
|
|
120
185
|
|
|
186
|
+
// import { mergeMap } from 'rxjs/operators';
|
|
121
187
|
class ReactiveDictionary extends Map {
|
|
122
|
-
static { this.instance = new Map; }
|
|
188
|
+
static { this.instance = new Map(); }
|
|
123
189
|
constructor(socketService) {
|
|
124
190
|
super();
|
|
125
|
-
this.changes$ = new
|
|
191
|
+
this.changes$ = new Subject();
|
|
192
|
+
this.deletes$ = new Subject();
|
|
126
193
|
this.isInitialized = false;
|
|
127
194
|
this._authToken = null;
|
|
128
195
|
this._socketService = socketService;
|
|
@@ -130,26 +197,12 @@ class ReactiveDictionary extends Map {
|
|
|
130
197
|
// this._socketService.getSetEvent(this)
|
|
131
198
|
}
|
|
132
199
|
async initialize(authToken) {
|
|
133
|
-
this._authToken = authToken;
|
|
134
200
|
this._authToken = authToken;
|
|
135
201
|
this._socketService.initSocket(authToken);
|
|
136
202
|
this._socketService.getSetEvent(this);
|
|
203
|
+
this._socketService.getDeleteEvent(this);
|
|
137
204
|
await this.asyncInit();
|
|
138
205
|
}
|
|
139
|
-
// // Method to get the singleton instance
|
|
140
|
-
// public static getInstance(socketService: SocketService, authToken: string, instance_key?: string): ReactiveDictionary {
|
|
141
|
-
// if (!instance_key)
|
|
142
|
-
// instance_key = 'root'
|
|
143
|
-
// if (!ReactiveDictionary.instance.has(instance_key)) {
|
|
144
|
-
// ReactiveDictionary.instance.set(instance_key, new ReactiveDictionary(socketService, authToken));
|
|
145
|
-
// }
|
|
146
|
-
// const instance = ReactiveDictionary.instance.get(instance_key);
|
|
147
|
-
// if (!instance) {
|
|
148
|
-
// throw new Error(`No instance found for key: ${instance_key}`); // Handle undefined case
|
|
149
|
-
// }
|
|
150
|
-
// return instance; // Now TypeScript knows 'instance' is not undefined
|
|
151
|
-
// }
|
|
152
|
-
// str_keys(): string[] {
|
|
153
206
|
keys() {
|
|
154
207
|
const excludedKeys = ['__guid', '__type']; // Key to exclude
|
|
155
208
|
const iterator = super.keys();
|
|
@@ -170,8 +223,8 @@ class ReactiveDictionary extends Map {
|
|
|
170
223
|
return { value: key, done: false }; // Return the valid key
|
|
171
224
|
}
|
|
172
225
|
} while (true); // Continue until a valid key is found
|
|
173
|
-
}
|
|
174
|
-
})
|
|
226
|
+
},
|
|
227
|
+
}),
|
|
175
228
|
};
|
|
176
229
|
return filteredIterator;
|
|
177
230
|
}
|
|
@@ -213,7 +266,7 @@ class ReactiveDictionary extends Map {
|
|
|
213
266
|
}
|
|
214
267
|
}
|
|
215
268
|
else {
|
|
216
|
-
const obj = await this.asyncGet(keys[0]);
|
|
269
|
+
const obj = (await this.asyncGet(keys[0]));
|
|
217
270
|
if (obj)
|
|
218
271
|
return await obj.asyncGet(keys.slice(1).join('.'));
|
|
219
272
|
else
|
|
@@ -224,9 +277,9 @@ class ReactiveDictionary extends Map {
|
|
|
224
277
|
// Transform a value to a format that can be serialized.
|
|
225
278
|
const dict_type = value['__type'];
|
|
226
279
|
if (dict_type === 'lazy')
|
|
227
|
-
return {
|
|
280
|
+
return { __type: 'lazy' };
|
|
228
281
|
else if (value instanceof ReactiveDictionary)
|
|
229
|
-
return {
|
|
282
|
+
return { __type: 'dict', __guid: value.get('__guid') };
|
|
230
283
|
else
|
|
231
284
|
return value;
|
|
232
285
|
}
|
|
@@ -243,12 +296,29 @@ class ReactiveDictionary extends Map {
|
|
|
243
296
|
this.set(key, value);
|
|
244
297
|
this.changes$.next({ key, value });
|
|
245
298
|
}
|
|
299
|
+
async asyncDelete(key, emmit_event = true) {
|
|
300
|
+
if (this.has(key)) {
|
|
301
|
+
if (emmit_event) {
|
|
302
|
+
try {
|
|
303
|
+
await this._socketService.emitDelete(this.get('__guid'), key);
|
|
304
|
+
}
|
|
305
|
+
catch (error) {
|
|
306
|
+
console.error('Error emitting set event:', error);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
this.delete(key);
|
|
310
|
+
this.deletes$.next({ key });
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
deleteAsObservable(key, emmit_event = true) {
|
|
314
|
+
return from(this.asyncDelete(key, emmit_event));
|
|
315
|
+
}
|
|
246
316
|
// Asynchronous method to initialize with a set of key-value pairs
|
|
247
317
|
async asyncInit(initialData) {
|
|
248
318
|
if (!this.isInitialized) {
|
|
249
319
|
try {
|
|
250
320
|
// If initial data is not provided, fetch it
|
|
251
|
-
const data = initialData || await this._socketService.getInitialData();
|
|
321
|
+
const data = initialData || (await this._socketService.getInitialData());
|
|
252
322
|
// this.known_dicts.set(data.__guid,data);
|
|
253
323
|
// Set the initial properties on the proxy
|
|
254
324
|
for (const [key, value] of Object.entries(data)) {
|
|
@@ -274,98 +344,166 @@ class ReactiveDictionary extends Map {
|
|
|
274
344
|
getPlainObject() {
|
|
275
345
|
const plainObject = {};
|
|
276
346
|
this.forEach((value, key) => {
|
|
277
|
-
if (value instanceof ReactiveDictionary)
|
|
347
|
+
if (value instanceof ReactiveDictionary) {
|
|
278
348
|
plainObject[key] = value.getPlainObject();
|
|
279
|
-
|
|
280
|
-
|
|
349
|
+
}
|
|
350
|
+
else if (typeof value === 'string') {
|
|
351
|
+
const formattedValue = value
|
|
352
|
+
.replace(/'/g, '"') // Convert single quotes to double quotes
|
|
353
|
+
.replace(/\bNone\b/g, 'null') // Replace None with null
|
|
354
|
+
.replace(/\bFalse\b/g, 'false') // Replace False with false
|
|
355
|
+
.replace(/\bTrue\b/g, 'true'); // Replace True with true
|
|
356
|
+
try {
|
|
357
|
+
const parsedValue = JSON.parse(formattedValue, this.jsonDateReviver);
|
|
358
|
+
plainObject[key] = parsedValue;
|
|
359
|
+
}
|
|
360
|
+
catch {
|
|
361
|
+
plainObject[key] = value; // Keep as string if not valid JSON
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
else {
|
|
365
|
+
plainObject[key] = value;
|
|
366
|
+
}
|
|
281
367
|
});
|
|
282
368
|
return plainObject; // Return the plain object
|
|
283
369
|
}
|
|
370
|
+
jsonDateReviver(key, value) {
|
|
371
|
+
// Check if the value is a valid ISO date string
|
|
372
|
+
if (typeof value === 'string' &&
|
|
373
|
+
/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/.test(value)) {
|
|
374
|
+
return new Date(value); // Convert to JavaScript Date object
|
|
375
|
+
}
|
|
376
|
+
return value;
|
|
377
|
+
}
|
|
284
378
|
getAsObservable(key) {
|
|
285
379
|
return from(this.asyncGet(key));
|
|
286
380
|
}
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
// map(value => ({ data: value, success: true })), // Transform the response
|
|
290
|
-
// catchError(error => {
|
|
291
|
-
// console.error('Error fetching value:', error);
|
|
292
|
-
// throw error; // Rethrow the error so subscribers can handle it
|
|
293
|
-
// })
|
|
294
|
-
// );
|
|
295
|
-
// }
|
|
296
|
-
getTableAsObservable(key) {
|
|
297
|
-
return from(this.getTable(key)).pipe(map(dictionary => {
|
|
298
|
-
// Check if dictionary is an array
|
|
381
|
+
getTableAsObservable(key, data = null) {
|
|
382
|
+
return from(this.getTable(key, data)).pipe(mergeMap((dictionary) => {
|
|
299
383
|
if (!Array.isArray(dictionary)) {
|
|
300
384
|
throw new Error('Expected an array but received something else');
|
|
301
385
|
}
|
|
302
|
-
|
|
303
|
-
const isArrayOfReactiveDictionaries = dictionary.every(item => item instanceof ReactiveDictionary);
|
|
386
|
+
const isArrayOfReactiveDictionaries = dictionary.every((item) => item instanceof ReactiveDictionary);
|
|
304
387
|
if (!isArrayOfReactiveDictionaries) {
|
|
305
388
|
throw new Error('Expected an array of ReactiveDictionary instances but received something else');
|
|
306
389
|
}
|
|
307
|
-
//
|
|
308
|
-
return
|
|
309
|
-
const filteredObject = {};
|
|
310
|
-
for (const [key, value] of dict.entries()) {
|
|
311
|
-
if (key !== '__guid') {
|
|
312
|
-
filteredObject[key] = value;
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
return filteredObject;
|
|
316
|
-
});
|
|
390
|
+
// ✅ WRAP THIS IN from(...) to make it emit real data, not a Promise
|
|
391
|
+
return from(this.processTableData(dictionary));
|
|
317
392
|
}));
|
|
318
393
|
}
|
|
319
|
-
async getTable(key) {
|
|
320
|
-
|
|
321
|
-
|
|
394
|
+
async getTable(key, data = null) {
|
|
395
|
+
if (!data)
|
|
396
|
+
data = await this.asyncGet(key); // Get rooms from the ReactiveDictionary
|
|
397
|
+
if (!data)
|
|
322
398
|
return []; // Return an empty array if data is undefined
|
|
323
|
-
|
|
399
|
+
console.log('getTable', data);
|
|
324
400
|
// Filter and get only entries that are instances of ReactiveDictionary
|
|
325
|
-
const result = await Promise.all(Array.from(data.entries()).map(async (key) =>
|
|
326
|
-
|
|
401
|
+
const result = (await Promise.all(Array.from(data.entries()).map(async (key, index) => {
|
|
402
|
+
const entry = (await data.asyncGet(key[0]));
|
|
403
|
+
if (entry instanceof ReactiveDictionary) {
|
|
404
|
+
entry.set('__idx', key[0]);
|
|
405
|
+
}
|
|
406
|
+
return entry;
|
|
407
|
+
}))) || []; // Return an empty array if the above yields undefined
|
|
327
408
|
return result.filter((entry) => entry instanceof ReactiveDictionary);
|
|
328
409
|
}
|
|
329
410
|
async getTableWithoutGuid(key) {
|
|
330
|
-
const data = await this.asyncGet(key);
|
|
331
|
-
if (!data)
|
|
332
|
-
return [];
|
|
411
|
+
const data = await this.asyncGet(key);
|
|
412
|
+
if (!data)
|
|
413
|
+
return [];
|
|
414
|
+
// Reuse the common processing logic
|
|
415
|
+
return this.processTableData(data);
|
|
416
|
+
}
|
|
417
|
+
async processTableData(data) {
|
|
418
|
+
if (data instanceof ReactiveDictionary) {
|
|
419
|
+
const result = (await Promise.all(Array.from(data.entries()).map(async ([key]) => {
|
|
420
|
+
const entry = (await data.asyncGet(key));
|
|
421
|
+
if (entry instanceof ReactiveDictionary) {
|
|
422
|
+
entry.set('__idx', key);
|
|
423
|
+
}
|
|
424
|
+
return entry;
|
|
425
|
+
}))) || [];
|
|
426
|
+
return result
|
|
427
|
+
.filter((entry) => entry instanceof ReactiveDictionary)
|
|
428
|
+
.map((dictionary) => {
|
|
429
|
+
const filteredObject = {};
|
|
430
|
+
for (const [key, value] of dictionary.entries()) {
|
|
431
|
+
if (key !== '__guid') {
|
|
432
|
+
filteredObject[key] = value;
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
return filteredObject;
|
|
436
|
+
});
|
|
333
437
|
}
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
if (key !== '__guid') {
|
|
343
|
-
filteredObject[key] = value;
|
|
438
|
+
else if (Array.isArray(data)) {
|
|
439
|
+
// Directly process array of ReactiveDictionary instances
|
|
440
|
+
return data.map((dictionary) => {
|
|
441
|
+
const filteredObject = {};
|
|
442
|
+
for (const [key, value] of dictionary.entries()) {
|
|
443
|
+
if (key !== '__guid') {
|
|
444
|
+
filteredObject[key] = value;
|
|
445
|
+
}
|
|
344
446
|
}
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
}
|
|
447
|
+
return filteredObject;
|
|
448
|
+
});
|
|
449
|
+
}
|
|
450
|
+
else {
|
|
451
|
+
console.warn('processTableData received unexpected data:', data);
|
|
452
|
+
return [];
|
|
453
|
+
}
|
|
348
454
|
}
|
|
455
|
+
// async processTableData(data: any): Promise<any[]> {
|
|
456
|
+
// // Filter and get only entries that are instances of ReactiveDictionary
|
|
457
|
+
// const result = await Promise.all(
|
|
458
|
+
// Array.from(data.entries()).map(async ([key]) => {
|
|
459
|
+
// const entry = await data.asyncGet(key) as ReactiveDictionary
|
|
460
|
+
// if (entry instanceof ReactiveDictionary) {
|
|
461
|
+
// entry.set('__idx', key);
|
|
462
|
+
// }
|
|
463
|
+
// return entry;
|
|
464
|
+
// })
|
|
465
|
+
// ) || [];
|
|
466
|
+
// // Filter out entries that are not ReactiveDictionary instances
|
|
467
|
+
// const filteredResults = result.filter((entry: any) => entry instanceof ReactiveDictionary);
|
|
468
|
+
// // Remove __guid from each dictionary and return the plain object
|
|
469
|
+
// return filteredResults.map(dictionary => {
|
|
470
|
+
// const filteredObject: Record<string, any> = {};
|
|
471
|
+
// for (const [key, value] of dictionary.entries()) {
|
|
472
|
+
// if (key !== '__guid') {
|
|
473
|
+
// filteredObject[key] = value;
|
|
474
|
+
// }
|
|
475
|
+
// }
|
|
476
|
+
// return filteredObject;
|
|
477
|
+
// });
|
|
478
|
+
// }
|
|
349
479
|
onChanges() {
|
|
350
480
|
return this.changes$.asObservable();
|
|
351
481
|
}
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
482
|
+
onDelete() {
|
|
483
|
+
return this.deletes$.asObservable();
|
|
484
|
+
}
|
|
485
|
+
async update(record, key = null) {
|
|
486
|
+
if (!key)
|
|
487
|
+
key = this.size.toString();
|
|
488
|
+
const dict = await this.asyncGet(key);
|
|
355
489
|
for (const key in record) {
|
|
356
490
|
if (record.hasOwnProperty(key)) {
|
|
357
|
-
await dict.
|
|
491
|
+
const currentValue = await dict.asyncGet(key);
|
|
492
|
+
if (currentValue !== record[key])
|
|
493
|
+
await dict.asyncSet(key, record[key]);
|
|
358
494
|
}
|
|
359
495
|
}
|
|
360
496
|
}
|
|
497
|
+
modelFormList(property, value) {
|
|
498
|
+
return this.get('__modelFormList');
|
|
499
|
+
}
|
|
361
500
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.3", ngImport: i0, type: ReactiveDictionary, deps: [{ token: SocketService }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
362
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.1.3", ngImport: i0, type: ReactiveDictionary, providedIn: 'root'
|
|
363
|
-
}); }
|
|
501
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.1.3", ngImport: i0, type: ReactiveDictionary, providedIn: 'root' }); }
|
|
364
502
|
}
|
|
365
503
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.3", ngImport: i0, type: ReactiveDictionary, decorators: [{
|
|
366
504
|
type: Injectable,
|
|
367
505
|
args: [{
|
|
368
|
-
providedIn: 'root' // This makes the service a singleton and available throughout the app
|
|
506
|
+
providedIn: 'root', // This makes the service a singleton and available throughout the app
|
|
369
507
|
}]
|
|
370
508
|
}], ctorParameters: () => [{ type: SocketService }] });
|
|
371
509
|
|
|
@@ -629,6 +767,63 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.3", ngImpor
|
|
|
629
767
|
], template: "<div class=\"custom-toolbar\">\r\n <button kendoButton [svgIcon]=\"menuSvg\" fillMode=\"flat\" (click)=\"drawer.toggle()\"></button>\r\n <!-- <kendo-toolbar-button icon=\"menu\" themeColor=\"tertiary\" (click)=\"drawer.toggle()\"> </kendo-toolbar-button> -->\r\n <span class=\"app-title\">{{apptitle}}</span>\r\n</div>\r\n<kendo-drawer-container>\r\n <kendo-drawer #drawer [items]=\"items\" mode=\"push\" [mini]=\"true\" [expanded]=\"true\" (select)=\"onSelect($event)\"\r\n [autoCollapse]=\"false\" [isItemExpanded]=\"isItemExpanded\">\r\n <!-- <ng-template kendoDrawerItemTemplate let-item>\r\n <div *ngIf=\"item.path !== ''\" class=\"k-drawer-link\" [routerLink]=\"item.path\">\r\n <kendo-svgicon [icon]=\"item.svgIcon\"></kendo-svgicon>\r\n <span>{{ item.text }}</span>\r\n </div>\r\n <div *ngIf=\"item.path == ''\" class=\"k-drawer-link\" >\r\n <kendo-svgicon [icon]=\"item.svgIcon\"></kendo-svgicon>\r\n <span>{{ item.text }}</span>\r\n </div>\r\n </ng-template> -->\r\n </kendo-drawer>\r\n\r\n <kendo-drawer-content>\r\n <router-outlet></router-outlet>\r\n <!-- <div>{{selected}}</div> -->\r\n <!-- <my-content [selectedItem]=\"selected\"></my-content> -->\r\n </kendo-drawer-content>\r\n</kendo-drawer-container>", styles: ["html,body,rdict-full{padding:0;height:100%}rdict-full{display:flex;flex-direction:column}kendo-drawer-container{flex:1 1 auto;overflow-y:auto}.k-icon{font-size:20px}.custom-toolbar{width:100%;background-color:#f6f6f6;line-height:10px;border-bottom:inset;border-bottom-width:1px;color:#656565}.custom-toolbar button{margin:3px 0 3px 8px}.app-title{margin-left:20px;font-weight:700;font-size:17px}\n"] }]
|
|
630
768
|
}], ctorParameters: () => [{ type: UserService }, { type: i1$1.Router }, { type: i2.TranslateService }, { type: ReactiveDictionary }] });
|
|
631
769
|
|
|
770
|
+
class MaterialDialogService {
|
|
771
|
+
constructor(translate, dialogService, notificationService) {
|
|
772
|
+
this.translate = translate;
|
|
773
|
+
this.dialogService = dialogService;
|
|
774
|
+
this.notificationService = notificationService;
|
|
775
|
+
this.state = {
|
|
776
|
+
content: "Your data has been saved.",
|
|
777
|
+
type: { style: "success", icon: true },
|
|
778
|
+
animation: { type: "slide", duration: 400 },
|
|
779
|
+
hideAfter: 3000,
|
|
780
|
+
};
|
|
781
|
+
}
|
|
782
|
+
confirmDelete() {
|
|
783
|
+
return this.confirm(this.translate.instant("Are you sure you want to delete this record ?"), this.translate.instant("Delete Record"), this.translate.instant("General.Yes"), this.translate.instant("General.No"));
|
|
784
|
+
}
|
|
785
|
+
confirm(content, title, confirmButtonText, cancelButtonText) {
|
|
786
|
+
const dialog = this.dialogService.open({
|
|
787
|
+
title: title || "Confirm",
|
|
788
|
+
content: content || "Are you sure?",
|
|
789
|
+
actions: [
|
|
790
|
+
{ text: cancelButtonText || "No", result: false },
|
|
791
|
+
{ text: confirmButtonText || "Yes", themeColor: "primary", result: true }
|
|
792
|
+
],
|
|
793
|
+
width: 450,
|
|
794
|
+
height: 200,
|
|
795
|
+
minWidth: 250,
|
|
796
|
+
});
|
|
797
|
+
// Return an Observable<boolean>
|
|
798
|
+
return new Observable((observer) => {
|
|
799
|
+
dialog.result.subscribe((result) => {
|
|
800
|
+
if (result instanceof DialogCloseResult) {
|
|
801
|
+
// Dialog was closed without an action
|
|
802
|
+
observer.next(false);
|
|
803
|
+
}
|
|
804
|
+
else {
|
|
805
|
+
const actionResult = result;
|
|
806
|
+
observer.next(actionResult.result);
|
|
807
|
+
}
|
|
808
|
+
observer.complete(); // Complete the observable
|
|
809
|
+
});
|
|
810
|
+
});
|
|
811
|
+
}
|
|
812
|
+
showSaveMessage(message) {
|
|
813
|
+
this.state.content = message || "Your data has been saved.";
|
|
814
|
+
this.state.type = { style: "success", icon: true };
|
|
815
|
+
this.notificationService.show(this.state);
|
|
816
|
+
}
|
|
817
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.3", ngImport: i0, type: MaterialDialogService, deps: [{ token: i2.TranslateService }, { token: i2$1.DialogService }, { token: i3.NotificationService }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
818
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.1.3", ngImport: i0, type: MaterialDialogService, providedIn: 'root' }); }
|
|
819
|
+
}
|
|
820
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.3", ngImport: i0, type: MaterialDialogService, decorators: [{
|
|
821
|
+
type: Injectable,
|
|
822
|
+
args: [{
|
|
823
|
+
providedIn: 'root'
|
|
824
|
+
}]
|
|
825
|
+
}], ctorParameters: () => [{ type: i2.TranslateService }, { type: i2$1.DialogService }, { type: i3.NotificationService }] });
|
|
826
|
+
|
|
632
827
|
class TranslateExtension {
|
|
633
828
|
constructor(translate) {
|
|
634
829
|
this.translate = translate;
|
|
@@ -697,11 +892,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.3", ngImpor
|
|
|
697
892
|
}] });
|
|
698
893
|
|
|
699
894
|
class RdictCrudComponent {
|
|
700
|
-
constructor(router, route, translate, rdict) {
|
|
895
|
+
constructor(router, route, translate, rdict, localFileService, dialogService) {
|
|
701
896
|
this.router = router;
|
|
702
897
|
this.route = route;
|
|
703
898
|
this.translate = translate;
|
|
704
899
|
this.rdict = rdict;
|
|
900
|
+
this.localFileService = localFileService;
|
|
901
|
+
this.dialogService = dialogService;
|
|
705
902
|
this.baseForm = new FormGroup({});
|
|
706
903
|
this.model = {};
|
|
707
904
|
this.options = {};
|
|
@@ -709,38 +906,133 @@ class RdictCrudComponent {
|
|
|
709
906
|
this.saveIcon = saveIcon;
|
|
710
907
|
}
|
|
711
908
|
async ngOnInit() {
|
|
909
|
+
this.setValueFromSnapshot(this, this.route.snapshot, 'fileLayout', '');
|
|
712
910
|
const currentUrlSegments = this.router.url.split('/').filter(segment => segment !== '' && isNaN(Number(segment)));
|
|
713
911
|
if (['add', 'edit'].includes(currentUrlSegments[currentUrlSegments.length - 1])) {
|
|
714
912
|
currentUrlSegments.pop();
|
|
715
913
|
}
|
|
716
914
|
this.dictPath = currentUrlSegments.join('.');
|
|
717
915
|
this.rdictModel = currentUrlSegments.length > 0 ? currentUrlSegments[currentUrlSegments.length - 1] : '';
|
|
916
|
+
const id = this.route.snapshot.paramMap.get('id');
|
|
917
|
+
this.modelKey = id ?? null;
|
|
718
918
|
this.getModelFields();
|
|
919
|
+
this.getModel();
|
|
920
|
+
}
|
|
921
|
+
setValueFromSnapshot(component, snapshot, key, defaultValue) {
|
|
922
|
+
if (component[key] === undefined) {
|
|
923
|
+
let dataFromSnapshot = snapshot.data[key];
|
|
924
|
+
if (dataFromSnapshot === null || dataFromSnapshot === undefined) {
|
|
925
|
+
dataFromSnapshot = snapshot.params[key];
|
|
926
|
+
}
|
|
927
|
+
component[key] = dataFromSnapshot !== undefined ? dataFromSnapshot : defaultValue;
|
|
928
|
+
}
|
|
719
929
|
}
|
|
720
930
|
onSubmit(model) {
|
|
721
|
-
this.saveModel(this.baseForm)
|
|
931
|
+
// this.saveModel(this.baseForm)
|
|
722
932
|
}
|
|
723
|
-
|
|
724
|
-
if (this.
|
|
725
|
-
this.rdict.getAsObservable(
|
|
726
|
-
next:
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
933
|
+
getModel() {
|
|
934
|
+
if (this.modelKey) {
|
|
935
|
+
this.rdict.getAsObservable(this.dictPath).subscribe({
|
|
936
|
+
next: value => {
|
|
937
|
+
value.getAsObservable(this.modelKey).subscribe({
|
|
938
|
+
next: modelValue => {
|
|
939
|
+
this.modelRdict = modelValue;
|
|
940
|
+
this.model = this.modelRdict.getPlainObject();
|
|
941
|
+
this.modelRdict.onChanges().subscribe(changes => {
|
|
942
|
+
if (changes) {
|
|
943
|
+
console.log("Changes detected:", changes);
|
|
944
|
+
this.baseForm.get(changes.key).patchValue(changes.value);
|
|
945
|
+
// this.model[changes.key] = changes.value;
|
|
946
|
+
}
|
|
947
|
+
});
|
|
948
|
+
}
|
|
949
|
+
});
|
|
731
950
|
},
|
|
732
951
|
error: err => console.error('Error:', err.message),
|
|
733
952
|
});
|
|
734
953
|
}
|
|
735
954
|
}
|
|
955
|
+
getModelFields() {
|
|
956
|
+
if (this.rdictModel) {
|
|
957
|
+
if (this.fileLayout) {
|
|
958
|
+
//load from file
|
|
959
|
+
this.localFileService.getJsonData(this.fileLayout).subscribe({
|
|
960
|
+
next: value => {
|
|
961
|
+
if (value) {
|
|
962
|
+
const layout = value.find(item => item.model === this.rdictModel);
|
|
963
|
+
this.setLayout(layout?.formLayout);
|
|
964
|
+
}
|
|
965
|
+
},
|
|
966
|
+
error: err => console.error('Error:', err.message),
|
|
967
|
+
});
|
|
968
|
+
}
|
|
969
|
+
else
|
|
970
|
+
this.rdict.getAsObservable("config.models." + this.rdictModel + ".formLayout").subscribe({
|
|
971
|
+
next: formLayout => {
|
|
972
|
+
if (formLayout) {
|
|
973
|
+
this.setLayout(formLayout);
|
|
974
|
+
}
|
|
975
|
+
},
|
|
976
|
+
error: err => console.error('Error:', err.message),
|
|
977
|
+
});
|
|
978
|
+
}
|
|
979
|
+
}
|
|
980
|
+
setLayout(formLayout) {
|
|
981
|
+
this.title = this.translate.instant(formLayout["title"]);
|
|
982
|
+
// console.log(formLayout["fields"]);
|
|
983
|
+
let fieldsTmp = formLayout["fields"];
|
|
984
|
+
this.fields = this.transformFields(fieldsTmp);
|
|
985
|
+
// this.transformJsonToFormlyFields()
|
|
986
|
+
}
|
|
987
|
+
// transformJsonToFormlyFields(json: any[]): FormlyFieldConfig[] {
|
|
988
|
+
// // return json.map(field => {
|
|
989
|
+
// // if (field.type === 'select' && field.props.options) {
|
|
990
|
+
// // field.props.options = this.getSelectData(field.props.options);
|
|
991
|
+
// // }
|
|
992
|
+
// // return {
|
|
993
|
+
// // key: field.key,
|
|
994
|
+
// // type: field.type,
|
|
995
|
+
// // props: field.props,
|
|
996
|
+
// // fieldGroup: field?.fieldGroup
|
|
997
|
+
// // };
|
|
998
|
+
// // });
|
|
999
|
+
// }
|
|
1000
|
+
transformFields(fields) {
|
|
1001
|
+
return fields.map(field => this.transformField(field));
|
|
1002
|
+
}
|
|
1003
|
+
transformField(field) {
|
|
1004
|
+
// Handle the current field
|
|
1005
|
+
if (field.type === 'select' && field.props?.options && typeof field.props.options === 'string') {
|
|
1006
|
+
field.props.options = this.getSelectData(field.props.options);
|
|
1007
|
+
}
|
|
1008
|
+
// Recursively handle fieldGroup
|
|
1009
|
+
if (field.fieldGroup) {
|
|
1010
|
+
field.fieldGroup = this.transformFields(field.fieldGroup);
|
|
1011
|
+
}
|
|
1012
|
+
// Recursively handle fieldArray
|
|
1013
|
+
if (field.fieldArray) {
|
|
1014
|
+
if (typeof field.fieldArray === 'function') {
|
|
1015
|
+
const originalFieldArrayFn = field.fieldArray;
|
|
1016
|
+
field.fieldArray = (fieldConfig) => {
|
|
1017
|
+
const transformedField = this.transformField(originalFieldArrayFn(fieldConfig));
|
|
1018
|
+
return transformedField;
|
|
1019
|
+
};
|
|
1020
|
+
}
|
|
1021
|
+
else {
|
|
1022
|
+
field.fieldArray = this.transformField(field.fieldArray);
|
|
1023
|
+
}
|
|
1024
|
+
}
|
|
1025
|
+
return field;
|
|
1026
|
+
}
|
|
736
1027
|
async onSave() {
|
|
737
1028
|
await this.saveModel(this.baseForm);
|
|
738
1029
|
}
|
|
739
1030
|
async saveModel(fg) {
|
|
740
1031
|
if (fg.valid) {
|
|
741
1032
|
var dict = await this.rdict.asyncGet(this.dictPath);
|
|
742
|
-
await dict.
|
|
743
|
-
|
|
1033
|
+
await dict.update(fg.value, this.modelKey);
|
|
1034
|
+
this.dialogService.showSaveMessage();
|
|
1035
|
+
// console.log(fg.value);
|
|
744
1036
|
}
|
|
745
1037
|
else {
|
|
746
1038
|
this.validateAllFormFields(fg);
|
|
@@ -758,8 +1050,11 @@ class RdictCrudComponent {
|
|
|
758
1050
|
}
|
|
759
1051
|
});
|
|
760
1052
|
}
|
|
761
|
-
|
|
762
|
-
|
|
1053
|
+
getSelectData(key) {
|
|
1054
|
+
return this.rdict.getTableAsObservable(key);
|
|
1055
|
+
}
|
|
1056
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.3", ngImport: i0, type: RdictCrudComponent, deps: [{ token: i1$1.Router }, { token: i1$1.ActivatedRoute }, { token: i2.TranslateService }, { token: ReactiveDictionary }, { token: i1.LocalFileService }, { token: MaterialDialogService }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1057
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.1.3", type: RdictCrudComponent, isStandalone: true, selector: "app-rdict-crud", ngImport: i0, template: "<kendo-toolbar>\r\n <kendo-toolbar-spacer></kendo-toolbar-spacer>\r\n <kendo-toolbar-button text=\"Save\" showText=\"both\" [svgIcon]=\"saveIcon\" showIcon=\"both\" themeColor=\"primary\"\r\n [disabled]=\"false\" (click)=\"onSave()\">\r\n </kendo-toolbar-button>\r\n</kendo-toolbar>\r\n<form [formGroup]=\"baseForm\" (ngSubmit)=\"onSubmit(model)\">\r\n\r\n <formly-form [form]=\"baseForm\" [fields]=\"fields\" [model]=\"model\" [options]=\"options\"></formly-form>\r\n</form>", styles: [""], 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: i8.ToolBarComponent, selector: "kendo-toolbar", inputs: ["overflow", "resizable", "popupSettings", "fillMode", "tabindex", "size", "tabIndex"], outputs: ["open", "close"], exportAs: ["kendoToolBar"] }, { kind: "component", type: i8.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: i8.ToolBarSpacerComponent, selector: "kendo-toolbar-spacer", exportAs: ["kendoToolBarSpacer"] }] }); }
|
|
763
1058
|
}
|
|
764
1059
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.3", ngImport: i0, type: RdictCrudComponent, decorators: [{
|
|
765
1060
|
type: Component,
|
|
@@ -771,7 +1066,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.3", ngImpor
|
|
|
771
1066
|
CrudFormlyTransaltionModule,
|
|
772
1067
|
KENDO_TOOLBAR
|
|
773
1068
|
], template: "<kendo-toolbar>\r\n <kendo-toolbar-spacer></kendo-toolbar-spacer>\r\n <kendo-toolbar-button text=\"Save\" showText=\"both\" [svgIcon]=\"saveIcon\" showIcon=\"both\" themeColor=\"primary\"\r\n [disabled]=\"false\" (click)=\"onSave()\">\r\n </kendo-toolbar-button>\r\n</kendo-toolbar>\r\n<form [formGroup]=\"baseForm\" (ngSubmit)=\"onSubmit(model)\">\r\n\r\n <formly-form [form]=\"baseForm\" [fields]=\"fields\" [model]=\"model\" [options]=\"options\"></formly-form>\r\n</form>" }]
|
|
774
|
-
}], ctorParameters: () => [{ type: i1$1.Router }, { type: i1$1.ActivatedRoute }, { type: i2.TranslateService }, { type: ReactiveDictionary }] });
|
|
1069
|
+
}], ctorParameters: () => [{ type: i1$1.Router }, { type: i1$1.ActivatedRoute }, { type: i2.TranslateService }, { type: ReactiveDictionary }, { type: i1.LocalFileService }, { type: MaterialDialogService }] });
|
|
775
1070
|
|
|
776
1071
|
class RdictTableTitle extends ToolBarToolComponent {
|
|
777
1072
|
constructor() {
|
|
@@ -783,7 +1078,7 @@ class RdictTableTitle extends ToolBarToolComponent {
|
|
|
783
1078
|
<ng-template #toolbarTemplate>
|
|
784
1079
|
<kendo-label>{{text}}</kendo-label>
|
|
785
1080
|
</ng-template>
|
|
786
|
-
`, isInline: true }); }
|
|
1081
|
+
`, isInline: true, dependencies: [{ kind: "component", type: i1$2.LabelComponent, selector: "kendo-label", inputs: ["text", "for", "optional", "labelCssStyle", "labelCssClass"], exportAs: ["kendoLabel"] }] }); }
|
|
787
1082
|
}
|
|
788
1083
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.3", ngImport: i0, type: RdictTableTitle, decorators: [{
|
|
789
1084
|
type: Component,
|
|
@@ -791,6 +1086,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.3", ngImpor
|
|
|
791
1086
|
providers: [{ provide: ToolBarToolComponent, useExisting: forwardRef(() => RdictTableTitle) }],
|
|
792
1087
|
selector: 'table-title',
|
|
793
1088
|
standalone: true,
|
|
1089
|
+
imports: [
|
|
1090
|
+
KENDO_LABEL,
|
|
1091
|
+
],
|
|
794
1092
|
template: `
|
|
795
1093
|
<ng-template #toolbarTemplate>
|
|
796
1094
|
<kendo-label>{{text}}</kendo-label>
|
|
@@ -805,26 +1103,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.3", ngImpor
|
|
|
805
1103
|
}] } });
|
|
806
1104
|
|
|
807
1105
|
class GenericRdictTableComponent {
|
|
808
|
-
constructor(router, route, translate, injector,
|
|
1106
|
+
constructor(router, route, translate, injector, localFileService, rdict, dialogService) {
|
|
809
1107
|
this.router = router;
|
|
810
1108
|
this.route = route;
|
|
811
1109
|
this.translate = translate;
|
|
812
1110
|
this.injector = injector;
|
|
813
|
-
this.
|
|
1111
|
+
this.localFileService = localFileService;
|
|
814
1112
|
this.rdict = rdict;
|
|
815
|
-
this.
|
|
816
|
-
"base",
|
|
817
|
-
"primary",
|
|
818
|
-
"secondary",
|
|
819
|
-
"tertiary",
|
|
820
|
-
"info",
|
|
821
|
-
"success",
|
|
822
|
-
"warning",
|
|
823
|
-
"error",
|
|
824
|
-
"dark",
|
|
825
|
-
"light",
|
|
826
|
-
"inverse",
|
|
827
|
-
];
|
|
1113
|
+
this.dialogService = dialogService;
|
|
828
1114
|
this.editOnClick = false;
|
|
829
1115
|
this.editOnDblClick = false;
|
|
830
1116
|
this.data = [];
|
|
@@ -864,6 +1150,8 @@ class GenericRdictTableComponent {
|
|
|
864
1150
|
this.setValueFromSnapshot(this, this.route.snapshot, 'canEdit', true);
|
|
865
1151
|
this.setValueFromSnapshot(this, this.route.snapshot, 'editOnClick', false);
|
|
866
1152
|
this.setValueFromSnapshot(this, this.route.snapshot, 'editOnDblClick', false);
|
|
1153
|
+
this.setValueFromSnapshot(this, this.route.snapshot, 'editColumn', null);
|
|
1154
|
+
this.setValueFromSnapshot(this, this.route.snapshot, 'fileLayout', '');
|
|
867
1155
|
const currentUrlSegments = this.router.url.split('/').map(segment => new UrlSegment(segment, {}));
|
|
868
1156
|
this.basePath = currentUrlSegments.map(segment => segment.path).join('/');
|
|
869
1157
|
const filteredSegments = currentUrlSegments.filter(segment => segment.path !== '');
|
|
@@ -890,48 +1178,147 @@ class GenericRdictTableComponent {
|
|
|
890
1178
|
}
|
|
891
1179
|
}
|
|
892
1180
|
async loadData() {
|
|
893
|
-
this.rdict.
|
|
894
|
-
next:
|
|
895
|
-
this.
|
|
1181
|
+
this.rdict.getAsObservable(this.dictPath).subscribe({
|
|
1182
|
+
next: rdictData => {
|
|
1183
|
+
this.tableRdict = rdictData;
|
|
1184
|
+
this.tableRdict.onChanges().subscribe({
|
|
1185
|
+
next: (changes) => {
|
|
1186
|
+
console.log("Changes detected grid:", changes);
|
|
1187
|
+
this.onChangeEvent(changes);
|
|
1188
|
+
}
|
|
1189
|
+
});
|
|
1190
|
+
this.tableRdict.onDelete().subscribe({
|
|
1191
|
+
next: (changes) => {
|
|
1192
|
+
console.log("Delete detected grid:", changes);
|
|
1193
|
+
this.ondDeleteEvent(changes);
|
|
1194
|
+
}
|
|
1195
|
+
});
|
|
1196
|
+
this.rdict.getTableAsObservable(this.dictPath, this.tableRdict).subscribe({
|
|
1197
|
+
next: value => {
|
|
1198
|
+
this.dataSource = value;
|
|
1199
|
+
},
|
|
1200
|
+
error: err => console.error('Error:', err.message),
|
|
1201
|
+
});
|
|
896
1202
|
},
|
|
897
1203
|
error: err => console.error('Error:', err.message),
|
|
898
1204
|
});
|
|
899
1205
|
}
|
|
1206
|
+
onChangeEvent(changes) {
|
|
1207
|
+
if (changes) {
|
|
1208
|
+
const key = changes?.key;
|
|
1209
|
+
const value = changes?.value;
|
|
1210
|
+
if (key && value) {
|
|
1211
|
+
const index = this.dataSource.findIndex((item) => item.__idx === key);
|
|
1212
|
+
if (index > -1) {
|
|
1213
|
+
this.dataSource[index] = value;
|
|
1214
|
+
}
|
|
1215
|
+
else {
|
|
1216
|
+
//get the object from rdict
|
|
1217
|
+
this.tableRdict.getAsObservable(key).subscribe({
|
|
1218
|
+
next: value => {
|
|
1219
|
+
var dd = value.getPlainObject();
|
|
1220
|
+
this.dataSource.push(dd);
|
|
1221
|
+
}
|
|
1222
|
+
});
|
|
1223
|
+
}
|
|
1224
|
+
}
|
|
1225
|
+
}
|
|
1226
|
+
}
|
|
1227
|
+
ondDeleteEvent(changes) {
|
|
1228
|
+
if (changes) {
|
|
1229
|
+
const key = changes?.key;
|
|
1230
|
+
if (key) {
|
|
1231
|
+
const index = this.dataSource.findIndex((item) => item.__idx === key);
|
|
1232
|
+
if (index > -1) {
|
|
1233
|
+
this.dataSource.splice(index, 1);
|
|
1234
|
+
}
|
|
1235
|
+
// this.tableRdict.delete(key)
|
|
1236
|
+
}
|
|
1237
|
+
}
|
|
1238
|
+
}
|
|
900
1239
|
getListLayout() {
|
|
901
1240
|
if (this.model) {
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
1241
|
+
if (this.fileLayout) {
|
|
1242
|
+
//load from file
|
|
1243
|
+
this.localFileService.getJsonData(this.fileLayout).subscribe({
|
|
1244
|
+
next: value => {
|
|
1245
|
+
if (value) {
|
|
1246
|
+
const layout = value.find(item => item.model === this.model);
|
|
1247
|
+
this.setLayout(layout?.tableLayout);
|
|
1248
|
+
}
|
|
1249
|
+
},
|
|
1250
|
+
error: err => console.error('Error:', err.message),
|
|
1251
|
+
});
|
|
1252
|
+
}
|
|
1253
|
+
else
|
|
1254
|
+
//Use rdict layout
|
|
1255
|
+
this.rdict.getAsObservable("config.models." + this.model + ".tableLayout").subscribe({
|
|
1256
|
+
next: value => {
|
|
1257
|
+
this.setLayout(value);
|
|
1258
|
+
},
|
|
1259
|
+
error: err => console.error('Error:', err.message),
|
|
1260
|
+
});
|
|
1261
|
+
}
|
|
1262
|
+
}
|
|
1263
|
+
setLayout(layout) {
|
|
1264
|
+
if (layout) {
|
|
1265
|
+
this.tableLayout = layout;
|
|
1266
|
+
this.title = this.translate.instant(this.tableLayout["title"]);
|
|
1267
|
+
this.allColumns = this.tableLayout["columns"].map(item => {
|
|
1268
|
+
if (!item.isTranslated) {
|
|
1269
|
+
item.name = this.translate.instant(item.translateKey);
|
|
1270
|
+
item.isTranslated = true;
|
|
1271
|
+
item.isEditLink = false;
|
|
1272
|
+
if (this.editColumn && this.editColumn === item.propertyName) {
|
|
1273
|
+
item.isEditLink = true;
|
|
918
1274
|
}
|
|
919
|
-
}
|
|
920
|
-
|
|
1275
|
+
}
|
|
1276
|
+
return item;
|
|
921
1277
|
});
|
|
1278
|
+
this.columns = [];
|
|
1279
|
+
this.allColumns.sort((a, b) => a.order - b.order);
|
|
1280
|
+
this.displayedColumns = [];
|
|
1281
|
+
this.displayedColumns.push.apply(this.displayedColumns, this.allColumns.map(x => x.propertyName));
|
|
922
1282
|
}
|
|
923
1283
|
}
|
|
924
1284
|
addHandler() {
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
1285
|
+
this.router.navigate([`${this.basePath}/add`]);
|
|
1286
|
+
}
|
|
1287
|
+
editHandler(args) {
|
|
1288
|
+
this.edit(args.dataItem);
|
|
1289
|
+
// this.editDataItem = args.dataItem;
|
|
1290
|
+
// this.isNew = false;
|
|
1291
|
+
}
|
|
1292
|
+
edit(dataItem) {
|
|
1293
|
+
this.router.navigate([`${this.basePath}/edit/${dataItem.__idx}`]);
|
|
1294
|
+
}
|
|
1295
|
+
removeHandler(args) {
|
|
1296
|
+
this.dialogService.confirmDelete().subscribe({
|
|
1297
|
+
next: (result) => {
|
|
1298
|
+
if (result) {
|
|
1299
|
+
this.tableRdict.deleteAsObservable(args.dataItem.__idx).subscribe({
|
|
1300
|
+
next: (result) => {
|
|
1301
|
+
this.dataSource.splice(args.rowIndex, 1);
|
|
1302
|
+
}
|
|
1303
|
+
});
|
|
1304
|
+
}
|
|
1305
|
+
}
|
|
1306
|
+
});
|
|
1307
|
+
// this.editService.remove(args.dataItem);
|
|
1308
|
+
}
|
|
1309
|
+
getCellValue(item, propertyName) {
|
|
1310
|
+
if (item instanceof ReactiveDictionary) {
|
|
1311
|
+
console.log(item);
|
|
1312
|
+
}
|
|
1313
|
+
else {
|
|
1314
|
+
return item[propertyName];
|
|
1315
|
+
}
|
|
929
1316
|
}
|
|
930
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.3", ngImport: i0, type: GenericRdictTableComponent, deps: [{ token: i1$1.Router }, { token: i1$1.ActivatedRoute }, { token: i2.TranslateService }, { token: i0.Injector }, { token:
|
|
931
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.1.3", 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\"
|
|
1317
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.3", ngImport: i0, type: GenericRdictTableComponent, deps: [{ token: i1$1.Router }, { token: i1$1.ActivatedRoute }, { token: i2.TranslateService }, { token: i0.Injector }, { token: i1.LocalFileService }, { token: ReactiveDictionary }, { token: MaterialDialogService }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1318
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.1.3", 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 <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 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\">\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.propertyName) }}\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.propertyName) }}\r\n </ng-template>\r\n </kendo-grid-column>\r\n\r\n\r\n <kendo-grid-command-column 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 kendoGridEditCommand [svgIcon]=\"svgEdit\" themeColor=\"light\"></button>\r\n <button 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: i6$2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i6$2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: RouterModule }, { kind: "ngmodule", type:
|
|
932
1319
|
// MatPaginatorModule,
|
|
933
1320
|
// MatTableModule,
|
|
934
|
-
TranslateModule }, { kind: "pipe", type: i2.TranslatePipe, name: "translate" }, { kind: "component", type:
|
|
1321
|
+
TranslateModule }, { kind: "pipe", type: i2.TranslatePipe, name: "translate" }, { kind: "component", type: i7$1.GridComponent, selector: "kendo-grid", inputs: ["data", "pageSize", "height", "rowHeight", "detailRowHeight", "skip", "scrollable", "selectable", "sort", "size", "trackBy", "filter", "group", "virtualColumns", "filterable", "sortable", "pageable", "groupable", "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: i7$1.GridToolbarFocusableDirective, selector: " [kendoGridToolbarFocusable], [kendoGridAddCommand], [kendoGridCancelCommand], [kendoGridEditCommand], [kendoGridRemoveCommand], [kendoGridSaveCommand], [kendoGridExcelCommand], [kendoGridPDFCommand] " }, { kind: "component", type: i7$1.ColumnComponent, selector: "kendo-grid-column", inputs: ["field", "format", "sortable", "groupable", "editor", "filter", "filterable", "editable"] }, { kind: "directive", type: i7$1.FocusableDirective, selector: "[kendoGridFocusable], [kendoGridEditCommand], [kendoGridRemoveCommand], [kendoGridSaveCommand], [kendoGridCancelCommand], [kendoGridSelectionCheckbox] ", inputs: ["kendoGridFocusable"] }, { kind: "component", type: i7$1.CommandColumnComponent, selector: "kendo-grid-command-column" }, { kind: "directive", type: i7$1.CellTemplateDirective, selector: "[kendoGridCellTemplate]" }, { kind: "component", type: i7$1.EditCommandDirective, selector: "[kendoGridEditCommand]" }, { kind: "component", type: i7$1.RemoveCommandDirective, selector: "[kendoGridRemoveCommand]" }, { kind: "directive", type: i7$1.AddCommandToolbarDirective, selector: "[kendoGridAddTool]" }, { kind: "component", type: i8.ToolBarComponent, selector: "kendo-toolbar", inputs: ["overflow", "resizable", "popupSettings", "fillMode", "tabindex", "size", "tabIndex"], outputs: ["open", "close"], exportAs: ["kendoToolBar"] }, { kind: "component", type: i8.ToolbarCustomMessagesComponent, selector: "kendo-toolbar-messages" }, { kind: "component", type: i8.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: i8.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 }); }
|
|
935
1322
|
}
|
|
936
1323
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.3", ngImport: i0, type: GenericRdictTableComponent, decorators: [{
|
|
937
1324
|
type: Component,
|
|
@@ -945,9 +1332,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.3", ngImpor
|
|
|
945
1332
|
KENDO_TOOLBAR,
|
|
946
1333
|
KENDO_LABEL,
|
|
947
1334
|
KENDO_BUTTONS,
|
|
1335
|
+
KENDO_DIALOG,
|
|
948
1336
|
RdictTableTitle
|
|
949
|
-
], providers: [], template: "<kendo-grid [data]=\"dataSource\"
|
|
950
|
-
}], ctorParameters: () => [{ type: i1$1.Router }, { type: i1$1.ActivatedRoute }, { type: i2.TranslateService }, { type: i0.Injector }, { type:
|
|
1337
|
+
], providers: [], template: "<kendo-grid [data]=\"dataSource\" [sortable]=\"true\" [filterable]=\"showSerach\" [resizable]=\"true\" (add)=\"addHandler()\"\r\n (edit)=\"editHandler($event)\" (remove)=\"removeHandler($event)\">\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 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\">\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.propertyName) }}\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.propertyName) }}\r\n </ng-template>\r\n </kendo-grid-column>\r\n\r\n\r\n <kendo-grid-command-column 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 kendoGridEditCommand [svgIcon]=\"svgEdit\" themeColor=\"light\"></button>\r\n <button 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"] }]
|
|
1338
|
+
}], ctorParameters: () => [{ type: i1$1.Router }, { type: i1$1.ActivatedRoute }, { type: i2.TranslateService }, { type: i0.Injector }, { type: i1.LocalFileService }, { type: ReactiveDictionary }, { type: MaterialDialogService }], propDecorators: { showSerach: [{
|
|
951
1339
|
type: Input
|
|
952
1340
|
}], searchFields: [{
|
|
953
1341
|
type: Input
|