retold-data-service 2.0.21 → 2.0.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/.quackage-comprehension-loader.json +19 -0
  2. package/bin/retold-data-service-clone.js +4 -1
  3. package/generate-bookstore-comprehension.js +645 -0
  4. package/package.json +7 -7
  5. package/source/Retold-Data-Service.js +30 -2
  6. package/source/services/comprehension-loader/ComprehensionLoader-Command-Load.js +345 -0
  7. package/source/services/comprehension-loader/ComprehensionLoader-Command-Schema.js +97 -0
  8. package/source/services/comprehension-loader/ComprehensionLoader-Command-Session.js +221 -0
  9. package/source/services/comprehension-loader/ComprehensionLoader-Command-WebUI.js +57 -0
  10. package/source/services/comprehension-loader/Retold-Data-Service-ComprehensionLoader.js +536 -0
  11. package/source/services/comprehension-loader/pict-app/Pict-Application-ComprehensionLoader-Configuration.json +9 -0
  12. package/source/services/comprehension-loader/pict-app/Pict-Application-ComprehensionLoader.js +86 -0
  13. package/source/services/comprehension-loader/pict-app/Pict-ComprehensionLoader-Bundle.js +6 -0
  14. package/source/services/comprehension-loader/pict-app/providers/Pict-Provider-ComprehensionLoader.js +760 -0
  15. package/source/services/comprehension-loader/pict-app/views/PictView-ComprehensionLoader-Layout.js +360 -0
  16. package/source/services/comprehension-loader/pict-app/views/PictView-ComprehensionLoader-Load.js +472 -0
  17. package/source/services/comprehension-loader/pict-app/views/PictView-ComprehensionLoader-Schema.js +119 -0
  18. package/source/services/comprehension-loader/pict-app/views/PictView-ComprehensionLoader-Session.js +269 -0
  19. package/source/services/comprehension-loader/pict-app/views/PictView-ComprehensionLoader-Source.js +330 -0
  20. package/source/services/comprehension-loader/web/comprehension-loader.js +6794 -0
  21. package/source/services/comprehension-loader/web/comprehension-loader.js.map +1 -0
  22. package/source/services/comprehension-loader/web/comprehension-loader.min.js +2 -0
  23. package/source/services/comprehension-loader/web/comprehension-loader.min.js.map +1 -0
  24. package/source/services/comprehension-loader/web/index.html +17 -0
  25. package/source/services/data-cloner/DataCloner-Command-Schema.js +407 -15
  26. package/source/services/data-cloner/Retold-Data-Service-DataCloner.js +59 -1
  27. package/source/services/data-cloner/pict-app/Pict-Application-DataCloner.js +1 -0
  28. package/source/services/data-cloner/pict-app/providers/Pict-Provider-DataCloner.js +125 -5
  29. package/source/services/data-cloner/pict-app/views/PictView-DataCloner-Connection.js +18 -8
  30. package/source/services/data-cloner/pict-app/views/PictView-DataCloner-Deploy.js +104 -1
  31. package/source/services/data-cloner/pict-app/views/PictView-DataCloner-Export.js +1 -1
  32. package/source/services/data-cloner/pict-app/views/PictView-DataCloner-Layout.js +12 -0
  33. package/source/services/data-cloner/web/data-cloner.js +201 -139
  34. package/source/services/data-cloner/web/data-cloner.js.map +1 -1
  35. package/source/services/data-cloner/web/data-cloner.min.js +1 -1
  36. package/source/services/data-cloner/web/data-cloner.min.js.map +1 -1
  37. package/test/RetoldDataService_tests.js +225 -0
