retold-data-service 2.1.2 → 2.1.5

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 (80) hide show
  1. package/BUILDING-AND-PUBLISHING.md +2 -2
  2. package/Dockerfile +1 -1
  3. package/README.md +12 -27
  4. package/build-all.js +66 -0
  5. package/diagrams/architecture.excalidraw +2966 -0
  6. package/diagrams/architecture.mmd +17 -0
  7. package/diagrams/architecture.svg +2 -0
  8. package/docs/README.md +12 -12
  9. package/docs/_brand.json +18 -0
  10. package/docs/_cover.md +1 -1
  11. package/docs/_topbar.md +1 -1
  12. package/docs/_version.json +3 -3
  13. package/docs/api/reference.md +8 -8
  14. package/docs/architecture.md +6 -84
  15. package/docs/diagrams/component-diagram.excalidraw +2807 -0
  16. package/docs/diagrams/component-diagram.mmd +14 -0
  17. package/docs/diagrams/component-diagram.svg +2 -0
  18. package/docs/diagrams/component-stack.excalidraw +1169 -0
  19. package/docs/diagrams/component-stack.mmd +6 -0
  20. package/docs/diagrams/component-stack.svg +2 -0
  21. package/docs/diagrams/hook-execution-order.excalidraw +3230 -0
  22. package/docs/diagrams/hook-execution-order.mmd +19 -0
  23. package/docs/diagrams/hook-execution-order.svg +2 -0
  24. package/docs/diagrams/initialization-flow.excalidraw +1800 -0
  25. package/docs/diagrams/initialization-flow.mmd +22 -0
  26. package/docs/diagrams/initialization-flow.svg +2 -0
  27. package/docs/index.html +6 -7
  28. package/docs/lifecycle-hooks.md +2 -21
  29. package/docs/retold-catalog.json +141 -141
  30. package/docs/retold-keyword-index.json +6818 -1608
  31. package/package.json +130 -96
  32. package/source/services/RetoldDataService-Brand.js +13 -0
  33. package/source/services/comprehension-loader/pict-app/Pict-Application-ComprehensionLoader.js +65 -15
  34. package/source/services/comprehension-loader/pict-app/views/PictView-ComprehensionLoader-Layout.js +28 -74
  35. package/source/services/comprehension-loader/pict-app/views/PictView-ComprehensionLoader-Load.js +17 -17
  36. package/source/services/comprehension-loader/pict-app/views/PictView-ComprehensionLoader-SettingsPanel.js +62 -0
  37. package/source/services/comprehension-loader/pict-app/views/PictView-ComprehensionLoader-Shell.js +142 -0
  38. package/source/services/comprehension-loader/pict-app/views/PictView-ComprehensionLoader-StatusBar.js +125 -0
  39. package/source/services/comprehension-loader/pict-app/views/PictView-ComprehensionLoader-StatusDetail.js +89 -0
  40. package/source/services/comprehension-loader/pict-app/views/PictView-ComprehensionLoader-TopBar-Nav.js +42 -0
  41. package/source/services/comprehension-loader/pict-app/views/PictView-ComprehensionLoader-TopBar-User.js +48 -0
  42. package/source/services/comprehension-loader/web/comprehension-loader.js +5415 -6183
  43. package/source/services/comprehension-loader/web/comprehension-loader.js.map +1 -1
  44. package/source/services/comprehension-loader/web/comprehension-loader.min.js +75 -1
  45. package/source/services/comprehension-loader/web/comprehension-loader.min.js.map +1 -1
  46. package/source/services/comprehension-loader/web/favicons/favicon-dark.svg +13 -0
  47. package/source/services/comprehension-loader/web/favicons/favicon-light.svg +13 -0
  48. package/source/services/comprehension-loader/web/favicons/favicon.svg +13 -0
  49. package/source/services/comprehension-loader/web/index.html +3 -0
  50. package/source/services/comprehension-loader/web/pict.min.js +12 -0
  51. package/source/services/data-cloner/DataCloner-Command-Headless.js +2 -1
  52. package/source/services/data-cloner/DataCloner-Command-Sync.js +110 -75
  53. package/source/services/data-cloner/pict-app/Pict-Application-DataCloner.js +70 -47
  54. package/source/services/data-cloner/pict-app/views/PictView-DataCloner-Export.js +3 -3
  55. package/source/services/data-cloner/pict-app/views/PictView-DataCloner-Layout.js +40 -86
  56. package/source/services/data-cloner/pict-app/views/PictView-DataCloner-SettingsPanel.js +61 -0
  57. package/source/services/data-cloner/pict-app/views/PictView-DataCloner-Shell.js +136 -0
  58. package/source/services/data-cloner/pict-app/views/PictView-DataCloner-StatusBar.js +117 -0
  59. package/source/services/data-cloner/pict-app/views/PictView-DataCloner-StatusDetail.js +81 -0
  60. package/source/services/data-cloner/pict-app/views/PictView-DataCloner-Sync.js +18 -18
  61. package/source/services/data-cloner/pict-app/views/PictView-DataCloner-TopBar-Nav.js +42 -0
  62. package/source/services/data-cloner/pict-app/views/PictView-DataCloner-TopBar-User.js +48 -0
  63. package/source/services/data-cloner/pict-app/views/PictView-DataCloner-ViewData.js +2 -2
  64. package/source/services/data-cloner/web/data-cloner.js +5772 -7986
  65. package/source/services/data-cloner/web/data-cloner.js.map +1 -1
  66. package/source/services/data-cloner/web/data-cloner.min.js +75 -1
  67. package/source/services/data-cloner/web/data-cloner.min.js.map +1 -1
  68. package/source/services/data-cloner/web/favicons/favicon-dark.svg +13 -0
  69. package/source/services/data-cloner/web/favicons/favicon-light.svg +13 -0
  70. package/source/services/data-cloner/web/favicons/favicon.svg +13 -0
  71. package/source/services/data-cloner/web/favicons/favicons/favicon-dark.svg +13 -0
  72. package/source/services/data-cloner/web/favicons/favicons/favicon-light.svg +13 -0
  73. package/source/services/data-cloner/web/favicons/favicons/favicon.svg +13 -0
  74. package/source/services/data-cloner/web/index.html +3 -0
  75. package/source/services/data-cloner/web/pict.min.js +12 -0
  76. package/test/Bundles_smoke_tests.js +43 -0
  77. package/test/ComprehensionLoader_smoke_tests.js +95 -0
  78. package/test/DataCloner-RuntimeOverrides_tests.js +344 -0
  79. package/test/DataCloner_smoke_tests.js +87 -0
  80. package/docs/css/docuserve.css +0 -327
