retold-data-service 2.0.43 → 2.1.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/.github/workflows/publish-image.yml +66 -0
- package/BUILDING-AND-PUBLISHING.md +140 -0
- package/Dockerfile +21 -0
- package/package.json +25 -14
- package/source/services/data-cloner/DataCloner-Command-Connection.js +41 -1
- package/source/services/data-cloner/pict-app/Pict-Application-DataCloner.js +50 -16
- package/source/services/data-cloner/pict-app/providers/Pict-Provider-DataCloner.js +185 -96
- package/source/services/data-cloner/pict-app/views/PictView-DataCloner-Connection.js +181 -383
- package/source/services/data-cloner/pict-app/views/PictView-DataCloner-Export.js +34 -57
- package/source/services/data-cloner/web/data-cloner.js +1116 -530
- package/source/services/data-cloner/web/data-cloner.js.map +1 -1
- package/source/services/data-cloner/web/data-cloner.min.js +1 -1
- package/source/services/data-cloner/web/data-cloner.min.js.map +1 -1
|
@@ -76,60 +76,25 @@ class DataClonerProvider extends libPictProvider
|
|
|
76
76
|
|
|
77
77
|
updateAllPreviews()
|
|
78
78
|
{
|
|
79
|
-
// Section 1 — Database Connection
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
let tmpHost = document.getElementById('mysqlServer').value || '127.0.0.1';
|
|
92
|
-
let tmpPort = document.getElementById('mysqlPort').value || '3306';
|
|
93
|
-
let tmpUser = document.getElementById('mysqlUser').value || 'root';
|
|
94
|
-
tmpPreview1 = 'MySQL on ' + tmpHost + ':' + tmpPort + ' as ' + tmpUser;
|
|
95
|
-
}
|
|
96
|
-
else if (tmpProvider === 'MSSQL')
|
|
97
|
-
{
|
|
98
|
-
let tmpHost = document.getElementById('mssqlServer').value || '127.0.0.1';
|
|
99
|
-
let tmpPort = document.getElementById('mssqlPort').value || '1433';
|
|
100
|
-
let tmpUser = document.getElementById('mssqlUser').value || 'sa';
|
|
101
|
-
tmpPreview1 = 'MSSQL on ' + tmpHost + ':' + tmpPort + ' as ' + tmpUser;
|
|
102
|
-
}
|
|
103
|
-
else if (tmpProvider === 'PostgreSQL')
|
|
104
|
-
{
|
|
105
|
-
let tmpHost = document.getElementById('postgresqlHost').value || '127.0.0.1';
|
|
106
|
-
let tmpPort = document.getElementById('postgresqlPort').value || '5432';
|
|
107
|
-
let tmpUser = document.getElementById('postgresqlUser').value || 'postgres';
|
|
108
|
-
tmpPreview1 = 'PostgreSQL on ' + tmpHost + ':' + tmpPort + ' as ' + tmpUser;
|
|
109
|
-
}
|
|
110
|
-
else if (tmpProvider === 'MongoDB')
|
|
111
|
-
{
|
|
112
|
-
let tmpHost = document.getElementById('mongodbHost').value || '127.0.0.1';
|
|
113
|
-
let tmpPort = document.getElementById('mongodbPort').value || '27017';
|
|
114
|
-
tmpPreview1 = 'MongoDB on ' + tmpHost + ':' + tmpPort;
|
|
115
|
-
}
|
|
116
|
-
else if (tmpProvider === 'Solr')
|
|
117
|
-
{
|
|
118
|
-
let tmpHost = document.getElementById('solrHost').value || '127.0.0.1';
|
|
119
|
-
let tmpPort = document.getElementById('solrPort').value || '8983';
|
|
120
|
-
tmpPreview1 = 'Solr on ' + tmpHost + ':' + tmpPort;
|
|
79
|
+
// Section 1 — Database Connection (schema-driven; the
|
|
80
|
+
// Connection view owns the heuristic that turns the active
|
|
81
|
+
// schema's field values into preview text). The view's
|
|
82
|
+
// _buildPreviewText reads live DOM values for the active
|
|
83
|
+
// provider and falls back to schema Defaults if a field's
|
|
84
|
+
// element doesn't exist yet.
|
|
85
|
+
let tmpConnView = this.pict.views['DataCloner-Connection'];
|
|
86
|
+
let tmpConnState = (this.pict.AppData.DataCloner && this.pict.AppData.DataCloner.Connection) || null;
|
|
87
|
+
let tmpPreview1Text;
|
|
88
|
+
if (tmpConnView && tmpConnState && (tmpConnState.Schemas || []).length > 0)
|
|
89
|
+
{
|
|
90
|
+
tmpPreview1Text = tmpConnView._buildPreviewText(tmpConnState);
|
|
121
91
|
}
|
|
122
|
-
else
|
|
123
|
-
{
|
|
124
|
-
let tmpFolder = document.getElementById('rocksdbFolder').value || '~/headlight-liveconnect-local/rocksdb';
|
|
125
|
-
tmpPreview1 = 'RocksDB at ' + tmpFolder;
|
|
126
|
-
}
|
|
127
|
-
else if (tmpProvider === 'Bibliograph')
|
|
92
|
+
else
|
|
128
93
|
{
|
|
129
|
-
|
|
130
|
-
tmpPreview1 = 'Bibliograph at ' + tmpFolder;
|
|
94
|
+
tmpPreview1Text = (tmpConnState && tmpConnState.PreviewText) || 'Loading providers…';
|
|
131
95
|
}
|
|
132
|
-
document.getElementById('preview1')
|
|
96
|
+
let tmpPreview1El = document.getElementById('preview1');
|
|
97
|
+
if (tmpPreview1El) { tmpPreview1El.textContent = tmpPreview1Text; }
|
|
133
98
|
|
|
134
99
|
// Section 2 — Remote Session
|
|
135
100
|
let tmpServerURL = document.getElementById('serverURL').value;
|
|
@@ -210,14 +175,12 @@ class DataClonerProvider extends libPictProvider
|
|
|
210
175
|
{
|
|
211
176
|
let tmpSelf = this;
|
|
212
177
|
|
|
178
|
+
// Static (non-connection) fields that drive accordion previews.
|
|
179
|
+
// Connection-section fields hook updateAllPreviews via
|
|
180
|
+
// _persistConnectionFields() once schemas load — see
|
|
181
|
+
// bootstrapConnectionSchemas().
|
|
213
182
|
let tmpPreviewFields = [
|
|
214
|
-
'connProvider',
|
|
215
|
-
'mysqlServer', 'mysqlPort', 'mysqlUser',
|
|
216
|
-
'mssqlServer', 'mssqlPort', 'mssqlUser',
|
|
217
|
-
'postgresqlHost', 'postgresqlPort', 'postgresqlUser',
|
|
218
|
-
'mongodbHost', 'mongodbPort',
|
|
219
|
-
'solrHost', 'solrPort',
|
|
220
|
-
'rocksdbFolder', 'bibliographFolder',
|
|
183
|
+
'connProvider',
|
|
221
184
|
'serverURL', 'userName',
|
|
222
185
|
'schemaURL',
|
|
223
186
|
'pageSize', 'dateTimePrecisionMS',
|
|
@@ -258,7 +221,17 @@ class DataClonerProvider extends libPictProvider
|
|
|
258
221
|
saveField(pFieldId)
|
|
259
222
|
{
|
|
260
223
|
let tmpEl = document.getElementById(pFieldId);
|
|
261
|
-
if (tmpEl)
|
|
224
|
+
if (!tmpEl) { return; }
|
|
225
|
+
// Checkboxes persist .checked, everything else persists .value.
|
|
226
|
+
// Older code special-cased a small set of checkbox ids (solrSecure,
|
|
227
|
+
// mssqlLegacyPagination, etc.); the schema-driven path no longer
|
|
228
|
+
// needs those — the checkbox handler in bootstrapConnectionSchemas
|
|
229
|
+
// stores 'true' / 'false' which restore picks up below.
|
|
230
|
+
if (tmpEl.type === 'checkbox')
|
|
231
|
+
{
|
|
232
|
+
localStorage.setItem('dataCloner_' + pFieldId, tmpEl.checked ? 'true' : 'false');
|
|
233
|
+
}
|
|
234
|
+
else
|
|
262
235
|
{
|
|
263
236
|
localStorage.setItem('dataCloner_' + pFieldId, tmpEl.value);
|
|
264
237
|
}
|
|
@@ -274,38 +247,40 @@ class DataClonerProvider extends libPictProvider
|
|
|
274
247
|
if (tmpSaved !== null)
|
|
275
248
|
{
|
|
276
249
|
let tmpEl = document.getElementById(tmpId);
|
|
277
|
-
if (tmpEl)
|
|
250
|
+
if (tmpEl)
|
|
251
|
+
{
|
|
252
|
+
if (tmpEl.type === 'checkbox')
|
|
253
|
+
{
|
|
254
|
+
tmpEl.checked = (tmpSaved === 'true');
|
|
255
|
+
}
|
|
256
|
+
else
|
|
257
|
+
{
|
|
258
|
+
tmpEl.value = tmpSaved;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
278
261
|
}
|
|
279
262
|
}
|
|
280
263
|
|
|
281
|
-
// Restore checkbox state
|
|
264
|
+
// Restore checkbox state for non-connection checkboxes that
|
|
265
|
+
// aren't in PersistFields (these all live outside the schema-
|
|
266
|
+
// driven Connection section, so they stay hardcoded).
|
|
282
267
|
let tmpSyncDeleted = localStorage.getItem('dataCloner_syncDeletedRecords');
|
|
283
268
|
if (tmpSyncDeleted !== null)
|
|
284
269
|
{
|
|
285
|
-
document.getElementById('syncDeletedRecords')
|
|
270
|
+
let tmpEl = document.getElementById('syncDeletedRecords');
|
|
271
|
+
if (tmpEl) tmpEl.checked = tmpSyncDeleted === 'true';
|
|
286
272
|
}
|
|
287
|
-
// Restore sync mode
|
|
288
273
|
let tmpSyncMode = localStorage.getItem('dataCloner_syncMode');
|
|
289
274
|
if (tmpSyncMode === 'Ongoing')
|
|
290
275
|
{
|
|
291
|
-
document.getElementById('syncModeOngoing')
|
|
292
|
-
|
|
293
|
-
let tmpSolrSecure = localStorage.getItem('dataCloner_solrSecure');
|
|
294
|
-
if (tmpSolrSecure !== null)
|
|
295
|
-
{
|
|
296
|
-
document.getElementById('solrSecure').checked = tmpSolrSecure === 'true';
|
|
297
|
-
}
|
|
298
|
-
let tmpMssqlLegacyPagination = localStorage.getItem('dataCloner_mssqlLegacyPagination');
|
|
299
|
-
if (tmpMssqlLegacyPagination !== null)
|
|
300
|
-
{
|
|
301
|
-
let tmpEl = document.getElementById('mssqlLegacyPagination');
|
|
302
|
-
if (tmpEl) tmpEl.checked = tmpMssqlLegacyPagination === 'true';
|
|
276
|
+
let tmpEl = document.getElementById('syncModeOngoing');
|
|
277
|
+
if (tmpEl) tmpEl.checked = true;
|
|
303
278
|
}
|
|
304
|
-
// Restore advanced ID pagination checkbox
|
|
305
279
|
let tmpAdvancedIDPagination = localStorage.getItem('dataCloner_syncAdvancedIDPagination');
|
|
306
280
|
if (tmpAdvancedIDPagination !== null)
|
|
307
281
|
{
|
|
308
|
-
document.getElementById('syncAdvancedIDPagination')
|
|
282
|
+
let tmpEl = document.getElementById('syncAdvancedIDPagination');
|
|
283
|
+
if (tmpEl) tmpEl.checked = tmpAdvancedIDPagination === 'true';
|
|
309
284
|
}
|
|
310
285
|
}
|
|
311
286
|
|
|
@@ -347,25 +322,9 @@ class DataClonerProvider extends libPictProvider
|
|
|
347
322
|
});
|
|
348
323
|
});
|
|
349
324
|
|
|
350
|
-
//
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
{
|
|
354
|
-
tmpSolrSecureEl.addEventListener('change', function()
|
|
355
|
-
{
|
|
356
|
-
localStorage.setItem('dataCloner_solrSecure', this.checked);
|
|
357
|
-
});
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
// Persist MSSQL legacy pagination checkbox
|
|
361
|
-
let tmpMssqlLegacyPaginationEl = document.getElementById('mssqlLegacyPagination');
|
|
362
|
-
if (tmpMssqlLegacyPaginationEl)
|
|
363
|
-
{
|
|
364
|
-
tmpMssqlLegacyPaginationEl.addEventListener('change', function()
|
|
365
|
-
{
|
|
366
|
-
localStorage.setItem('dataCloner_mssqlLegacyPagination', this.checked);
|
|
367
|
-
});
|
|
368
|
-
}
|
|
325
|
+
// (Connection-section checkboxes — solrSecure, mssqlLegacyPagination —
|
|
326
|
+
// are handled by bootstrapConnectionSchemas() which hooks change
|
|
327
|
+
// listeners after the schema-driven form renders.)
|
|
369
328
|
|
|
370
329
|
// Persist advanced ID pagination checkbox
|
|
371
330
|
let tmpAdvancedIDPaginationEl = document.getElementById('syncAdvancedIDPagination');
|
|
@@ -397,6 +356,136 @@ class DataClonerProvider extends libPictProvider
|
|
|
397
356
|
}
|
|
398
357
|
}
|
|
399
358
|
|
|
359
|
+
// ================================================================
|
|
360
|
+
// Connection Schemas Bootstrap
|
|
361
|
+
//
|
|
362
|
+
// Fetches the host's aggregated connection-form schemas and re-
|
|
363
|
+
// renders the Connection view so it shows the real provider list +
|
|
364
|
+
// per-provider field blocks. Then restores localStorage values
|
|
365
|
+
// for the new (schema-driven) DOM ids and hooks save listeners.
|
|
366
|
+
// ================================================================
|
|
367
|
+
|
|
368
|
+
bootstrapConnectionSchemas(fCallback)
|
|
369
|
+
{
|
|
370
|
+
let tmpSelf = this;
|
|
371
|
+
let tmpDone = (typeof(fCallback) === 'function') ? fCallback : function () {};
|
|
372
|
+
|
|
373
|
+
this.api('GET', '/clone/connection/schemas')
|
|
374
|
+
.then(function (pData)
|
|
375
|
+
{
|
|
376
|
+
let tmpSchemas = (pData && Array.isArray(pData.Schemas)) ? pData.Schemas : [];
|
|
377
|
+
tmpSelf._applyConnectionSchemas(tmpSchemas);
|
|
378
|
+
return tmpDone(null, tmpSchemas);
|
|
379
|
+
})
|
|
380
|
+
.catch(function (pError)
|
|
381
|
+
{
|
|
382
|
+
if (tmpSelf.fable && tmpSelf.fable.log && tmpSelf.fable.log.error)
|
|
383
|
+
{
|
|
384
|
+
tmpSelf.fable.log.error(`DataCloner: failed to fetch connection schemas: ${pError && pError.message}`);
|
|
385
|
+
}
|
|
386
|
+
// On failure, leave the empty-schema state in place — the
|
|
387
|
+
// shared view's "no schemas detected" notice will surface.
|
|
388
|
+
tmpSelf._applyConnectionSchemas([]);
|
|
389
|
+
return tmpDone(pError);
|
|
390
|
+
});
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
_applyConnectionSchemas(pSchemas)
|
|
394
|
+
{
|
|
395
|
+
let tmpAppData = this.pict.AppData.DataCloner;
|
|
396
|
+
if (!tmpAppData.Connection) { tmpAppData.Connection = { Schemas: [], ActiveProvider: '', PreviewText: '' }; }
|
|
397
|
+
tmpAppData.Connection.Schemas = pSchemas;
|
|
398
|
+
|
|
399
|
+
// Pick an initial ActiveProvider — restore from localStorage
|
|
400
|
+
// if the saved value matches one of the available providers,
|
|
401
|
+
// otherwise default to the first schema (or stay empty).
|
|
402
|
+
let tmpAvailable = pSchemas.map(function (pS) { return pS.Provider; });
|
|
403
|
+
let tmpSavedProvider = localStorage.getItem('dataCloner_activeProvider');
|
|
404
|
+
if (tmpSavedProvider && tmpAvailable.indexOf(tmpSavedProvider) >= 0)
|
|
405
|
+
{
|
|
406
|
+
tmpAppData.Connection.ActiveProvider = tmpSavedProvider;
|
|
407
|
+
}
|
|
408
|
+
else if (pSchemas.length > 0)
|
|
409
|
+
{
|
|
410
|
+
tmpAppData.Connection.ActiveProvider = pSchemas[0].Provider;
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
// Hand the schemas to the shared view, which renders the form
|
|
414
|
+
// into #DataCloner-Connection-FormSlot.
|
|
415
|
+
let tmpForm = this.pict.views['PictSection-ConnectionForm'];
|
|
416
|
+
if (tmpForm)
|
|
417
|
+
{
|
|
418
|
+
let tmpSelf = this;
|
|
419
|
+
tmpForm.options.OnProviderChange = function (pProvider)
|
|
420
|
+
{
|
|
421
|
+
tmpAppData.Connection.ActiveProvider = pProvider;
|
|
422
|
+
localStorage.setItem('dataCloner_activeProvider', pProvider);
|
|
423
|
+
// Re-hook persistence on the new active form's inputs
|
|
424
|
+
// (the shared view re-renders on provider change, so the
|
|
425
|
+
// previous input listeners are gone).
|
|
426
|
+
tmpSelf._persistConnectionFields(pSchemas);
|
|
427
|
+
tmpSelf.updateAllPreviews();
|
|
428
|
+
};
|
|
429
|
+
if (tmpAppData.Connection.ActiveProvider)
|
|
430
|
+
{
|
|
431
|
+
tmpForm._ActiveProvider = tmpAppData.Connection.ActiveProvider;
|
|
432
|
+
}
|
|
433
|
+
tmpForm.setSchemas(pSchemas);
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
// Re-render the DataCloner accordion shell so the preview text
|
|
437
|
+
// reflects the active provider.
|
|
438
|
+
let tmpAccordion = this.pict.views['DataCloner-Connection'];
|
|
439
|
+
if (tmpAccordion) { tmpAccordion.render(); }
|
|
440
|
+
|
|
441
|
+
// Restore values + hook input listeners on the freshly-rendered
|
|
442
|
+
// shared-view inputs.
|
|
443
|
+
this._persistConnectionFields(pSchemas);
|
|
444
|
+
this.updateAllPreviews();
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
_persistConnectionFields(pSchemas)
|
|
448
|
+
{
|
|
449
|
+
let tmpForm = this.pict.views['PictSection-ConnectionForm'];
|
|
450
|
+
if (!tmpForm) { return; }
|
|
451
|
+
|
|
452
|
+
let tmpSelf = this;
|
|
453
|
+
|
|
454
|
+
// Restore + hook every per-provider field. saveField()
|
|
455
|
+
// dispatches on element type internally so checkboxes and
|
|
456
|
+
// text inputs share the same path.
|
|
457
|
+
(pSchemas || []).forEach(function (pSchema)
|
|
458
|
+
{
|
|
459
|
+
(pSchema.Fields || []).forEach(function (pField)
|
|
460
|
+
{
|
|
461
|
+
let tmpId = tmpForm.fieldDOMId(pSchema.Provider, pField.Name);
|
|
462
|
+
let tmpEl = document.getElementById(tmpId);
|
|
463
|
+
if (!tmpEl) { return; }
|
|
464
|
+
|
|
465
|
+
let tmpSaved = localStorage.getItem('dataCloner_' + tmpId);
|
|
466
|
+
if (tmpSaved !== null)
|
|
467
|
+
{
|
|
468
|
+
if (tmpEl.type === 'checkbox')
|
|
469
|
+
{
|
|
470
|
+
tmpEl.checked = (tmpSaved === 'true');
|
|
471
|
+
}
|
|
472
|
+
else
|
|
473
|
+
{
|
|
474
|
+
tmpEl.value = tmpSaved;
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
// Avoid double-binding when the shared view re-renders
|
|
479
|
+
// on provider change. We tag the element so subsequent
|
|
480
|
+
// runs of this method are no-ops.
|
|
481
|
+
if (tmpEl.dataset && tmpEl.dataset.dataclonerHooked === '1') { return; }
|
|
482
|
+
if (tmpEl.dataset) { tmpEl.dataset.dataclonerHooked = '1'; }
|
|
483
|
+
tmpEl.addEventListener('input', function () { tmpSelf.saveField(tmpId); tmpSelf.updateAllPreviews(); });
|
|
484
|
+
tmpEl.addEventListener('change', function () { tmpSelf.saveField(tmpId); tmpSelf.updateAllPreviews(); });
|
|
485
|
+
});
|
|
486
|
+
});
|
|
487
|
+
}
|
|
488
|
+
|
|
400
489
|
// ================================================================
|
|
401
490
|
// Live Status Indicator
|
|
402
491
|
// ================================================================
|