@@ -0,0 +1,536 @@
1
+ /**
2
+ * Retold Data Service - Comprehension Loader Service
3
+ *
4
+ * Fable service that pushes comprehension data to a remote retold-based server.
5
+ * Provides REST endpoints for session management, schema discovery,
6
+ * comprehension ingestion, and entity-by-entity load orchestration.
7
+ *
8
+ * Two route groups:
9
+ * connectRoutes() - JSON API endpoints under /comprehension_load/*
10
+ * connectWebUIRoutes() - Web UI HTML serving at /comprehension_load/
11
+ *
12
+ * @author Steven Velozo <steven@velozo.com>
13
+ */
14
+ const libFableServiceProviderBase = require('fable-serviceproviderbase');
15
+
16
+ const libPath = require('path');
17
+
18
+ const libPict = require('pict');
19
+ const libPictSessionManager = require('pict-sessionmanager');
20
+
21
+ // Resolve the meadow-integration IntegrationAdapter
22
+ const _MeadowIntegrationBase = libPath.dirname(require.resolve('meadow-integration/package.json'));
23
+ const libIntegrationAdapter = require(libPath.join(_MeadowIntegrationBase, 'source/Meadow-Service-Integration-Adapter.js'));
24
+
25
+ const defaultComprehensionLoaderOptions = (
26
+ {
27
+ RoutePrefix: '/comprehension_load'
28
+ });
29
+
30
+ class RetoldDataServiceComprehensionLoader extends libFableServiceProviderBase
31
+ {
32
+ constructor(pFable, pOptions, pServiceHash)
33
+ {
34
+ let tmpOptions = Object.assign({}, defaultComprehensionLoaderOptions, pOptions);
35
+ super(pFable, tmpOptions, pServiceHash);
36
+
37
+ this.serviceType = 'RetoldDataServiceComprehensionLoader';
38
+
39
+ // Load state - tracks session, schema, comprehension, and push progress
40
+ this._loadState = (
41
+ {
42
+ // Remote session
43
+ SessionConfigured: false,
44
+ SessionAuthenticated: false,
45
+ RemoteServerURL: '',
46
+
47
+ // Remote schema (fetched to discover valid entities)
48
+ RemoteSchema: false,
49
+ RemoteEntityList: [],
50
+
51
+ // Comprehension data (received from browser)
52
+ ComprehensionData: null,
53
+ ComprehensionEntityList: [],
54
+ ComprehensionRecordCounts: {},
55
+ ComprehensionTotalRecords: 0,
56
+
57
+ // Load progress
58
+ LoadRunning: false,
59
+ LoadStopping: false,
60
+ LoadProgress: {},
61
+ LoadStartTime: null,
62
+ LoadEndTime: null,
63
+ LoadEventLog: [],
64
+ LoadReport: null,
65
+
66
+ // Throughput sampling - records per 10-second window
67
+ ThroughputSamples: [],
68
+ ThroughputTimer: null
69
+ });
70
+
71
+ // Create an isolated Pict instance for remote session management
72
+ this._Pict = new libPict(
73
+ {
74
+ Product: 'ComprehensionLoaderSession',
75
+ TraceLog: true,
76
+ LogStreams:
77
+ [
78
+ {
79
+ streamtype: 'console'
80
+ }
81
+ ]
82
+ });
83
+
84
+ this._Pict.serviceManager.addServiceType('SessionManager', libPictSessionManager);
85
+ this._Pict.serviceManager.instantiateServiceProvider('SessionManager');
86
+ }
87
+
88
+ /**
89
+ * The route prefix for all comprehension loader endpoints.
90
+ */
91
+ get routePrefix()
92
+ {
93
+ let tmpConfig = this.fable.RetoldDataService.options.ComprehensionLoader || {};
94
+ return tmpConfig.RoutePrefix || this.options.RoutePrefix || '/comprehension_load';
95
+ }
96
+
97
+ /**
98
+ * The load state object.
99
+ */
100
+ get loadState()
101
+ {
102
+ return this._loadState;
103
+ }
104
+
105
+ /**
106
+ * The isolated Pict instance for session management.
107
+ */
108
+ get pict()
109
+ {
110
+ return this._Pict;
111
+ }
112
+
113
+ /**
114
+ * The IntegrationAdapter class.
115
+ */
116
+ get IntegrationAdapter()
117
+ {
118
+ return libIntegrationAdapter;
119
+ }
120
+
121
+ // ================================================================
122
+ // Comprehension Management
123
+ // ================================================================
124
+
125
+ /**
126
+ * Load comprehension data into state. Extracts entity names and counts.
127
+ *
128
+ * @param {object} pComprehensionData - The comprehension JSON object
129
+ * @return {object} Summary with entity list and record counts
130
+ */
131
+ loadComprehension(pComprehensionData)
132
+ {
133
+ this._loadState.ComprehensionData = pComprehensionData;
134
+ this._loadState.ComprehensionEntityList = Object.keys(pComprehensionData);
135
+ this._loadState.ComprehensionRecordCounts = {};
136
+ this._loadState.ComprehensionTotalRecords = 0;
137
+
138
+ for (let i = 0; i < this._loadState.ComprehensionEntityList.length; i++)
139
+ {
140
+ let tmpEntityName = this._loadState.ComprehensionEntityList[i];
141
+ let tmpEntityData = pComprehensionData[tmpEntityName];
142
+ let tmpCount = 0;
143
+
144
+ if (Array.isArray(tmpEntityData))
145
+ {
146
+ tmpCount = tmpEntityData.length;
147
+ }
148
+ else if (typeof tmpEntityData === 'object' && tmpEntityData !== null)
149
+ {
150
+ tmpCount = Object.keys(tmpEntityData).length;
151
+ }
152
+
153
+ this._loadState.ComprehensionRecordCounts[tmpEntityName] = tmpCount;
154
+ this._loadState.ComprehensionTotalRecords += tmpCount;
155
+ }
156
+
157
+ return (
158
+ {
159
+ EntityList: this._loadState.ComprehensionEntityList,
160
+ RecordCounts: this._loadState.ComprehensionRecordCounts,
161
+ TotalRecords: this._loadState.ComprehensionTotalRecords
162
+ });
163
+ }
164
+
165
+ /**
166
+ * Clear loaded comprehension data.
167
+ */
168
+ clearComprehension()
169
+ {
170
+ this._loadState.ComprehensionData = null;
171
+ this._loadState.ComprehensionEntityList = [];
172
+ this._loadState.ComprehensionRecordCounts = {};
173
+ this._loadState.ComprehensionTotalRecords = 0;
174
+ }
175
+
176
+ // ================================================================
177
+ // Push Orchestration
178
+ // ================================================================
179
+
180
+ /**
181
+ * Helper to extract capital letters from a string for GUID prefix.
182
+ */
183
+ getCapitalLettersAsString(pInputString)
184
+ {
185
+ let tmpRegex = /[A-Z]/g;
186
+ let tmpMatch = pInputString.match(tmpRegex);
187
+ return tmpMatch ? tmpMatch.join('') : 'UNK';
188
+ }
189
+
190
+ /**
191
+ * Push comprehension entities to the remote server, one at a time.
192
+ *
193
+ * @param {Array<string>} pEntityList - Entity names to push
194
+ */
195
+ pushEntities(pEntityList)
196
+ {
197
+ this._loadState.LoadRunning = true;
198
+ this._loadState.LoadStopping = false;
199
+ this._loadState.LoadStartTime = new Date().toJSON();
200
+ this._loadState.LoadEndTime = null;
201
+ this._loadState.LoadEventLog = [];
202
+ this._loadState.LoadReport = null;
203
+
204
+ // Initialize progress for each entity
205
+ for (let i = 0; i < pEntityList.length; i++)
206
+ {
207
+ let tmpEntityName = pEntityList[i];
208
+ this._loadState.LoadProgress[tmpEntityName] = (
209
+ {
210
+ Status: 'Pending',
211
+ Total: this._loadState.ComprehensionRecordCounts[tmpEntityName] || 0,
212
+ Pushed: 0,
213
+ Errors: 0,
214
+ ErrorMessage: null,
215
+ StartTime: null,
216
+ EndTime: null
217
+ });
218
+ }
219
+
220
+ this.logLoadEvent('RunStart', `Load started: ${pEntityList.length} entities, ${this._loadState.ComprehensionTotalRecords} total records`);
221
+
222
+ this.startThroughputSampling();
223
+
224
+ let tmpEntityIndex = 0;
225
+
226
+ let fPushNextEntity = () =>
227
+ {
228
+ if (this._loadState.LoadStopping || tmpEntityIndex >= pEntityList.length)
229
+ {
230
+ this.stopThroughputSampling();
231
+ this._loadState.LoadRunning = false;
232
+ this._loadState.LoadEndTime = new Date().toJSON();
233
+
234
+ if (this._loadState.LoadStopping)
235
+ {
236
+ this.logLoadEvent('RunStopped', 'Load was stopped by user request.');
237
+ }
238
+ else
239
+ {
240
+ this.logLoadEvent('RunComplete', 'Load finished.');
241
+ }
242
+
243
+ this._loadState.LoadStopping = false;
244
+ this.generateLoadReport();
245
+ this.fable.log.info('Comprehension Loader: Load complete.');
246
+ return;
247
+ }
248
+
249
+ let tmpEntityName = pEntityList[tmpEntityIndex];
250
+ tmpEntityIndex++;
251
+
252
+ let tmpProgress = this._loadState.LoadProgress[tmpEntityName];
253
+ if (!tmpProgress)
254
+ {
255
+ fPushNextEntity();
256
+ return;
257
+ }
258
+
259
+ tmpProgress.Status = 'Pushing';
260
+ tmpProgress.StartTime = new Date().toJSON();
261
+
262
+ this.logLoadEvent('EntityStart', `Push [${tmpEntityName}] - starting.`, { Entity: tmpEntityName });
263
+ this.fable.log.info(`Comprehension Loader: Push [${tmpEntityName}] - starting via IntegrationAdapter...`);
264
+
265
+ let tmpEntityData = this._loadState.ComprehensionData[tmpEntityName];
266
+ if (!tmpEntityData)
267
+ {
268
+ tmpProgress.Status = 'Complete';
269
+ tmpProgress.EndTime = new Date().toJSON();
270
+ this.logLoadEvent('EntityComplete', `Push [${tmpEntityName}] - no data.`, { Entity: tmpEntityName });
271
+ fPushNextEntity();
272
+ return;
273
+ }
274
+
275
+ // Use the IntegrationAdapter to marshal and push records
276
+ let tmpAdapterPrefix = this.getCapitalLettersAsString(tmpEntityName);
277
+ libIntegrationAdapter.getAdapter(this._Pict, tmpEntityName, tmpAdapterPrefix, { SimpleMarshal: true, ForceMarshal: true });
278
+
279
+ let tmpAdapter = this._Pict.servicesMap.IntegrationAdapter[tmpEntityName];
280
+ if (!tmpAdapter)
281
+ {
282
+ tmpProgress.Status = 'Error';
283
+ tmpProgress.ErrorMessage = 'Failed to create IntegrationAdapter.';
284
+ tmpProgress.EndTime = new Date().toJSON();
285
+ this.logLoadEvent('EntityError', `Push [${tmpEntityName}] - adapter creation failed.`, { Entity: tmpEntityName });
286
+ fPushNextEntity();
287
+ return;
288
+ }
289
+
290
+ tmpAdapter.options.ServerURL = this._loadState.RemoteServerURL;
291
+
292
+ // Add source records
293
+ if (Array.isArray(tmpEntityData))
294
+ {
295
+ for (let r = 0; r < tmpEntityData.length; r++)
296
+ {
297
+ tmpAdapter.addSourceRecord(tmpEntityData[r]);
298
+ }
299
+ }
300
+ else if (typeof tmpEntityData === 'object')
301
+ {
302
+ let tmpKeys = Object.keys(tmpEntityData);
303
+ for (let r = 0; r < tmpKeys.length; r++)
304
+ {
305
+ tmpAdapter.addSourceRecord(tmpEntityData[tmpKeys[r]]);
306
+ }
307
+ }
308
+
309
+ // Integrate records (marshal + push to remote)
310
+ tmpAdapter.integrateRecords(
311
+ (pError) =>
312
+ {
313
+ if (pError)
314
+ {
315
+ this.fable.log.error(`Comprehension Loader: Error pushing [${tmpEntityName}]: ${pError}`);
316
+ tmpProgress.Status = 'Error';
317
+ tmpProgress.ErrorMessage = `${pError}`;
318
+ tmpProgress.Errors = 1;
319
+ this.logLoadEvent('EntityError', `Push [${tmpEntityName}] - error: ${pError}`, { Entity: tmpEntityName, Error: `${pError}` });
320
+ }
321
+ else
322
+ {
323
+ tmpProgress.Status = 'Complete';
324
+ tmpProgress.Pushed = tmpProgress.Total;
325
+ this.fable.log.info(`Comprehension Loader: Push [${tmpEntityName}] - complete. ${tmpProgress.Total} records.`);
326
+ this.logLoadEvent('EntityComplete', `Push [${tmpEntityName}] - complete. ${tmpProgress.Total} records.`,
327
+ { Entity: tmpEntityName, Total: tmpProgress.Total });
328
+ }
329
+
330
+ tmpProgress.EndTime = new Date().toJSON();
331
+ fPushNextEntity();
332
+ });
333
+ };
334
+
335
+ fPushNextEntity();
336
+ }
337
+
338
+ // ================================================================
339
+ // Throughput Sampling
340
+ // ================================================================
341
+
342
+ startThroughputSampling()
343
+ {
344
+ this.stopThroughputSampling();
345
+ this._loadState.ThroughputSamples = [];
346
+ this._loadState.ThroughputSamples.push({ t: Date.now(), pushed: 0 });
347
+
348
+ this._loadState.ThroughputTimer = setInterval(
349
+ () =>
350
+ {
351
+ let tmpTotalPushed = 0;
352
+ let tmpEntityNames = Object.keys(this._loadState.LoadProgress);
353
+ for (let i = 0; i < tmpEntityNames.length; i++)
354
+ {
355
+ tmpTotalPushed += (this._loadState.LoadProgress[tmpEntityNames[i]].Pushed || 0);
356
+ }
357
+ this._loadState.ThroughputSamples.push({ t: Date.now(), pushed: tmpTotalPushed });
358
+ }, 10000);
359
+ }
360
+
361
+ stopThroughputSampling()
362
+ {
363
+ if (this._loadState.ThroughputTimer)
364
+ {
365
+ clearInterval(this._loadState.ThroughputTimer);
366
+ this._loadState.ThroughputTimer = null;
367
+ }
368
+ if (this._loadState.ThroughputSamples && this._loadState.ThroughputSamples.length > 0)
369
+ {
370
+ let tmpTotalPushed = 0;
371
+ let tmpEntityNames = Object.keys(this._loadState.LoadProgress);
372
+ for (let i = 0; i < tmpEntityNames.length; i++)
373
+ {
374
+ tmpTotalPushed += (this._loadState.LoadProgress[tmpEntityNames[i]].Pushed || 0);
375
+ }
376
+ this._loadState.ThroughputSamples.push({ t: Date.now(), pushed: tmpTotalPushed });
377
+ }
378
+ }
379
+
380
+ // ================================================================
381
+ // Event Logging & Report
382
+ // ================================================================
383
+
384
+ logLoadEvent(pType, pMessage, pData)
385
+ {
386
+ this._loadState.LoadEventLog.push(
387
+ {
388
+ Timestamp: new Date().toJSON(),
389
+ Type: pType,
390
+ Message: pMessage,
391
+ Data: pData || undefined
392
+ });
393
+ }
394
+
395
+ generateLoadReport()
396
+ {
397
+ let tmpState = this._loadState;
398
+ let tmpEntityNames = Object.keys(tmpState.LoadProgress);
399
+
400
+ let tmpEntities = [];
401
+ let tmpTotalRecords = 0;
402
+ let tmpTotalPushed = 0;
403
+ let tmpTotalErrors = 0;
404
+ let tmpComplete = 0;
405
+ let tmpErrors = 0;
406
+ let tmpPending = 0;
407
+
408
+ for (let i = 0; i < tmpEntityNames.length; i++)
409
+ {
410
+ let tmpName = tmpEntityNames[i];
411
+ let tmpP = tmpState.LoadProgress[tmpName];
412
+
413
+ let tmpDuration = 0;
414
+ if (tmpP.StartTime && tmpP.EndTime)
415
+ {
416
+ tmpDuration = Math.round((new Date(tmpP.EndTime).getTime() - new Date(tmpP.StartTime).getTime()) / 1000);
417
+ }
418
+
419
+ tmpEntities.push(
420
+ {
421
+ Name: tmpName,
422
+ Status: tmpP.Status,
423
+ Total: tmpP.Total || 0,
424
+ Pushed: tmpP.Pushed || 0,
425
+ Errors: tmpP.Errors || 0,
426
+ ErrorMessage: tmpP.ErrorMessage || null,
427
+ StartTime: tmpP.StartTime || null,
428
+ EndTime: tmpP.EndTime || null,
429
+ DurationSeconds: tmpDuration
430
+ });
431
+
432
+ tmpTotalRecords += (tmpP.Total || 0);
433
+ tmpTotalPushed += (tmpP.Pushed || 0);
434
+ tmpTotalErrors += (tmpP.Errors || 0);
435
+
436
+ if (tmpP.Status === 'Complete') tmpComplete++;
437
+ else if (tmpP.Status === 'Error') tmpErrors++;
438
+ else tmpPending++;
439
+ }
440
+
441
+ tmpEntities.sort((a, b) => b.DurationSeconds - a.DurationSeconds);
442
+
443
+ let tmpOutcome = 'Success';
444
+ if (tmpState.LoadStopping || (!tmpState.LoadRunning && tmpPending > 0))
445
+ {
446
+ tmpOutcome = 'Stopped';
447
+ }
448
+ else if (tmpErrors > 0)
449
+ {
450
+ tmpOutcome = 'Error';
451
+ }
452
+
453
+ let tmpAnomalies = [];
454
+ for (let i = 0; i < tmpEntities.length; i++)
455
+ {
456
+ let tmpE = tmpEntities[i];
457
+ if (tmpE.Status === 'Error')
458
+ {
459
+ tmpAnomalies.push(
460
+ {
461
+ Entity: tmpE.Name,
462
+ Type: 'Error',
463
+ Message: tmpE.ErrorMessage || 'Unknown error'
464
+ });
465
+ }
466
+ else if (tmpE.Status === 'Pending')
467
+ {
468
+ tmpAnomalies.push(
469
+ {
470
+ Entity: tmpE.Name,
471
+ Type: 'Skipped',
472
+ Message: 'Load was stopped before this entity was processed'
473
+ });
474
+ }
475
+ }
476
+
477
+ let tmpRunDuration = 0;
478
+ if (tmpState.LoadStartTime && tmpState.LoadEndTime)
479
+ {
480
+ tmpRunDuration = Math.round((new Date(tmpState.LoadEndTime).getTime() - new Date(tmpState.LoadStartTime).getTime()) / 1000);
481
+ }
482
+
483
+ let tmpReport = (
484
+ {
485
+ ReportVersion: '1.0.0',
486
+ Outcome: tmpOutcome,
487
+ RunTimestamps:
488
+ {
489
+ Start: tmpState.LoadStartTime,
490
+ End: tmpState.LoadEndTime,
491
+ DurationSeconds: tmpRunDuration
492
+ },
493
+ Summary:
494
+ {
495
+ TotalEntities: tmpEntityNames.length,
496
+ Complete: tmpComplete,
497
+ Errors: tmpErrors,
498
+ Pending: tmpPending,
499
+ TotalRecords: tmpTotalRecords,
500
+ TotalPushed: tmpTotalPushed,
501
+ TotalErrors: tmpTotalErrors
502
+ },
503
+ Entities: tmpEntities,
504
+ Anomalies: tmpAnomalies,
505
+ EventLog: tmpState.LoadEventLog,
506
+ ThroughputSamples: tmpState.ThroughputSamples || []
507
+ });
508
+
509
+ tmpState.LoadReport = tmpReport;
510
+ return tmpReport;
511
+ }
512
+
513
+ // ================================================================
514
+ // Route Registration
515
+ // ================================================================
516
+
517
+ connectRoutes(pOratorServiceServer)
518
+ {
519
+ require('./ComprehensionLoader-Command-Session.js')(this, pOratorServiceServer);
520
+ require('./ComprehensionLoader-Command-Schema.js')(this, pOratorServiceServer);
521
+ require('./ComprehensionLoader-Command-Load.js')(this, pOratorServiceServer);
522
+
523
+ this.fable.log.info('Retold Data Service ComprehensionLoader API routes registered.');
524
+ }
525
+
526
+ connectWebUIRoutes(pOratorServiceServer)
527
+ {
528
+ require('./ComprehensionLoader-Command-WebUI.js')(this, pOratorServiceServer);
529
+
530
+ this.fable.log.info('Retold Data Service ComprehensionLoader Web UI routes registered.');
531
+ }
532
+ }
533
+
534
+ module.exports = RetoldDataServiceComprehensionLoader;
535
+ module.exports.serviceType = 'RetoldDataServiceComprehensionLoader';
536
+ module.exports.default_configuration = defaultComprehensionLoaderOptions;
@@ -0,0 +1,9 @@
1
+ {
2
+ "Name": "Retold Comprehension Loader",
3
+ "Hash": "ComprehensionLoader",
4
+ "MainViewportViewIdentifier": "ComprehensionLoader-Layout",
5
+ "MainViewportDestinationAddress": "#ComprehensionLoader-Application-Container",
6
+ "MainViewportDefaultDataAddress": "AppData.ComprehensionLoader",
7
+ "pict_configuration": { "Product": "ComprehensionLoader" },
8
+ "AutoRenderMainViewportViewAfterInitialize": false
9
+ }
@@ -0,0 +1,86 @@
1
+ const libPictApplication = require('pict-application');
2
+
3
+ const libProvider = require('./providers/Pict-Provider-ComprehensionLoader.js');
4
+
5
+ const libViewLayout = require('./views/PictView-ComprehensionLoader-Layout.js');
6
+ const libViewSession = require('./views/PictView-ComprehensionLoader-Session.js');
7
+ const libViewSchema = require('./views/PictView-ComprehensionLoader-Schema.js');
8
+ const libViewSource = require('./views/PictView-ComprehensionLoader-Source.js');
9
+ const libViewLoad = require('./views/PictView-ComprehensionLoader-Load.js');
10
+ const libViewHistogram = require('pict-section-histogram');
11
+
12
+ class ComprehensionLoaderApplication extends libPictApplication
13
+ {
14
+ constructor(pFable, pOptions, pServiceHash)
15
+ {
16
+ super(pFable, pOptions, pServiceHash);
17
+
18
+ // Register provider
19
+ this.pict.addProvider('ComprehensionLoader', libProvider.default_configuration, libProvider);
20
+
21
+ // Register views
22
+ this.pict.addView('ComprehensionLoader-Layout', libViewLayout.default_configuration, libViewLayout);
23
+ this.pict.addView('ComprehensionLoader-Session', libViewSession.default_configuration, libViewSession);
24
+ this.pict.addView('ComprehensionLoader-Schema', libViewSchema.default_configuration, libViewSchema);
25
+ this.pict.addView('ComprehensionLoader-Source', libViewSource.default_configuration, libViewSource);
26
+ this.pict.addView('ComprehensionLoader-Load', libViewLoad.default_configuration, libViewLoad);
27
+ this.pict.addView('ComprehensionLoader-StatusHistogram',
28
+ {
29
+ ViewIdentifier: 'ComprehensionLoader-StatusHistogram',
30
+ TargetElementAddress: '#ComprehensionLoader-Throughput-Histogram',
31
+ DefaultDestinationAddress: '#ComprehensionLoader-Throughput-Histogram',
32
+ RenderOnLoad: false,
33
+ Selectable: false,
34
+ Orientation: 'vertical',
35
+ FillContainer: true,
36
+ ShowValues: false,
37
+ ShowLabels: true,
38
+ MaxBarSize: 80,
39
+ BarColor: '#4a90d9',
40
+ Bins: []
41
+ }, libViewHistogram);
42
+ }
43
+
44
+ onAfterInitializeAsync(fCallback)
45
+ {
46
+ // Centralized state
47
+ this.pict.AppData.ComprehensionLoader =
48
+ {
49
+ FetchedEntities: [],
50
+ LastReport: null,
51
+ ServerBusyAtLoad: false,
52
+ LoadPollTimer: null,
53
+ LiveStatusTimer: null,
54
+ StatusDetailExpanded: false,
55
+ StatusDetailTimer: null,
56
+ StatusDetailData: null,
57
+ LastLiveStatus: null,
58
+ PersistFields: [
59
+ 'serverURL', 'authMethod', 'authURI', 'checkURI',
60
+ 'cookieName', 'cookieValueAddr', 'cookieValueTemplate', 'loginMarker',
61
+ 'userName', 'password', 'schemaURL',
62
+ 'comprehensionSourceMode', 'comprehensionURL'
63
+ ]
64
+ };
65
+
66
+ // Make pict available for inline onclick handlers
67
+ window.pict = this.pict;
68
+
69
+ // Render layout (which chains child view renders via onAfterRender)
70
+ this.pict.views['ComprehensionLoader-Layout'].render();
71
+
72
+ // Post-render initialization
73
+ this.pict.providers.ComprehensionLoader.initPersistence();
74
+ this.pict.providers.ComprehensionLoader.startLiveStatusPolling();
75
+ this.pict.providers.ComprehensionLoader.initAccordionPreviews();
76
+ this.pict.providers.ComprehensionLoader.updateAllPreviews();
77
+ this.pict.views['ComprehensionLoader-Layout'].collapseAllSections();
78
+ this.pict.providers.ComprehensionLoader.initAutoProcess();
79
+
80
+ return fCallback();
81
+ }
82
+ }
83
+
84
+ module.exports = ComprehensionLoaderApplication;
85
+
86
+ module.exports.default_configuration = require('./Pict-Application-ComprehensionLoader-Configuration.json');
@@ -0,0 +1,6 @@
1
+ module.exports = { ComprehensionLoaderApplication: require('./Pict-Application-ComprehensionLoader.js') };
2
+
3
+ if (typeof(window) !== 'undefined')
4
+ {
5
+ window.ComprehensionLoaderApplication = module.exports.ComprehensionLoaderApplication;
6
+ }