@@ -45,37 +45,6 @@ class DataClonerLayoutView extends libPictView
45
45
  tmpCards[i].classList.remove('open');
46
46
  }
47
47
  }
48
-
49
- toggleStatusDetail()
50
- {
51
- let tmpDetail = document.getElementById('liveStatusDetail');
52
- let tmpMeta = document.getElementById('liveStatusMeta');
53
- let tmpMessage = document.getElementById('liveStatusMessage');
54
- let tmpToggle = document.getElementById('liveStatusToggle');
55
- let tmpBar = document.getElementById('liveStatusBar');
56
- if (!tmpDetail) return;
57
-
58
- let tmpIsExpanded = tmpDetail.style.display !== 'none';
59
-
60
- if (tmpIsExpanded)
61
- {
62
- tmpDetail.style.display = 'none';
63
- tmpMeta.style.display = '';
64
- tmpMessage.style.display = '';
65
- tmpToggle.innerHTML = '▼';
66
- tmpBar.classList.remove('expanded');
67
- this.pict.providers.DataCloner.onStatusDetailCollapsed();
68
- }
69
- else
70
- {
71
- tmpDetail.style.display = '';
72
- tmpMeta.style.display = 'none';
73
- tmpMessage.style.display = 'none';
74
- tmpToggle.innerHTML = '▲';
75
- tmpBar.classList.add('expanded');
76
- this.pict.providers.DataCloner.onStatusDetailExpanded();
77
- }
78
- }
79
48
  }
80
49
 
81
50
  module.exports = DataClonerLayoutView;
