retold-data-service 2.1.1 → 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.
- package/BUILDING-AND-PUBLISHING.md +2 -2
- package/Dockerfile +1 -1
- package/README.md +12 -27
- package/build-all.js +66 -0
- package/diagrams/architecture.excalidraw +2966 -0
- package/diagrams/architecture.mmd +17 -0
- package/diagrams/architecture.svg +2 -0
- package/docs/README.md +12 -12
- package/docs/_brand.json +18 -0
- package/docs/_cover.md +1 -1
- package/docs/_topbar.md +1 -1
- package/docs/_version.json +3 -3
- package/docs/api/reference.md +8 -8
- package/docs/architecture.md +6 -84
- package/docs/diagrams/component-diagram.excalidraw +2807 -0
- package/docs/diagrams/component-diagram.mmd +14 -0
- package/docs/diagrams/component-diagram.svg +2 -0
- package/docs/diagrams/component-stack.excalidraw +1169 -0
- package/docs/diagrams/component-stack.mmd +6 -0
- package/docs/diagrams/component-stack.svg +2 -0
- package/docs/diagrams/hook-execution-order.excalidraw +3230 -0
- package/docs/diagrams/hook-execution-order.mmd +19 -0
- package/docs/diagrams/hook-execution-order.svg +2 -0
- package/docs/diagrams/initialization-flow.excalidraw +1800 -0
- package/docs/diagrams/initialization-flow.mmd +22 -0
- package/docs/diagrams/initialization-flow.svg +2 -0
- package/docs/index.html +6 -7
- package/docs/lifecycle-hooks.md +2 -21
- package/docs/retold-catalog.json +141 -141
- package/docs/retold-keyword-index.json +6818 -1608
- package/package.json +130 -96
- package/source/services/RetoldDataService-Brand.js +13 -0
- package/source/services/comprehension-loader/pict-app/Pict-Application-ComprehensionLoader.js +65 -15
- package/source/services/comprehension-loader/pict-app/providers/Pict-Provider-ComprehensionLoader.js +2 -2
- package/source/services/comprehension-loader/pict-app/views/PictView-ComprehensionLoader-Layout.js +68 -114
- package/source/services/comprehension-loader/pict-app/views/PictView-ComprehensionLoader-Load.js +29 -29
- package/source/services/comprehension-loader/pict-app/views/PictView-ComprehensionLoader-Schema.js +3 -3
- package/source/services/comprehension-loader/pict-app/views/PictView-ComprehensionLoader-Session.js +2 -2
- package/source/services/comprehension-loader/pict-app/views/PictView-ComprehensionLoader-SettingsPanel.js +62 -0
- package/source/services/comprehension-loader/pict-app/views/PictView-ComprehensionLoader-Shell.js +142 -0
- package/source/services/comprehension-loader/pict-app/views/PictView-ComprehensionLoader-Source.js +7 -7
- package/source/services/comprehension-loader/pict-app/views/PictView-ComprehensionLoader-StatusBar.js +125 -0
- package/source/services/comprehension-loader/pict-app/views/PictView-ComprehensionLoader-StatusDetail.js +89 -0
- package/source/services/comprehension-loader/pict-app/views/PictView-ComprehensionLoader-TopBar-Nav.js +42 -0
- package/source/services/comprehension-loader/pict-app/views/PictView-ComprehensionLoader-TopBar-User.js +48 -0
- package/source/services/comprehension-loader/web/comprehension-loader.js +5475 -6243
- package/source/services/comprehension-loader/web/comprehension-loader.js.map +1 -1
- package/source/services/comprehension-loader/web/comprehension-loader.min.js +75 -1
- package/source/services/comprehension-loader/web/comprehension-loader.min.js.map +1 -1
- package/source/services/comprehension-loader/web/favicons/favicon-dark.svg +13 -0
- package/source/services/comprehension-loader/web/favicons/favicon-light.svg +13 -0
- package/source/services/comprehension-loader/web/favicons/favicon.svg +13 -0
- package/source/services/comprehension-loader/web/index.html +3 -0
- package/source/services/comprehension-loader/web/pict.min.js +12 -0
- package/source/services/data-cloner/DataCloner-Command-Headless.js +2 -1
- package/source/services/data-cloner/DataCloner-Command-Sync.js +110 -75
- package/source/services/data-cloner/pict-app/Pict-Application-DataCloner.js +70 -47
- package/source/services/data-cloner/pict-app/providers/Pict-Provider-DataCloner.js +3 -3
- package/source/services/data-cloner/pict-app/views/PictView-DataCloner-Connection.js +1 -1
- package/source/services/data-cloner/pict-app/views/PictView-DataCloner-Deploy.js +5 -5
- package/source/services/data-cloner/pict-app/views/PictView-DataCloner-Export.js +11 -11
- package/source/services/data-cloner/pict-app/views/PictView-DataCloner-Layout.js +89 -135
- package/source/services/data-cloner/pict-app/views/PictView-DataCloner-Schema.js +3 -3
- package/source/services/data-cloner/pict-app/views/PictView-DataCloner-Session.js +2 -2
- package/source/services/data-cloner/pict-app/views/PictView-DataCloner-SettingsPanel.js +61 -0
- package/source/services/data-cloner/pict-app/views/PictView-DataCloner-Shell.js +136 -0
- package/source/services/data-cloner/pict-app/views/PictView-DataCloner-StatusBar.js +117 -0
- package/source/services/data-cloner/pict-app/views/PictView-DataCloner-StatusDetail.js +81 -0
- package/source/services/data-cloner/pict-app/views/PictView-DataCloner-Sync.js +38 -38
- package/source/services/data-cloner/pict-app/views/PictView-DataCloner-TopBar-Nav.js +42 -0
- package/source/services/data-cloner/pict-app/views/PictView-DataCloner-TopBar-User.js +48 -0
- package/source/services/data-cloner/pict-app/views/PictView-DataCloner-ViewData.js +5 -5
- package/source/services/data-cloner/web/data-cloner.js +5855 -8067
- package/source/services/data-cloner/web/data-cloner.js.map +1 -1
- package/source/services/data-cloner/web/data-cloner.min.js +75 -1
- package/source/services/data-cloner/web/data-cloner.min.js.map +1 -1
- package/source/services/data-cloner/web/favicons/favicon-dark.svg +13 -0
- package/source/services/data-cloner/web/favicons/favicon-light.svg +13 -0
- package/source/services/data-cloner/web/favicons/favicon.svg +13 -0
- package/source/services/data-cloner/web/favicons/favicons/favicon-dark.svg +13 -0
- package/source/services/data-cloner/web/favicons/favicons/favicon-light.svg +13 -0
- package/source/services/data-cloner/web/favicons/favicons/favicon.svg +13 -0
- package/source/services/data-cloner/web/index.html +3 -0
- package/source/services/data-cloner/web/pict.min.js +12 -0
- package/test/Bundles_smoke_tests.js +43 -0
- package/test/ComprehensionLoader_smoke_tests.js +95 -0
- package/test/DataCloner-RuntimeOverrides_tests.js +344 -0
- package/test/DataCloner_smoke_tests.js +87 -0
- package/docs/css/docuserve.css +0 -327
|
@@ -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
|
+
};
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const libPictView = require('pict-view');
|
|
4
|
+
|
|
5
|
+
class DataClonerStatusDetailView 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 = DataClonerStatusDetailView;
|
|
15
|
+
|
|
16
|
+
module.exports.default_configuration =
|
|
17
|
+
{
|
|
18
|
+
ViewIdentifier: 'DataCloner-StatusDetail',
|
|
19
|
+
DefaultRenderable: 'DataCloner-StatusDetail',
|
|
20
|
+
DefaultDestinationAddress: '#DataCloner-StatusDetail-Panel',
|
|
21
|
+
AutoRender: false,
|
|
22
|
+
CSS: /*css*/`
|
|
23
|
+
.rds-status-detail-body {
|
|
24
|
+
padding: 12px 20px 16px;
|
|
25
|
+
max-height: 100%;
|
|
26
|
+
overflow-y: auto;
|
|
27
|
+
color: var(--theme-color-text-primary, #333);
|
|
28
|
+
}
|
|
29
|
+
.rds-status-detail-section { margin-bottom: 14px; }
|
|
30
|
+
.rds-status-detail-section:last-child { margin-bottom: 0; }
|
|
31
|
+
.rds-status-detail-section-title {
|
|
32
|
+
font-size: 0.85em; font-weight: 600;
|
|
33
|
+
color: var(--theme-color-text-secondary, #555);
|
|
34
|
+
text-transform: uppercase; letter-spacing: 0.5px;
|
|
35
|
+
margin-bottom: 8px; padding-bottom: 4px;
|
|
36
|
+
border-bottom: 1px solid var(--theme-color-border-light, #eee);
|
|
37
|
+
}
|
|
38
|
+
.running-op-row { display: flex; align-items: center; gap: 12px; padding: 6px 0; font-size: 0.9em; }
|
|
39
|
+
.running-op-name { font-weight: 600; min-width: 180px; }
|
|
40
|
+
.running-op-bar {
|
|
41
|
+
flex: 1; height: 8px;
|
|
42
|
+
background: var(--theme-color-background-tertiary, #e9ecef);
|
|
43
|
+
border-radius: 4px; overflow: hidden; min-width: 120px;
|
|
44
|
+
}
|
|
45
|
+
.running-op-bar-fill {
|
|
46
|
+
height: 100%;
|
|
47
|
+
background: var(--theme-color-brand-primary, #4a90d9);
|
|
48
|
+
transition: width 0.5s ease;
|
|
49
|
+
}
|
|
50
|
+
.running-op-count { font-size: 0.85em; color: var(--theme-color-text-secondary, #666); white-space: nowrap; }
|
|
51
|
+
.running-op-pending { color: var(--theme-color-text-muted, #888); font-size: 0.85em; font-style: italic; padding: 4px 0; }
|
|
52
|
+
.completed-op-row { padding: 8px 0; border-bottom: 1px solid var(--theme-color-background-tertiary, #f0f0f0); }
|
|
53
|
+
.completed-op-row:last-child { border-bottom: none; }
|
|
54
|
+
.completed-op-header { display: flex; align-items: center; gap: 10px; font-size: 0.9em; margin-bottom: 4px; }
|
|
55
|
+
.completed-op-name { font-weight: 600; }
|
|
56
|
+
.completed-op-stats { color: var(--theme-color-text-secondary, #666); font-size: 0.85em; }
|
|
57
|
+
.completed-op-checkmark { color: var(--theme-color-status-success, #28a745); }
|
|
58
|
+
.error-op-row { padding: 6px 0; border-bottom: 1px solid var(--theme-color-background-tertiary, #f0f0f0); font-size: 0.9em; }
|
|
59
|
+
.error-op-row:last-child { border-bottom: none; }
|
|
60
|
+
.error-op-header { display: flex; align-items: center; gap: 8px; }
|
|
61
|
+
.error-op-name { font-weight: 600; color: var(--theme-color-status-error, #dc3545); }
|
|
62
|
+
.error-op-status { font-size: 0.82em; color: var(--theme-color-status-error, #dc3545); }
|
|
63
|
+
.error-op-message { font-size: 0.82em; color: var(--theme-color-text-muted, #888); margin-top: 2px; padding-left: 18px; }
|
|
64
|
+
`,
|
|
65
|
+
Templates: [{
|
|
66
|
+
Hash: 'DataCloner-StatusDetail',
|
|
67
|
+
Template: /*html*/`
|
|
68
|
+
<div class="rds-status-detail-body">
|
|
69
|
+
<div class="rds-status-detail-section">
|
|
70
|
+
<div class="rds-status-detail-section-title">Throughput</div>
|
|
71
|
+
<div id="DataCloner-Throughput-Histogram" style="height:120px"></div>
|
|
72
|
+
</div>
|
|
73
|
+
<div id="DataCloner-StatusDetail-Container"></div>
|
|
74
|
+
</div>`
|
|
75
|
+
}],
|
|
76
|
+
Renderables: [{
|
|
77
|
+
RenderableHash: 'DataCloner-StatusDetail',
|
|
78
|
+
TemplateHash: 'DataCloner-StatusDetail',
|
|
79
|
+
DestinationAddress: '#DataCloner-StatusDetail-Panel'
|
|
80
|
+
}]
|
|
81
|
+
};
|
|
@@ -196,7 +196,7 @@ class DataClonerSyncView extends libPictView
|
|
|
196
196
|
// --- Summary Cards ---
|
|
197
197
|
let tmpCardsContainer = document.getElementById('reportSummaryCards');
|
|
198
198
|
let tmpOutcomeClass = 'outcome-' + pReport.Outcome.toLowerCase();
|
|
199
|
-
let tmpOutcomeColor = { Success: '#28a745', Partial: '#ffc107', Error: '#dc3545', Stopped: '#6c757d' }[pReport.Outcome] || '#666';
|
|
199
|
+
let tmpOutcomeColor = { Success: 'var(--theme-color-status-success, #28a745)', Partial: 'var(--theme-color-status-warning, #ffc107)', Error: 'var(--theme-color-status-error, #dc3545)', Stopped: 'var(--theme-color-text-secondary, #6c757d)' }[pReport.Outcome] || 'var(--theme-color-text-secondary, #666)';
|
|
200
200
|
|
|
201
201
|
let tmpDurationSec = pReport.RunTimestamps.DurationSeconds || 0;
|
|
202
202
|
let tmpDurationStr = tmpDurationSec < 60 ? tmpDurationSec + 's' : Math.floor(tmpDurationSec / 60) + 'm ' + (tmpDurationSec % 60) + 's';
|
|
@@ -224,24 +224,24 @@ class DataClonerSyncView extends libPictView
|
|
|
224
224
|
+ '<div class="report-card">'
|
|
225
225
|
+ ' <div class="card-label">Records</div>'
|
|
226
226
|
+ ' <div class="card-value">' + tmpTotalSynced + '</div>'
|
|
227
|
-
+ ' <div style="font-size:0.75em; color
|
|
227
|
+
+ ' <div style="font-size:0.75em; color:var(--theme-color-text-muted, #888)">of ' + tmpTotalRecords + '</div>'
|
|
228
228
|
+ '</div>';
|
|
229
229
|
|
|
230
230
|
// --- Anomalies ---
|
|
231
231
|
let tmpAnomalyContainer = document.getElementById('reportAnomalies');
|
|
232
232
|
if (pReport.Anomalies.length === 0)
|
|
233
233
|
{
|
|
234
|
-
tmpAnomalyContainer.innerHTML = '<div style="color
|
|
234
|
+
tmpAnomalyContainer.innerHTML = '<div style="color:var(--theme-color-status-success, #28a745); font-weight:600; font-size:0.9em">No anomalies detected.</div>';
|
|
235
235
|
}
|
|
236
236
|
else
|
|
237
237
|
{
|
|
238
|
-
let tmpHtml = '<h4 style="margin:0 0 8px; color
|
|
238
|
+
let tmpHtml = '<h4 style="margin:0 0 8px; color:var(--theme-color-status-error, #dc3545); font-size:0.95em">Anomalies (' + pReport.Anomalies.length + ')</h4>';
|
|
239
239
|
tmpHtml += '<table class="progress-table">';
|
|
240
240
|
tmpHtml += '<tr><th>Table</th><th>Type</th><th>Message</th></tr>';
|
|
241
241
|
for (let i = 0; i < pReport.Anomalies.length; i++)
|
|
242
242
|
{
|
|
243
243
|
let tmpAnomaly = pReport.Anomalies[i];
|
|
244
|
-
let tmpTypeColor = tmpAnomaly.Type === 'Error' ? '#dc3545' : (tmpAnomaly.Type === 'Partial' ? '#ffc107' : '#6c757d');
|
|
244
|
+
let tmpTypeColor = tmpAnomaly.Type === 'Error' ? 'var(--theme-color-status-error, #dc3545)' : (tmpAnomaly.Type === 'Partial' ? 'var(--theme-color-status-warning, #ffc107)' : 'var(--theme-color-text-secondary, #6c757d)');
|
|
245
245
|
tmpHtml += '<tr>';
|
|
246
246
|
tmpHtml += '<td><strong>' + this.pict.providers.DataCloner.escapeHtml(tmpAnomaly.Table) + '</strong></td>';
|
|
247
247
|
tmpHtml += '<td style="color:' + tmpTypeColor + '">' + tmpAnomaly.Type + '</td>';
|
|
@@ -257,7 +257,7 @@ class DataClonerSyncView extends libPictView
|
|
|
257
257
|
let tmpTopCount = Math.min(10, pReport.Tables.length);
|
|
258
258
|
if (tmpTopCount > 0)
|
|
259
259
|
{
|
|
260
|
-
let tmpHtml = '<h4 style="margin:0 0 8px; font-size:0.95em; color
|
|
260
|
+
let tmpHtml = '<h4 style="margin:0 0 8px; font-size:0.95em; color:var(--theme-color-text-secondary, #444)">Top Tables by Duration</h4>';
|
|
261
261
|
tmpHtml += '<table class="progress-table">';
|
|
262
262
|
tmpHtml += '<tr><th>Table</th><th>Duration</th><th>Records</th><th>Status</th></tr>';
|
|
263
263
|
for (let i = 0; i < tmpTopCount; i++)
|
|
@@ -265,7 +265,7 @@ class DataClonerSyncView extends libPictView
|
|
|
265
265
|
let tmpTable = pReport.Tables[i];
|
|
266
266
|
let tmpDur = tmpTable.DurationSeconds < 60 ? tmpTable.DurationSeconds + 's' : Math.floor(tmpTable.DurationSeconds / 60) + 'm ' + (tmpTable.DurationSeconds % 60) + 's';
|
|
267
267
|
let tmpRecs = tmpTable.Total.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
|
|
268
|
-
let tmpStatusColor = { Complete: '#28a745', Error: '#dc3545', Partial: '#ffc107' }[tmpTable.Status] || '#666';
|
|
268
|
+
let tmpStatusColor = { Complete: 'var(--theme-color-status-success, #28a745)', Error: 'var(--theme-color-status-error, #dc3545)', Partial: 'var(--theme-color-status-warning, #ffc107)' }[tmpTable.Status] || 'var(--theme-color-text-secondary, #666)';
|
|
269
269
|
tmpHtml += '<tr>';
|
|
270
270
|
tmpHtml += '<td><strong>' + this.pict.providers.DataCloner.escapeHtml(tmpTable.Name) + '</strong></td>';
|
|
271
271
|
tmpHtml += '<td>' + tmpDur + '</td>';
|
|
@@ -369,11 +369,11 @@ class DataClonerSyncView extends libPictView
|
|
|
369
369
|
}
|
|
370
370
|
|
|
371
371
|
// Color the progress bar based on status
|
|
372
|
-
let tmpBarColor = '#28a745'; // green
|
|
373
|
-
if (pTable.Status === 'Error') tmpBarColor = '#dc3545';
|
|
374
|
-
else if (pTable.Status === 'Partial') tmpBarColor = '#ffc107';
|
|
375
|
-
else if (pTable.Status === 'Syncing') tmpBarColor = '#4a90d9';
|
|
376
|
-
else if (pTable.Status === 'Pending') tmpBarColor = '#adb5bd';
|
|
372
|
+
let tmpBarColor = 'var(--theme-color-status-success, #28a745)'; // green
|
|
373
|
+
if (pTable.Status === 'Error') tmpBarColor = 'var(--theme-color-status-error, #dc3545)';
|
|
374
|
+
else if (pTable.Status === 'Partial') tmpBarColor = 'var(--theme-color-status-warning, #ffc107)';
|
|
375
|
+
else if (pTable.Status === 'Syncing') tmpBarColor = 'var(--theme-color-brand-primary, #4a90d9)';
|
|
376
|
+
else if (pTable.Status === 'Pending') tmpBarColor = 'var(--theme-color-text-muted, #adb5bd)';
|
|
377
377
|
|
|
378
378
|
// Status badge
|
|
379
379
|
let tmpStatusBadge = pTable.Status;
|
|
@@ -481,25 +481,25 @@ module.exports.default_configuration =
|
|
|
481
481
|
DefaultDestinationAddress: '#DataCloner-Section-Sync',
|
|
482
482
|
CSS: /*css*/`
|
|
483
483
|
.progress-table { width: 100%; border-collapse: collapse; margin-top: 4px; margin-bottom: 4px; }
|
|
484
|
-
.progress-table th, .progress-table td { text-align: left; padding: 6px 12px; border-bottom: 1px solid #eee; font-size: 0.9em; }
|
|
485
|
-
.progress-table th { background: #f8f9fa; font-weight: 600; }
|
|
486
|
-
.progress-table-muted td { color: #888; padding: 3px 12px; font-size: 0.85em; border-bottom: 1px solid #f4f5f6; }
|
|
487
|
-
.progress-bar-container { width: 120px; height: 16px; background: #e9ecef; border-radius: 8px; overflow: hidden; display: inline-block; vertical-align: middle; }
|
|
488
|
-
.progress-bar-fill { height: 100%; background: #28a745; transition: width 0.3s; }
|
|
489
|
-
.sync-section-header { font-size: 0.8em; font-weight: 700; text-transform: uppercase; letter-spacing: 0.5px; color: #4a90d9; padding: 10px 0 2px 0; margin-top: 6px; border-top: 1px solid #e0e0e0; }
|
|
484
|
+
.progress-table th, .progress-table td { text-align: left; padding: 6px 12px; border-bottom: 1px solid var(--theme-color-border-light, #eee); font-size: 0.9em; }
|
|
485
|
+
.progress-table th { background: var(--theme-color-background-secondary, #f8f9fa); font-weight: 600; }
|
|
486
|
+
.progress-table-muted td { color: var(--theme-color-text-muted, #888); padding: 3px 12px; font-size: 0.85em; border-bottom: 1px solid var(--theme-color-background-secondary, #f4f5f6); }
|
|
487
|
+
.progress-bar-container { width: 120px; height: 16px; background: var(--theme-color-background-tertiary, #e9ecef); border-radius: 8px; overflow: hidden; display: inline-block; vertical-align: middle; }
|
|
488
|
+
.progress-bar-fill { height: 100%; background: var(--theme-color-status-success, #28a745); transition: width 0.3s; }
|
|
489
|
+
.sync-section-header { font-size: 0.8em; font-weight: 700; text-transform: uppercase; letter-spacing: 0.5px; color: var(--theme-color-brand-primary, #4a90d9); padding: 10px 0 2px 0; margin-top: 6px; border-top: 1px solid var(--theme-color-border-default, #e0e0e0); }
|
|
490
490
|
.sync-section-header:first-child { border-top: none; margin-top: 10px; }
|
|
491
|
-
.sync-section-header-error { color: #dc3545; }
|
|
492
|
-
.sync-section-header-ok { color: #28a745; }
|
|
493
|
-
.sync-section-count { font-weight: 400; color: #999; font-size: 0.95em; }
|
|
494
|
-
.sync-section-overflow { font-size: 0.8em; color: #aaa; padding: 2px 12px 6px; }
|
|
495
|
-
.sync-pending-count { text-align: right; color: #aaa; font-size: 0.85em; }
|
|
496
|
-
.report-card { background: #f8f9fa; border-radius: 8px; padding: 12px 16px; min-width: 140px; text-align: center; border: 1px solid #e9ecef; }
|
|
497
|
-
.report-card .card-label { font-size: 0.8em; color: #666; text-transform: uppercase; letter-spacing: 0.5px; margin-bottom: 4px; }
|
|
491
|
+
.sync-section-header-error { color: var(--theme-color-status-error, #dc3545); }
|
|
492
|
+
.sync-section-header-ok { color: var(--theme-color-status-success, #28a745); }
|
|
493
|
+
.sync-section-count { font-weight: 400; color: var(--theme-color-text-muted, #999); font-size: 0.95em; }
|
|
494
|
+
.sync-section-overflow { font-size: 0.8em; color: var(--theme-color-text-muted, #aaa); padding: 2px 12px 6px; }
|
|
495
|
+
.sync-pending-count { text-align: right; color: var(--theme-color-text-muted, #aaa); font-size: 0.85em; }
|
|
496
|
+
.report-card { background: var(--theme-color-background-secondary, #f8f9fa); border-radius: 8px; padding: 12px 16px; min-width: 140px; text-align: center; border: 1px solid var(--theme-color-background-tertiary, #e9ecef); }
|
|
497
|
+
.report-card .card-label { font-size: 0.8em; color: var(--theme-color-text-secondary, #666); text-transform: uppercase; letter-spacing: 0.5px; margin-bottom: 4px; }
|
|
498
498
|
.report-card .card-value { font-size: 1.4em; font-weight: 700; }
|
|
499
|
-
.report-card.outcome-success { border-left: 4px solid #28a745; }
|
|
500
|
-
.report-card.outcome-partial { border-left: 4px solid #ffc107; }
|
|
501
|
-
.report-card.outcome-error { border-left: 4px solid #dc3545; }
|
|
502
|
-
.report-card.outcome-stopped { border-left: 4px solid #6c757d; }
|
|
499
|
+
.report-card.outcome-success { border-left: 4px solid var(--theme-color-status-success, #28a745); }
|
|
500
|
+
.report-card.outcome-partial { border-left: 4px solid var(--theme-color-status-warning, #ffc107); }
|
|
501
|
+
.report-card.outcome-error { border-left: 4px solid var(--theme-color-status-error, #dc3545); }
|
|
502
|
+
.report-card.outcome-stopped { border-left: 4px solid var(--theme-color-text-secondary, #6c757d); }
|
|
503
503
|
`,
|
|
504
504
|
Templates:
|
|
505
505
|
[
|
|
@@ -534,30 +534,30 @@ module.exports.default_configuration =
|
|
|
534
534
|
<button class="danger" style="margin:0" onclick="pict.views['DataCloner-Sync'].stopSync()">Stop Sync</button>
|
|
535
535
|
</div>
|
|
536
536
|
</div>
|
|
537
|
-
<div style="font-size:0.8em; color
|
|
537
|
+
<div style="font-size:0.8em; color:var(--theme-color-text-muted, #888); margin-bottom:10px; padding-left:158px">Cross-DB tolerance for date comparison (default: 1000ms)</div>
|
|
538
538
|
|
|
539
539
|
<div style="margin-bottom:10px">
|
|
540
540
|
<label style="margin-bottom:6px">Sync Mode</label>
|
|
541
541
|
<div style="display:flex; gap:12px 20px; align-items:center; flex-wrap:wrap">
|
|
542
542
|
<label style="font-weight:normal; margin:0; cursor:pointer">
|
|
543
543
|
<input type="radio" name="syncMode" id="syncModeInitial" value="Initial" checked onchange="pict.views['DataCloner-Sync'].onSyncModeChanged()"> Initial
|
|
544
|
-
<span style="color
|
|
544
|
+
<span style="color:var(--theme-color-text-muted, #888); font-size:0.85em">(full clone)</span>
|
|
545
545
|
</label>
|
|
546
546
|
<label style="font-weight:normal; margin:0; cursor:pointer">
|
|
547
547
|
<input type="radio" name="syncMode" id="syncModeOngoing" value="Ongoing" onchange="pict.views['DataCloner-Sync'].onSyncModeChanged()"> Ongoing
|
|
548
|
-
<span style="color
|
|
548
|
+
<span style="color:var(--theme-color-text-muted, #888); font-size:0.85em">(delta sync)</span>
|
|
549
549
|
</label>
|
|
550
550
|
<label style="font-weight:normal; margin:0; cursor:pointer">
|
|
551
551
|
<input type="radio" name="syncMode" id="syncModeOngoingEventualConsistency" value="OngoingEventualConsistency" onchange="pict.views['DataCloner-Sync'].onSyncModeChanged()"> Eventual
|
|
552
|
-
<span style="color
|
|
552
|
+
<span style="color:var(--theme-color-text-muted, #888); font-size:0.85em">(time-budgeted back-sync)</span>
|
|
553
553
|
</label>
|
|
554
554
|
<label style="font-weight:normal; margin:0; cursor:pointer">
|
|
555
555
|
<input type="radio" name="syncMode" id="syncModeTrueUp" value="TrueUp" onchange="pict.views['DataCloner-Sync'].onSyncModeChanged()"> True-Up
|
|
556
|
-
<span style="color
|
|
556
|
+
<span style="color:var(--theme-color-text-muted, #888); font-size:0.85em">(linear walk, one-time)</span>
|
|
557
557
|
</label>
|
|
558
558
|
<label style="font-weight:normal; margin:0; cursor:pointer">
|
|
559
559
|
<input type="radio" name="syncMode" id="syncModeComparisonOnly" value="ComparisonOnly" onchange="pict.views['DataCloner-Sync'].onSyncModeChanged()"> Compare
|
|
560
|
-
<span style="color
|
|
560
|
+
<span style="color:var(--theme-color-text-muted, #888); font-size:0.85em">(diff report, no sync)</span>
|
|
561
561
|
</label>
|
|
562
562
|
</div>
|
|
563
563
|
</div>
|
|
@@ -569,7 +569,7 @@ module.exports.default_configuration =
|
|
|
569
569
|
<input type="number" id="backSyncTimeLimit" value="30000" min="1000" max="600000" style="margin-bottom:0">
|
|
570
570
|
</div>
|
|
571
571
|
</div>
|
|
572
|
-
<div style="font-size:0.8em; color
|
|
572
|
+
<div style="font-size:0.8em; color:var(--theme-color-text-muted, #888); padding-left:4px">Milliseconds devoted to backwards bisection per entity before pulling new records (default: 30000)</div>
|
|
573
573
|
</div>
|
|
574
574
|
|
|
575
575
|
<div id="syncModeOptions-TrueUp" style="display:none; margin-bottom:10px">
|
|
@@ -579,7 +579,7 @@ module.exports.default_configuration =
|
|
|
579
579
|
<input type="number" id="trueUpPageSize" value="500" min="10" max="10000" style="margin-bottom:0">
|
|
580
580
|
</div>
|
|
581
581
|
</div>
|
|
582
|
-
<div style="font-size:0.8em; color
|
|
582
|
+
<div style="font-size:0.8em; color:var(--theme-color-text-muted, #888); padding-left:4px">Records per page for the linear keyset walk (default: 500)</div>
|
|
583
583
|
</div>
|
|
584
584
|
|
|
585
585
|
<div class="checkbox-row">
|
|
@@ -609,7 +609,7 @@ module.exports.default_configuration =
|
|
|
609
609
|
<div id="syncProgress"></div>
|
|
610
610
|
|
|
611
611
|
<!-- Sync Report (appears after sync completes) -->
|
|
612
|
-
<div id="syncReportSection" style="display:none; margin-top:16px; padding-top:16px; border-top:2px solid #ddd">
|
|
612
|
+
<div id="syncReportSection" style="display:none; margin-top:16px; padding-top:16px; border-top:2px solid var(--theme-color-border-default, #ddd)">
|
|
613
613
|
<h3 style="margin:0 0 12px; font-size:1.1em">Sync Report</h3>
|
|
614
614
|
|
|
615
615
|
<!-- Summary cards -->
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const libPictView = require('pict-view');
|
|
4
|
+
|
|
5
|
+
class DataClonerTopBarNavView 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 = DataClonerTopBarNavView;
|
|
15
|
+
|
|
16
|
+
module.exports.default_configuration =
|
|
17
|
+
{
|
|
18
|
+
ViewIdentifier: 'DataCloner-TopBar-Nav',
|
|
19
|
+
DefaultRenderable: 'DataCloner-TopBar-Nav',
|
|
20
|
+
DefaultDestinationAddress: '#Theme-TopBar-Nav',
|
|
21
|
+
AutoRender: false,
|
|
22
|
+
CSS: /*css*/`
|
|
23
|
+
.rds-nav {
|
|
24
|
+
display: flex; align-items: center; height: 100%;
|
|
25
|
+
padding: 0 12px; gap: 8px;
|
|
26
|
+
color: var(--theme-color-text-on-brand,
|
|
27
|
+
var(--theme-color-text-primary, #1a1a1a));
|
|
28
|
+
font-weight: 500;
|
|
29
|
+
}
|
|
30
|
+
.rds-nav-sep { opacity: 0.5; font-weight: 400; margin: 0 2px; }
|
|
31
|
+
.rds-nav-app { font-weight: 600; opacity: 0.95; }
|
|
32
|
+
`,
|
|
33
|
+
Templates: [{
|
|
34
|
+
Hash: 'DataCloner-TopBar-Nav',
|
|
35
|
+
Template: /*html*/`<div class="rds-nav"><span class="rds-nav-sep">·</span><span class="rds-nav-app">Data Cloner</span></div>`
|
|
36
|
+
}],
|
|
37
|
+
Renderables: [{
|
|
38
|
+
RenderableHash: 'DataCloner-TopBar-Nav',
|
|
39
|
+
TemplateHash: 'DataCloner-TopBar-Nav',
|
|
40
|
+
DestinationAddress: '#Theme-TopBar-Nav'
|
|
41
|
+
}]
|
|
42
|
+
};
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const libPictView = require('pict-view');
|
|
4
|
+
|
|
5
|
+
class DataClonerTopBarUserView 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 = DataClonerTopBarUserView;
|
|
15
|
+
|
|
16
|
+
module.exports.default_configuration =
|
|
17
|
+
{
|
|
18
|
+
ViewIdentifier: 'DataCloner-TopBar-User',
|
|
19
|
+
DefaultRenderable: 'DataCloner-TopBar-User',
|
|
20
|
+
DefaultDestinationAddress: '#Theme-TopBar-User',
|
|
21
|
+
AutoRender: false,
|
|
22
|
+
CSS: /*css*/`
|
|
23
|
+
.rds-user { display: flex; align-items: center; height: 100%; gap: 8px; padding: 0 12px; }
|
|
24
|
+
.rds-user-btn {
|
|
25
|
+
padding: 4px 8px;
|
|
26
|
+
border: 1px solid var(--theme-color-border-default, #5E5549);
|
|
27
|
+
background: transparent;
|
|
28
|
+
color: var(--theme-color-text-on-brand,
|
|
29
|
+
var(--theme-color-text-secondary, #1a1a1a));
|
|
30
|
+
border-radius: 4px;
|
|
31
|
+
cursor: pointer;
|
|
32
|
+
display: inline-flex; align-items: center; justify-content: center;
|
|
33
|
+
font-size: 1em; line-height: 1;
|
|
34
|
+
}
|
|
35
|
+
.rds-user-btn:hover {
|
|
36
|
+
background: var(--theme-color-background-hover, rgba(255,255,255,0.08));
|
|
37
|
+
}
|
|
38
|
+
`,
|
|
39
|
+
Templates: [{
|
|
40
|
+
Hash: 'DataCloner-TopBar-User',
|
|
41
|
+
Template: /*html*/`<div class="rds-user"><button class="rds-user-btn" onclick="_Pict.views['DataCloner-Shell'].toggleSettingsPanel()" title="Settings" aria-label="Settings">{~I:Settings~}</button></div>`
|
|
42
|
+
}],
|
|
43
|
+
Renderables: [{
|
|
44
|
+
RenderableHash: 'DataCloner-TopBar-User',
|
|
45
|
+
TemplateHash: 'DataCloner-TopBar-User',
|
|
46
|
+
DestinationAddress: '#Theme-TopBar-User'
|
|
47
|
+
}]
|
|
48
|
+
};
|
|
@@ -81,7 +81,7 @@ class DataClonerViewDataView extends libPictView
|
|
|
81
81
|
|
|
82
82
|
if (!pRows || pRows.length === 0)
|
|
83
83
|
{
|
|
84
|
-
tmpContainer.innerHTML = '<p style="color
|
|
84
|
+
tmpContainer.innerHTML = '<p style="color:var(--theme-color-text-secondary, #666); font-size:0.9em; padding:8px">No rows.</p>';
|
|
85
85
|
return;
|
|
86
86
|
}
|
|
87
87
|
|
|
@@ -123,10 +123,10 @@ module.exports.default_configuration =
|
|
|
123
123
|
DefaultDestinationAddress: '#DataCloner-Section-ViewData',
|
|
124
124
|
CSS: /*css*/`
|
|
125
125
|
.data-table { width: 100%; border-collapse: collapse; font-size: 0.8em; font-family: monospace; }
|
|
126
|
-
.data-table th { background: #f8f9fa; font-weight: 600; text-align: left; padding: 4px 8px; border: 1px solid #ddd; white-space: nowrap; position: sticky; top: 0; }
|
|
127
|
-
.data-table td { padding: 4px 8px; border: 1px solid #eee; white-space: nowrap; max-width: 300px; overflow: hidden; text-overflow: ellipsis; }
|
|
128
|
-
.data-table tr:nth-child(even) { background: #fafafa; }
|
|
129
|
-
.data-table tr:hover { background: #f0f7ff; }
|
|
126
|
+
.data-table th { background: var(--theme-color-background-secondary, #f8f9fa); font-weight: 600; text-align: left; padding: 4px 8px; border: 1px solid var(--theme-color-border-default, #ddd); white-space: nowrap; position: sticky; top: 0; }
|
|
127
|
+
.data-table td { padding: 4px 8px; border: 1px solid var(--theme-color-border-light, #eee); white-space: nowrap; max-width: 300px; overflow: hidden; text-overflow: ellipsis; }
|
|
128
|
+
.data-table tr:nth-child(even) { background: var(--theme-color-background-secondary, #fafafa); }
|
|
129
|
+
.data-table tr:hover { background: var(--theme-color-background-hover, #f0f7ff); }
|
|
130
130
|
`,
|
|
131
131
|
Templates:
|
|
132
132
|
[
|