@@ -84,7 +53,7 @@ module.exports.default_configuration =
84
53
  {
85
54
  ViewIdentifier: 'DataCloner-Layout',
86
55
  DefaultRenderable: 'DataCloner-Layout',
87
- DefaultDestinationAddress: '#DataCloner-Application-Container',
56
+ DefaultDestinationAddress: '#DataCloner-Workspace',
88
57
  CSS: /*css*/`
89
58
  * { box-sizing: border-box; margin: 0; padding: 0; }
90
59
  body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; background: var(--theme-color-background-secondary, #f5f5f5); color: var(--theme-color-text-primary, #333); padding: 20px; }
@@ -97,7 +66,7 @@ h2 { margin-bottom: 12px; color: var(--theme-color-text-secondary, #444); font-s
97
66
  .accordion-row { display: flex; gap: 0; margin-bottom: 16px; align-items: stretch; }
98
67
  .accordion-number {
99
68
  flex: 0 0 48px; display: flex; align-items: flex-start; justify-content: center;
100
- padding-top: 16px; font-size: 1.6em; font-weight: 700; color: #4a90d9;
69
+ padding-top: 16px; font-size: 1.6em; font-weight: 700; color: var(--theme-color-brand-primary, #4a90d9);
101
70
  user-select: none;
102
71
  }
103
72
  .accordion-card {
@@ -126,11 +95,11 @@ h2 { margin-bottom: 12px; color: var(--theme-color-text-secondary, #444); font-s
126
95
  .accordion-actions { display: flex; align-items: baseline; gap: 8px; flex-shrink: 0; }
127
96
  .accordion-card.open .accordion-actions { display: none; }
128
97
  .accordion-go {
129
- font-size: 0.82em; color: #4a90d9; cursor: pointer; text-decoration: none;
98
+ font-size: 0.82em; color: var(--theme-color-brand-primary, #4a90d9); cursor: pointer; text-decoration: none;
130
99
  font-weight: 500; white-space: nowrap; padding: 2px 6px; border-radius: 3px;
131
100
  transition: background 0.15s;
132
101
  }
133
- .accordion-go:hover { background: #e8f0fe; text-decoration: underline; }
102
+ .accordion-go:hover { background: var(--theme-color-background-hover, #e8f0fe); text-decoration: underline; }
134
103
  .accordion-auto {
135
104
  font-size: 0.82em; color: var(--theme-color-text-muted, #999); white-space: nowrap; cursor: pointer;
136
105
  }
@@ -147,7 +116,7 @@ h2 { margin-bottom: 12px; color: var(--theme-color-text-secondary, #444); font-s
147
116
  }
148
117
  .accordion-phase.visible { display: flex; }
149
118
  .accordion-phase-ok { color: var(--theme-color-status-success, #28a745); }
150
- .accordion-phase-error { color: #dc3545; }
119
+ .accordion-phase-error { color: var(--theme-color-status-error, #dc3545); }
151
120
  .accordion-phase-busy { color: var(--theme-color-status-success, #28a745); }
152
121
  .accordion-phase-busy .phase-spinner {
153
122
  display: inline-block; width: 14px; height: 14px;
@@ -173,18 +142,18 @@ input[type="text"], input[type="password"], input[type="number"] {
173
142
  font-size: 0.95em; margin-bottom: 10px;
174
143
  }
175
144
  input[type="text"]:focus, input[type="password"]:focus, input[type="number"]:focus {
176
- outline: none; border-color: #4a90d9;
145
+ outline: none; border-color: var(--theme-color-brand-primary, #4a90d9);
177
146
  }
178
147
 
179
148
  button {
180
149
  padding: 8px 16px; border: none; border-radius: 4px; cursor: pointer;
181
150
  font-size: 0.9em; font-weight: 600; margin-right: 8px; margin-bottom: 8px;
182
151
  }
183
- button.primary { background: #4a90d9; color: var(--theme-color-background-panel, #fff); }
184
- button.primary:hover { background: #357abd; }
185
- button.secondary { background: #6c757d; color: var(--theme-color-background-panel, #fff); }
152
+ button.primary { background: var(--theme-color-brand-primary, #4a90d9); color: var(--theme-color-background-panel, #fff); }
153
+ button.primary:hover { background: var(--theme-color-brand-primary-hover, #357abd); }
154
+ button.secondary { background: var(--theme-color-text-secondary, #6c757d); color: var(--theme-color-background-panel, #fff); }
186
155
  button.secondary:hover { background: #5a6268; }
187
- button.danger { background: #dc3545; color: var(--theme-color-background-panel, #fff); }
156
+ button.danger { background: var(--theme-color-status-error, #dc3545); color: var(--theme-color-background-panel, #fff); }
188
157
  button.danger:hover { background: #c82333; }
189
158
  button.success { background: var(--theme-color-status-success, #28a745); color: var(--theme-color-background-panel, #fff); }
190
159
  button.success:hover { background: #218838; }
@@ -199,7 +168,7 @@ button:disabled { opacity: 0.5; cursor: not-allowed; }
199
168
  .inline-group { display: flex; gap: 8px; align-items: flex-end; margin-bottom: 10px; }
200
169
  .inline-group > div { flex: 1; }
201
170
 
202
- a { color: #4a90d9; }
171
+ a { color: var(--theme-color-brand-primary, #4a90d9); }
203
172
 
204
173
  select { background: var(--theme-color-background-panel, #fff); width: 100%; padding: 8px 12px; border: 1px solid var(--theme-color-border-default, #ccc); border-radius: 4px; font-size: 0.95em; margin-bottom: 10px; }
205
174
 
@@ -211,28 +180,28 @@ select { background: var(--theme-color-background-panel, #fff); width: 100%; pad
211
180
  .live-status-bar {
212
181
  background: var(--theme-color-background-panel, #fff); border-radius: 8px; margin-bottom: 16px;
213
182
  box-shadow: 0 1px 3px rgba(0,0,0,0.1);
214
- position: sticky; top: 0; z-index: 100; border-left: 4px solid #6c757d;
183
+ position: sticky; top: 0; z-index: 100; border-left: 4px solid var(--theme-color-text-secondary, #6c757d);
215
184
  }
216
- .live-status-bar.phase-idle { border-left-color: #6c757d; }
217
- .live-status-bar.phase-disconnected { border-left-color: #dc3545; }
218
- .live-status-bar.phase-ready { border-left-color: #4a90d9; }
185
+ .live-status-bar.phase-idle { border-left-color: var(--theme-color-text-secondary, #6c757d); }
186
+ .live-status-bar.phase-disconnected { border-left-color: var(--theme-color-status-error, #dc3545); }
187
+ .live-status-bar.phase-ready { border-left-color: var(--theme-color-brand-primary, #4a90d9); }
219
188
  .live-status-bar.phase-syncing { border-left-color: var(--theme-color-status-success, #28a745); }
220
- .live-status-bar.phase-stopping { border-left-color: #ffc107; }
189
+ .live-status-bar.phase-stopping { border-left-color: var(--theme-color-status-warning, #ffc107); }
221
190
  .live-status-bar.phase-complete { border-left-color: var(--theme-color-status-success, #28a745); }
222
191
 
223
192
  .live-status-dot {
224
193
  width: 12px; height: 12px; border-radius: 50%; flex-shrink: 0;
225
- background: #6c757d;
194
+ background: var(--theme-color-text-secondary, #6c757d);
226
195
  }
227
- .live-status-bar.phase-idle .live-status-dot { background: #6c757d; }
228
- .live-status-bar.phase-disconnected .live-status-dot { background: #dc3545; }
229
- .live-status-bar.phase-ready .live-status-dot { background: #4a90d9; }
196
+ .live-status-bar.phase-idle .live-status-dot { background: var(--theme-color-text-secondary, #6c757d); }
197
+ .live-status-bar.phase-disconnected .live-status-dot { background: var(--theme-color-status-error, #dc3545); }
198
+ .live-status-bar.phase-ready .live-status-dot { background: var(--theme-color-brand-primary, #4a90d9); }
230
199
  .live-status-bar.phase-syncing .live-status-dot {
231
200
  background: var(--theme-color-status-success, #28a745);
232
201
  animation: live-pulse 1.5s ease-in-out infinite;
233
202
  }
234
203
  .live-status-bar.phase-stopping .live-status-dot {
235
- background: #ffc107;
204
+ background: var(--theme-color-status-warning, #ffc107);
236
205
  animation: live-pulse 0.8s ease-in-out infinite;
237
206
  }
238
207
  .live-status-bar.phase-complete .live-status-dot { background: var(--theme-color-status-success, #28a745); }
@@ -251,7 +220,7 @@ select { background: var(--theme-color-background-panel, #fff); width: 100%; pad
251
220
  .live-status-meta-item strong { color: var(--theme-color-text-primary, #333); }
252
221
 
253
222
  .live-status-progress-bar {
254
- height: 3px; background: #e9ecef; border-radius: 2px; overflow: hidden;
223
+ height: 3px; background: var(--theme-color-background-tertiary, #e9ecef); border-radius: 2px; overflow: hidden;
255
224
  position: absolute; bottom: 0; left: 0; right: 0;
256
225
  }
257
226
  .live-status-progress-fill {
@@ -263,7 +232,7 @@ select { background: var(--theme-color-background-panel, #fff); width: 100%; pad
263
232
  padding: 14px 20px; user-select: none;
264
233
  }
265
234
  .live-status-bar.expanded .live-status-header {
266
- border-bottom: 1px solid #e9ecef; padding-bottom: 10px;
235
+ border-bottom: 1px solid var(--theme-color-background-tertiary, #e9ecef); padding-bottom: 10px;
267
236
  }
268
237
  .live-status-expand-toggle {
269
238
  flex: 0 0 20px; display: flex; align-items: center; justify-content: center;
@@ -278,7 +247,7 @@ select { background: var(--theme-color-background-panel, #fff); width: 100%; pad
278
247
  /* Status Detail Summary Banner */
279
248
  .status-detail-summary {
280
249
  display: flex; align-items: center; gap: 16px; flex-wrap: wrap;
281
- padding: 8px 0 12px; margin-bottom: 12px; border-bottom: 1px solid #e9ecef;
250
+ padding: 8px 0 12px; margin-bottom: 12px; border-bottom: 1px solid var(--theme-color-background-tertiary, #e9ecef);
282
251
  }
283
252
  .status-detail-summary-message {
284
253
  font-size: 0.92em; color: var(--theme-color-text-primary, #333); font-weight: 600;
@@ -303,10 +272,10 @@ select { background: var(--theme-color-background-panel, #fff); width: 100%; pad
303
272
  }
304
273
  .running-op-name { font-weight: 600; min-width: 180px; }
305
274
  .running-op-bar {
306
- flex: 1; height: 8px; background: #e9ecef; border-radius: 4px; overflow: hidden;
275
+ flex: 1; height: 8px; background: var(--theme-color-background-tertiary, #e9ecef); border-radius: 4px; overflow: hidden;
307
276
  min-width: 120px;
308
277
  }
309
- .running-op-bar-fill { height: 100%; background: #4a90d9; transition: width 0.5s ease; }
278
+ .running-op-bar-fill { height: 100%; background: var(--theme-color-brand-primary, #4a90d9); transition: width 0.5s ease; }
310
279
  .running-op-count { font-size: 0.85em; color: var(--theme-color-text-secondary, #666); white-space: nowrap; }
311
280
  .running-op-pending { color: var(--theme-color-text-muted, #888); font-size: 0.85em; font-style: italic; padding: 4px 0; }
312
281
 
@@ -323,29 +292,29 @@ select { background: var(--theme-color-background-panel, #fff); width: 100%; pad
323
292
  /* Ratio Bar */
324
293
  .ratio-bar-container {
325
294
  display: flex; height: 10px; border-radius: 5px; overflow: hidden;
326
- background: #e9ecef; margin: 4px 0;
295
+ background: var(--theme-color-background-tertiary, #e9ecef); margin: 4px 0;
327
296
  }
328
297
  .ratio-bar-segment { height: 100%; transition: width 0.5s ease; }
329
- .ratio-bar-segment.unchanged { background: #6c757d; }
298
+ .ratio-bar-segment.unchanged { background: var(--theme-color-text-secondary, #6c757d); }
330
299
  .ratio-bar-segment.new-records { background: var(--theme-color-status-success, #28a745); }
331
- .ratio-bar-segment.updated { background: #4a90d9; }
332
- .ratio-bar-segment.deleted { background: #dc3545; }
300
+ .ratio-bar-segment.updated { background: var(--theme-color-brand-primary, #4a90d9); }
301
+ .ratio-bar-segment.deleted { background: var(--theme-color-status-error, #dc3545); }
333
302
  .ratio-bar-legend {
334
303
  display: flex; gap: 12px; font-size: 0.75em; color: var(--theme-color-text-secondary, #666); margin-top: 2px; flex-wrap: wrap;
335
304
  }
336
305
  .ratio-bar-legend-item { display: flex; align-items: center; gap: 4px; }
337
306
  .ratio-bar-legend-dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }
338
- .ratio-bar-legend-dot.unchanged-dot { background: #6c757d; }
307
+ .ratio-bar-legend-dot.unchanged-dot { background: var(--theme-color-text-secondary, #6c757d); }
339
308
  .ratio-bar-legend-dot.new-dot { background: var(--theme-color-status-success, #28a745); }
340
- .ratio-bar-legend-dot.updated-dot { background: #4a90d9; }
341
- .ratio-bar-legend-dot.deleted-dot { background: #dc3545; }
309
+ .ratio-bar-legend-dot.updated-dot { background: var(--theme-color-brand-primary, #4a90d9); }
310
+ .ratio-bar-legend-dot.deleted-dot { background: var(--theme-color-status-error, #dc3545); }
342
311
 
343
312
  /* Error Operations */
344
313
  .error-op-row { padding: 6px 0; border-bottom: 1px solid var(--theme-color-background-tertiary, #f0f0f0); font-size: 0.9em; }
345
314
  .error-op-row:last-child { border-bottom: none; }
346
315
  .error-op-header { display: flex; align-items: center; gap: 8px; }
347
- .error-op-name { font-weight: 600; color: #dc3545; }
348
- .error-op-status { font-size: 0.82em; color: #dc3545; }
316
+ .error-op-name { font-weight: 600; color: var(--theme-color-status-error, #dc3545); }
317
+ .error-op-status { font-size: 0.82em; color: var(--theme-color-status-error, #dc3545); }
349
318
  .error-op-message { font-size: 0.82em; color: var(--theme-color-text-muted, #888); margin-top: 2px; padding-left: 18px; }
350
319
  .error-op-log-entries {
351
320
  font-size: 0.78em; color: var(--theme-color-text-muted, #888); margin-top: 4px; padding-left: 18px;
@@ -359,23 +328,23 @@ select { background: var(--theme-color-background-panel, #fff); width: 100%; pad
359
328
  .precount-table thead th {
360
329
  text-align: left; font-weight: 600; color: var(--theme-color-text-secondary, #555); font-size: 0.85em;
361
330
  text-transform: uppercase; letter-spacing: 0.3px;
362
- padding: 4px 8px 6px; border-bottom: 2px solid #e9ecef;
331
+ padding: 4px 8px 6px; border-bottom: 2px solid var(--theme-color-background-tertiary, #e9ecef);
363
332
  }
364
333
  .precount-table tbody td {
365
334
  padding: 4px 8px; border-bottom: 1px solid var(--theme-color-background-tertiary, #f0f0f0);
366
335
  }
367
- .precount-table tbody tr:last-child td { border-bottom: 1px solid #e9ecef; }
336
+ .precount-table tbody tr:last-child td { border-bottom: 1px solid var(--theme-color-background-tertiary, #e9ecef); }
368
337
  .precount-table tfoot td {
369
338
  padding: 6px 8px 2px; font-size: 0.95em;
370
339
  }
371
- .precount-error td { color: #dc3545; }
340
+ .precount-error td { color: var(--theme-color-status-error, #dc3545); }
372
341
  .precount-pending {
373
342
  color: var(--theme-color-text-muted, #888); font-size: 0.85em; font-style: italic; padding: 8px 0 2px;
374
343
  display: flex; align-items: center; gap: 6px;
375
344
  }
376
345
  .precount-spinner {
377
346
  display: inline-block; width: 12px; height: 12px;
378
- border: 2px solid var(--theme-color-border-default, #ddd); border-top-color: #4a90d9;
347
+ border: 2px solid var(--theme-color-border-default, #ddd); border-top-color: var(--theme-color-brand-primary, #4a90d9);
379
348
  border-radius: 50%; animation: precount-spin 0.8s linear infinite;
380
349
  }
381
350
  @keyframes precount-spin { to { transform: rotate(360deg); } }
@@ -387,21 +356,6 @@ select { background: var(--theme-color-background-panel, #fff); width: 100%; pad
387
356
  Template: /*html*/`
388
357
  <h1>Retold Data Cloner</h1>
389
358
 
390
- <!-- Live Status Bar (Expandable) -->
391
- <div id="liveStatusBar" class="live-status-bar phase-idle" style="position:relative">
392
- <div class="live-status-header" onclick="pict.views['DataCloner-Layout'].toggleStatusDetail()">
393
- <div class="live-status-dot"></div>
394
- <div class="live-status-message" id="liveStatusMessage">Idle</div>
395
- <div class="live-status-meta" id="liveStatusMeta"></div>
396
- <div class="live-status-expand-toggle" id="liveStatusToggle">&#9660;</div>
397
- </div>
398
- <div class="live-status-detail" id="liveStatusDetail" style="display:none">
399
- <div id="DataCloner-Throughput-Histogram"></div>
400
- <div id="DataCloner-StatusDetail-Container"></div>
401
- </div>
402
- <div class="live-status-progress-bar"><div class="live-status-progress-fill" id="liveStatusProgressFill" style="width:0%"></div></div>
403
- </div>
404
-
405
359
  <!-- Expand / Collapse All -->
406
360
  <div class="accordion-controls">
407
361
  <button onclick="pict.views['DataCloner-Layout'].expandAllSections()">Expand All</button>
@@ -424,7 +378,7 @@ select { background: var(--theme-color-background-panel, #fff); width: 100%; pad
424
378
  {
425
379
  RenderableHash: 'DataCloner-Layout',
426
380
  TemplateHash: 'DataCloner-Layout',
427
- DestinationAddress: '#DataCloner-Application-Container'
381
+ DestinationAddress: '#DataCloner-Workspace'
428
382
  }
429
383
  ]
430
384
  };
@@ -0,0 +1,61 @@
1
+ 'use strict';
2
+
3
+ const libPictView = require('pict-view');
4
+
5
+ class DataClonerSettingsPanelView extends libPictView
6
+ {
7
+ onAfterRender(pRenderable, pAddress, pRecord, pContent)
8
+ {
9
+ if (this.pict.CSSMap) { this.pict.CSSMap.injectCSS(); }
10
+
11
+ let tmpTheme = this.pict.providers && this.pict.providers['Theme-Section'];
12
+ if (tmpTheme && typeof tmpTheme.mount === 'function')
13
+ {
14
+ tmpTheme.mount({
15
+ Container: '#DataCloner-Settings-Theme',
16
+ Views: ['Picker', 'ModeToggle', 'ScaleSelect']
17
+ });
18
+ }
19
+ return super.onAfterRender(pRenderable, pAddress, pRecord, pContent);
20
+ }
21
+ }
22
+
23
+ module.exports = DataClonerSettingsPanelView;
24
+
25
+ module.exports.default_configuration =
26
+ {
27
+ ViewIdentifier: 'DataCloner-SettingsPanel',
28
+ DefaultRenderable: 'DataCloner-SettingsPanel',
29
+ DefaultDestinationAddress: '#DataCloner-Settings-Panel',
30
+ AutoRender: false,
31
+ CSS: /*css*/`
32
+ .rds-settings-body {
33
+ padding: 12px;
34
+ display: flex; flex-direction: column; gap: 16px;
35
+ color: var(--theme-color-text-primary, #333333);
36
+ }
37
+ .rds-settings-section { display: flex; flex-direction: column; gap: 6px; }
38
+ .rds-settings-label {
39
+ font-size: 0.85em;
40
+ font-weight: 600;
41
+ text-transform: uppercase;
42
+ letter-spacing: 0.04em;
43
+ color: var(--theme-color-text-secondary, #555555);
44
+ }
45
+ `,
46
+ Templates: [{
47
+ Hash: 'DataCloner-SettingsPanel',
48
+ Template: /*html*/`
49
+ <div class="rds-settings-body">
50
+ <div class="rds-settings-section">
51
+ <div class="rds-settings-label">Appearance</div>
52
+ <div id="DataCloner-Settings-Theme"></div>
53
+ </div>
54
+ </div>`
55
+ }],
56
+ Renderables: [{
57
+ RenderableHash: 'DataCloner-SettingsPanel',
58
+ TemplateHash: 'DataCloner-SettingsPanel',
59
+ DestinationAddress: '#DataCloner-Settings-Panel'
60
+ }]
61
+ };
@@ -0,0 +1,136 @@
1
+ 'use strict';
2
+
3
+ const libPictView = require('pict-view');
4
+
5
+ class DataClonerShellView extends libPictView
6
+ {
7
+ constructor(pFable, pOptions, pServiceHash)
8
+ {
9
+ super(pFable, pOptions, pServiceHash);
10
+ this._shellPanelsBuilt = false;
11
+ }
12
+
13
+ onAfterRender(pRenderable, pAddress, pRecord, pContent)
14
+ {
15
+ if (this.pict.CSSMap) { this.pict.CSSMap.injectCSS(); }
16
+ if (!this._shellPanelsBuilt)
17
+ {
18
+ this._buildShell();
19
+ this._shellPanelsBuilt = true;
20
+ }
21
+ return super.onAfterRender(pRenderable, pAddress, pRecord, pContent);
22
+ }
23
+
24
+ _buildShell()
25
+ {
26
+ let tmpModal = this.pict.views['Pict-Section-Modal'];
27
+ let tmpMount = document.getElementById('DataCloner-Shell-Mount');
28
+ if (!tmpModal || typeof tmpModal.shell !== 'function' || !tmpMount)
29
+ {
30
+ this.log.warn('DataCloner-Shell: Pict-Section-Modal or mount not available; shell not built.');
31
+ return;
32
+ }
33
+
34
+ this._shell = tmpModal.shell(tmpMount, { PersistenceKey: 'data-cloner-shell' });
35
+
36
+ this._shell.addPanel({
37
+ Hash: 'topbar', Side: 'top', Mode: 'fixed', Size: 56,
38
+ ContentDestinationId: 'Theme-TopBar', ContentView: 'Theme-TopBar'
39
+ });
40
+
41
+ this._shell.addPanel({
42
+ Hash: 'bottombar', Side: 'bottom', Mode: 'fixed', Size: 36,
43
+ ContentDestinationId: 'Theme-BottomBar', ContentView: 'Theme-BottomBar'
44
+ });
45
+
46
+ this._shell.addPanel({
47
+ Hash: 'status-detail', Side: 'bottom', Mode: 'resizable', Position: 'overlay',
48
+ Size: 320, MinSize: 200, MaxSize: 480,
49
+ Hidden: true, Collapsed: true, Title: 'Status Detail',
50
+ ContentDestinationId: 'DataCloner-StatusDetail-Panel',
51
+ ContentView: 'DataCloner-StatusDetail'
52
+ });
53
+
54
+ this._shell.addPanel({
55
+ Hash: 'settings', Side: 'right', Mode: 'resizable', Position: 'overlay',
56
+ Size: 360, MinSize: 280, MaxSize: 540,
57
+ Hidden: true, Collapsed: true, Title: 'Settings',
58
+ ContentDestinationId: 'DataCloner-Settings-Panel',
59
+ ContentView: 'DataCloner-SettingsPanel'
60
+ });
61
+
62
+ this._shell.center({ ContentDestinationId: 'DataCloner-Workspace' });
63
+ }
64
+
65
+ getSettingsPanel() { return this._shell ? this._shell.getPanel('settings') : null; }
66
+ getStatusDetailPanel() { return this._shell ? this._shell.getPanel('status-detail') : null; }
67
+
68
+ toggleSettingsPanel()
69
+ {
70
+ let tmpPanel = this.getSettingsPanel();
71
+ if (tmpPanel) { tmpPanel.toggle(); }
72
+ }
73
+
74
+ toggleStatusDetail()
75
+ {
76
+ let tmpPanel = this.getStatusDetailPanel();
77
+ if (!tmpPanel) { return; }
78
+ tmpPanel.toggle();
79
+
80
+ let tmpProvider = this.pict.providers.DataCloner;
81
+ let tmpOpen = !tmpPanel.Collapsed;
82
+ if (tmpProvider && tmpOpen && typeof tmpProvider.onStatusDetailExpanded === 'function')
83
+ {
84
+ tmpProvider.onStatusDetailExpanded();
85
+ }
86
+ else if (tmpProvider && !tmpOpen && typeof tmpProvider.onStatusDetailCollapsed === 'function')
87
+ {
88
+ tmpProvider.onStatusDetailCollapsed();
89
+ }
90
+ }
91
+
92
+ renderTopBar()
93
+ {
94
+ let tmpNav = this.pict.views['DataCloner-TopBar-Nav'];
95
+ let tmpUser = this.pict.views['DataCloner-TopBar-User'];
96
+ if (tmpNav) { tmpNav.render(); }
97
+ if (tmpUser) { tmpUser.render(); }
98
+ }
99
+ }
100
+
101
+ module.exports = DataClonerShellView;
102
+
103
+ module.exports.default_configuration =
104
+ {
105
+ ViewIdentifier: 'DataCloner-Shell',
106
+ DefaultRenderable: 'DataCloner-Shell',
107
+ DefaultDestinationAddress: '#DataCloner-Application-Container',
108
+ AutoRender: false,
109
+ CSS: /*css*/`
110
+ html, body { height: 100%; margin: 0; padding: 0; }
111
+ body {
112
+ background: var(--theme-color-background-primary, #f5f5f5);
113
+ color: var(--theme-color-text-primary, #333333);
114
+ font-family: var(--theme-typography-family-sans,
115
+ -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif);
116
+ }
117
+ #DataCloner-Application-Container { height: 100%; min-height: 0; overflow: hidden; }
118
+ .pict-modal-shell-host { height: 100%; }
119
+ .pict-modal-shell { background: var(--theme-color-background-primary, #f5f5f5); }
120
+ .pict-modal-shell-panel { background: var(--theme-color-background-panel, #ffffff); }
121
+ .pict-modal-shell-center {
122
+ background: var(--theme-color-background-primary, #f5f5f5);
123
+ overflow: auto;
124
+ padding: 20px;
125
+ }
126
+ `,
127
+ Templates: [{
128
+ Hash: 'DataCloner-Shell',
129
+ Template: /*html*/`<div id="DataCloner-Shell-Mount" style="height:100%"></div>`
130
+ }],
131
+ Renderables: [{
132
+ RenderableHash: 'DataCloner-Shell',
133
+ TemplateHash: 'DataCloner-Shell',
134
+ DestinationAddress: '#DataCloner-Application-Container'
135
+ }]
136
+ };
@@ -0,0 +1,117 @@
1
+ 'use strict';
2
+
3
+ const libPictView = require('pict-view');
4
+
5
+ class DataClonerStatusBarView extends libPictView
6
+ {
7
+ onAfterRender(pRenderable, pAddress, pRecord, pContent)
8
+ {
9
+ if (this.pict.CSSMap) { this.pict.CSSMap.injectCSS(); }
10
+ return super.onAfterRender(pRenderable, pAddress, pRecord, pContent);
11
+ }
12
+ }
13
+
14
+ module.exports = DataClonerStatusBarView;
15
+
16
+ module.exports.default_configuration =
17
+ {
18
+ ViewIdentifier: 'DataCloner-StatusBar',
19
+ DefaultRenderable: 'DataCloner-StatusBar',
20
+ DefaultDestinationAddress: '#Theme-BottomBar-Status',
21
+ AutoRender: false,
22
+ CSS: /*css*/`
23
+ .rds-status-bar {
24
+ display: flex; align-items: center; gap: 12px;
25
+ height: 100%; padding: 0 12px;
26
+ color: var(--theme-color-text-primary, #333333);
27
+ font-size: 0.88em;
28
+ border-top: 1px solid var(--theme-color-border-light, #e9e9e9);
29
+ border-left: 3px solid var(--theme-color-text-secondary, #6c757d);
30
+ position: relative;
31
+ }
32
+ .rds-status-bar.phase-idle { border-left-color: var(--theme-color-text-secondary, #6c757d); }
33
+ .rds-status-bar.phase-disconnected { border-left-color: var(--theme-color-status-error, #dc3545); }
34
+ .rds-status-bar.phase-ready { border-left-color: var(--theme-color-brand-primary, #4a90d9); }
35
+ .rds-status-bar.phase-loading { border-left-color: var(--theme-color-status-success, #28a745); }
36
+ .rds-status-bar.phase-stopping { border-left-color: var(--theme-color-status-warning, #ffc107); }
37
+ .rds-status-bar.phase-complete { border-left-color: var(--theme-color-status-success, #28a745); }
38
+
39
+ .rds-status-dot {
40
+ width: 10px; height: 10px; border-radius: 50%;
41
+ flex-shrink: 0;
42
+ background: var(--theme-color-text-secondary, #6c757d);
43
+ }
44
+ .rds-status-bar.phase-idle .rds-status-dot { background: var(--theme-color-text-secondary, #6c757d); }
45
+ .rds-status-bar.phase-disconnected .rds-status-dot { background: var(--theme-color-status-error, #dc3545); }
46
+ .rds-status-bar.phase-ready .rds-status-dot { background: var(--theme-color-brand-primary, #4a90d9); }
47
+ .rds-status-bar.phase-loading .rds-status-dot {
48
+ background: var(--theme-color-status-success, #28a745);
49
+ animation: rds-status-pulse 1.5s ease-in-out infinite;
50
+ }
51
+ .rds-status-bar.phase-stopping .rds-status-dot {
52
+ background: var(--theme-color-status-warning, #ffc107);
53
+ animation: rds-status-pulse 0.8s ease-in-out infinite;
54
+ }
55
+ .rds-status-bar.phase-complete .rds-status-dot { background: var(--theme-color-status-success, #28a745); }
56
+
57
+ @keyframes rds-status-pulse {
58
+ 0%, 100% { opacity: 1; transform: scale(1); }
59
+ 50% { opacity: 0.4; transform: scale(0.8); }
60
+ }
61
+
62
+ .rds-status-message { flex: 1; line-height: 1.2; }
63
+ .rds-status-meta {
64
+ display: flex; gap: 12px; flex-shrink: 0;
65
+ font-size: 0.92em; color: var(--theme-color-text-secondary, #666);
66
+ }
67
+ .rds-status-meta .live-status-meta-item { white-space: nowrap; }
68
+ .rds-status-meta .live-status-meta-item strong { color: var(--theme-color-text-primary, #333); }
69
+
70
+ .rds-status-detail-btn {
71
+ padding: 2px 8px;
72
+ background: transparent;
73
+ border: 1px solid var(--theme-color-border-default, #ccc);
74
+ border-radius: 3px;
75
+ color: var(--theme-color-text-secondary, #666);
76
+ cursor: pointer;
77
+ font-size: 0.92em;
78
+ line-height: 1;
79
+ }
80
+ .rds-status-detail-btn:hover {
81
+ background: var(--theme-color-background-hover, #f0f0f0);
82
+ color: var(--theme-color-text-primary, #333);
83
+ }
84
+
85
+ .rds-status-progress-bar {
86
+ position: absolute; left: 0; right: 0; bottom: 0;
87
+ height: 2px;
88
+ background: var(--theme-color-background-tertiary, #e9ecef);
89
+ overflow: hidden;
90
+ }
91
+ .rds-status-progress-fill {
92
+ height: 100%;
93
+ background: var(--theme-color-status-success, #28a745);
94
+ transition: width 1s ease;
95
+ }
96
+ `,
97
+ Templates: [{
98
+ Hash: 'DataCloner-StatusBar',
99
+ Template: /*html*/`
100
+ <div id="liveStatusBar" class="rds-status-bar phase-idle">
101
+ <div class="rds-status-dot live-status-dot"></div>
102
+ <div id="liveStatusMessage" class="rds-status-message live-status-message">Idle</div>
103
+ <div id="liveStatusMeta" class="rds-status-meta live-status-meta"></div>
104
+ <button class="rds-status-detail-btn"
105
+ onclick="_Pict.views['DataCloner-Shell'].toggleStatusDetail()"
106
+ title="Show detail">Detail</button>
107
+ <div class="rds-status-progress-bar live-status-progress-bar">
108
+ <div id="liveStatusProgressFill" class="rds-status-progress-fill live-status-progress-fill" style="width:0%"></div>
109
+ </div>
110
+ </div>`
111
+ }],
112
+ Renderables: [{
113
+ RenderableHash: 'DataCloner-StatusBar',
114
+ TemplateHash: 'DataCloner-StatusBar',
115
+ DestinationAddress: '#Theme-BottomBar-Status'
116
+ }]
117
+ };