retold-data-service 2.0.16 → 2.0.18
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/.claude/launch.json +2 -2
- package/.quackage.json +19 -0
- package/package.json +13 -6
- package/source/services/data-cloner/DataCloner-Command-Sync.js +83 -50
- package/source/services/data-cloner/DataCloner-Command-WebUI.js +27 -10
- package/source/services/data-cloner/Retold-Data-Service-DataCloner.js +281 -4
- package/source/services/data-cloner/pict-app/Pict-Application-DataCloner-Configuration.json +9 -0
- package/source/services/data-cloner/pict-app/Pict-Application-DataCloner.js +102 -0
- package/source/services/data-cloner/pict-app/Pict-DataCloner-Bundle.js +6 -0
- package/source/services/data-cloner/pict-app/providers/Pict-Provider-DataCloner.js +998 -0
- package/source/services/data-cloner/pict-app/views/PictView-DataCloner-Connection.js +407 -0
- package/source/services/data-cloner/pict-app/views/PictView-DataCloner-Deploy.js +126 -0
- package/source/services/data-cloner/pict-app/views/PictView-DataCloner-Export.js +483 -0
- package/source/services/data-cloner/pict-app/views/PictView-DataCloner-Layout.js +390 -0
- package/source/services/data-cloner/pict-app/views/PictView-DataCloner-Schema.js +241 -0
- package/source/services/data-cloner/pict-app/views/PictView-DataCloner-Session.js +268 -0
- package/source/services/data-cloner/pict-app/views/PictView-DataCloner-Sync.js +575 -0
- package/source/services/data-cloner/pict-app/views/PictView-DataCloner-ViewData.js +176 -0
- package/source/services/data-cloner/web/data-cloner.js +7952 -0
- package/source/services/data-cloner/web/data-cloner.js.map +1 -0
- package/source/services/data-cloner/web/data-cloner.min.js +2 -0
- package/source/services/data-cloner/web/data-cloner.min.js.map +1 -0
- package/source/services/data-cloner/web/index.html +17 -0
- package/test/DataCloner-Integration_tests.js +1205 -0
- package/test/DataCloner-Puppeteer_tests.js +502 -0
- package/test/integration-report.json +311 -0
- package/test/run-integration-tests.js +501 -0
- package/source/services/data-cloner/data-cloner-web.html +0 -2706
|
@@ -0,0 +1,407 @@
|
|
|
1
|
+
const libPictView = require('pict-view');
|
|
2
|
+
|
|
3
|
+
class DataClonerConnectionView extends libPictView
|
|
4
|
+
{
|
|
5
|
+
constructor(pFable, pOptions, pServiceHash)
|
|
6
|
+
{
|
|
7
|
+
super(pFable, pOptions, pServiceHash);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
onProviderChange()
|
|
11
|
+
{
|
|
12
|
+
let tmpProvider = document.getElementById('connProvider').value;
|
|
13
|
+
let tmpProviders = ['SQLite', 'MySQL', 'MSSQL', 'PostgreSQL', 'Solr', 'MongoDB', 'RocksDB', 'Bibliograph'];
|
|
14
|
+
for (let i = 0; i < tmpProviders.length; i++)
|
|
15
|
+
{
|
|
16
|
+
let tmpEl = document.getElementById('config' + tmpProviders[i]);
|
|
17
|
+
if (tmpEl)
|
|
18
|
+
{
|
|
19
|
+
tmpEl.style.display = (tmpProvider === tmpProviders[i]) ? '' : 'none';
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
this.pict.providers.DataCloner.saveField('connProvider');
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
getProviderConfig()
|
|
26
|
+
{
|
|
27
|
+
let tmpProvider = document.getElementById('connProvider').value;
|
|
28
|
+
let tmpConfig = {};
|
|
29
|
+
|
|
30
|
+
if (tmpProvider === 'SQLite')
|
|
31
|
+
{
|
|
32
|
+
tmpConfig.SQLiteFilePath = document.getElementById('sqliteFilePath').value.trim() || 'data/cloned.sqlite';
|
|
33
|
+
}
|
|
34
|
+
else if (tmpProvider === 'MySQL')
|
|
35
|
+
{
|
|
36
|
+
tmpConfig.host = document.getElementById('mysqlServer').value.trim() || '127.0.0.1';
|
|
37
|
+
tmpConfig.port = parseInt(document.getElementById('mysqlPort').value, 10) || 3306;
|
|
38
|
+
tmpConfig.user = document.getElementById('mysqlUser').value.trim() || 'root';
|
|
39
|
+
tmpConfig.password = document.getElementById('mysqlPassword').value;
|
|
40
|
+
tmpConfig.database = document.getElementById('mysqlDatabase').value.trim();
|
|
41
|
+
tmpConfig.connectionLimit = parseInt(document.getElementById('mysqlConnectionLimit').value, 10) || 20;
|
|
42
|
+
}
|
|
43
|
+
else if (tmpProvider === 'MSSQL')
|
|
44
|
+
{
|
|
45
|
+
tmpConfig.server = document.getElementById('mssqlServer').value.trim() || '127.0.0.1';
|
|
46
|
+
tmpConfig.port = parseInt(document.getElementById('mssqlPort').value, 10) || 1433;
|
|
47
|
+
tmpConfig.user = document.getElementById('mssqlUser').value.trim() || 'sa';
|
|
48
|
+
tmpConfig.password = document.getElementById('mssqlPassword').value;
|
|
49
|
+
tmpConfig.database = document.getElementById('mssqlDatabase').value.trim();
|
|
50
|
+
tmpConfig.connectionLimit = parseInt(document.getElementById('mssqlConnectionLimit').value, 10) || 20;
|
|
51
|
+
}
|
|
52
|
+
else if (tmpProvider === 'PostgreSQL')
|
|
53
|
+
{
|
|
54
|
+
tmpConfig.host = document.getElementById('postgresqlHost').value.trim() || '127.0.0.1';
|
|
55
|
+
tmpConfig.port = parseInt(document.getElementById('postgresqlPort').value, 10) || 5432;
|
|
56
|
+
tmpConfig.user = document.getElementById('postgresqlUser').value.trim() || 'postgres';
|
|
57
|
+
tmpConfig.password = document.getElementById('postgresqlPassword').value;
|
|
58
|
+
tmpConfig.database = document.getElementById('postgresqlDatabase').value.trim();
|
|
59
|
+
tmpConfig.max = parseInt(document.getElementById('postgresqlConnectionLimit').value, 10) || 10;
|
|
60
|
+
}
|
|
61
|
+
else if (tmpProvider === 'Solr')
|
|
62
|
+
{
|
|
63
|
+
tmpConfig.host = document.getElementById('solrHost').value.trim() || 'localhost';
|
|
64
|
+
tmpConfig.port = parseInt(document.getElementById('solrPort').value, 10) || 8983;
|
|
65
|
+
tmpConfig.core = document.getElementById('solrCore').value.trim() || 'default';
|
|
66
|
+
tmpConfig.path = document.getElementById('solrPath').value.trim() || '/solr';
|
|
67
|
+
tmpConfig.secure = document.getElementById('solrSecure').checked;
|
|
68
|
+
}
|
|
69
|
+
else if (tmpProvider === 'MongoDB')
|
|
70
|
+
{
|
|
71
|
+
tmpConfig.host = document.getElementById('mongodbHost').value.trim() || '127.0.0.1';
|
|
72
|
+
tmpConfig.port = parseInt(document.getElementById('mongodbPort').value, 10) || 27017;
|
|
73
|
+
tmpConfig.user = document.getElementById('mongodbUser').value.trim();
|
|
74
|
+
tmpConfig.password = document.getElementById('mongodbPassword').value;
|
|
75
|
+
tmpConfig.database = document.getElementById('mongodbDatabase').value.trim() || 'test';
|
|
76
|
+
tmpConfig.maxPoolSize = parseInt(document.getElementById('mongodbConnectionLimit').value, 10) || 10;
|
|
77
|
+
}
|
|
78
|
+
else if (tmpProvider === 'RocksDB')
|
|
79
|
+
{
|
|
80
|
+
tmpConfig.RocksDBFolder = document.getElementById('rocksdbFolder').value.trim() || 'data/rocksdb';
|
|
81
|
+
}
|
|
82
|
+
else if (tmpProvider === 'Bibliograph')
|
|
83
|
+
{
|
|
84
|
+
tmpConfig.StorageFolder = document.getElementById('bibliographFolder').value.trim() || 'data/bibliograph';
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return { Provider: tmpProvider, Config: tmpConfig };
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
connectProvider()
|
|
91
|
+
{
|
|
92
|
+
let tmpConnInfo = this.getProviderConfig();
|
|
93
|
+
|
|
94
|
+
this.pict.providers.DataCloner.setSectionPhase(1, 'busy');
|
|
95
|
+
this.pict.providers.DataCloner.setStatus('connectionStatus', 'Connecting to ' + tmpConnInfo.Provider + '...', 'info');
|
|
96
|
+
|
|
97
|
+
this.pict.providers.DataCloner.api('POST', '/clone/connection/configure', tmpConnInfo)
|
|
98
|
+
.then(
|
|
99
|
+
(pData) =>
|
|
100
|
+
{
|
|
101
|
+
if (pData.Success)
|
|
102
|
+
{
|
|
103
|
+
this.pict.providers.DataCloner.setStatus('connectionStatus', pData.Message, 'ok');
|
|
104
|
+
this.pict.providers.DataCloner.setSectionPhase(1, 'ok');
|
|
105
|
+
}
|
|
106
|
+
else
|
|
107
|
+
{
|
|
108
|
+
this.pict.providers.DataCloner.setStatus('connectionStatus', 'Connection failed: ' + (pData.Error || 'Unknown error'), 'error');
|
|
109
|
+
this.pict.providers.DataCloner.setSectionPhase(1, 'error');
|
|
110
|
+
}
|
|
111
|
+
})
|
|
112
|
+
.catch(
|
|
113
|
+
(pError) =>
|
|
114
|
+
{
|
|
115
|
+
this.pict.providers.DataCloner.setStatus('connectionStatus', 'Request failed: ' + pError.message, 'error');
|
|
116
|
+
this.pict.providers.DataCloner.setSectionPhase(1, 'error');
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
testConnection()
|
|
121
|
+
{
|
|
122
|
+
let tmpConnInfo = this.getProviderConfig();
|
|
123
|
+
|
|
124
|
+
this.pict.providers.DataCloner.setStatus('connectionStatus', 'Testing ' + tmpConnInfo.Provider + ' connection...', 'info');
|
|
125
|
+
|
|
126
|
+
this.pict.providers.DataCloner.api('POST', '/clone/connection/test', tmpConnInfo)
|
|
127
|
+
.then(
|
|
128
|
+
(pData) =>
|
|
129
|
+
{
|
|
130
|
+
if (pData.Success)
|
|
131
|
+
{
|
|
132
|
+
this.pict.providers.DataCloner.setStatus('connectionStatus', pData.Message, 'ok');
|
|
133
|
+
}
|
|
134
|
+
else
|
|
135
|
+
{
|
|
136
|
+
this.pict.providers.DataCloner.setStatus('connectionStatus', 'Test failed: ' + (pData.Error || 'Unknown error'), 'error');
|
|
137
|
+
}
|
|
138
|
+
})
|
|
139
|
+
.catch(
|
|
140
|
+
(pError) =>
|
|
141
|
+
{
|
|
142
|
+
this.pict.providers.DataCloner.setStatus('connectionStatus', 'Request failed: ' + pError.message, 'error');
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
checkConnectionStatus()
|
|
147
|
+
{
|
|
148
|
+
this.pict.providers.DataCloner.api('GET', '/clone/connection/status')
|
|
149
|
+
.then(
|
|
150
|
+
(pData) =>
|
|
151
|
+
{
|
|
152
|
+
if (pData.Connected)
|
|
153
|
+
{
|
|
154
|
+
this.pict.providers.DataCloner.setStatus('connectionStatus', 'Connected: ' + pData.Provider, 'ok');
|
|
155
|
+
this.pict.providers.DataCloner.setSectionPhase(1, 'ok');
|
|
156
|
+
}
|
|
157
|
+
})
|
|
158
|
+
.catch(
|
|
159
|
+
() =>
|
|
160
|
+
{
|
|
161
|
+
/* ignore */
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
module.exports = DataClonerConnectionView;
|
|
167
|
+
|
|
168
|
+
module.exports.default_configuration =
|
|
169
|
+
{
|
|
170
|
+
ViewIdentifier: 'DataCloner-Connection',
|
|
171
|
+
DefaultRenderable: 'DataCloner-Connection',
|
|
172
|
+
DefaultDestinationAddress: '#DataCloner-Section-Connection',
|
|
173
|
+
Templates:
|
|
174
|
+
[
|
|
175
|
+
{
|
|
176
|
+
Hash: 'DataCloner-Connection',
|
|
177
|
+
Template: /*html*/`
|
|
178
|
+
<div class="accordion-row">
|
|
179
|
+
<div class="accordion-number">1</div>
|
|
180
|
+
<div class="accordion-card" id="section1" data-section="1">
|
|
181
|
+
<div class="accordion-header" onclick="pict.views['DataCloner-Layout'].toggleSection('section1')">
|
|
182
|
+
<div class="accordion-title">Database Connection</div>
|
|
183
|
+
<span class="accordion-phase" id="phase1"></span>
|
|
184
|
+
<div class="accordion-preview" id="preview1">SQLite at data/cloned.sqlite</div>
|
|
185
|
+
<div class="accordion-actions">
|
|
186
|
+
<span class="accordion-go" onclick="event.stopPropagation(); pict.views['DataCloner-Connection'].connectProvider()">go</span>
|
|
187
|
+
<label class="accordion-auto" onclick="event.stopPropagation()"><input type="checkbox" id="auto1"> <span class="auto-label">auto</span></label>
|
|
188
|
+
</div>
|
|
189
|
+
<div class="accordion-toggle">▼</div>
|
|
190
|
+
</div>
|
|
191
|
+
<div class="accordion-body">
|
|
192
|
+
<p style="font-size:0.9em; color:#666; margin-bottom:10px">Configure the local database where cloned data will be stored. SQLite is connected by default.</p>
|
|
193
|
+
|
|
194
|
+
<div class="inline-group">
|
|
195
|
+
<div style="flex:0 0 200px">
|
|
196
|
+
<label for="connProvider">Provider</label>
|
|
197
|
+
<select id="connProvider" onchange="pict.views['DataCloner-Connection'].onProviderChange()">
|
|
198
|
+
<option value="SQLite" selected>SQLite</option>
|
|
199
|
+
<option value="MySQL">MySQL</option>
|
|
200
|
+
<option value="MSSQL">MSSQL</option>
|
|
201
|
+
<option value="PostgreSQL">PostgreSQL</option>
|
|
202
|
+
<option value="Solr">Solr</option>
|
|
203
|
+
<option value="MongoDB">MongoDB</option>
|
|
204
|
+
<option value="RocksDB">RocksDB</option>
|
|
205
|
+
<option value="Bibliograph">Bibliograph</option>
|
|
206
|
+
</select>
|
|
207
|
+
</div>
|
|
208
|
+
<div style="flex:1; display:flex; align-items:flex-end; gap:8px">
|
|
209
|
+
<button class="primary" onclick="pict.views['DataCloner-Connection'].connectProvider()">Connect</button>
|
|
210
|
+
<button class="secondary" onclick="pict.views['DataCloner-Connection'].testConnection()">Test Connection</button>
|
|
211
|
+
</div>
|
|
212
|
+
</div>
|
|
213
|
+
|
|
214
|
+
<!-- SQLite Config -->
|
|
215
|
+
<div id="configSQLite">
|
|
216
|
+
<label for="sqliteFilePath">SQLite File Path</label>
|
|
217
|
+
<input type="text" id="sqliteFilePath" placeholder="data/cloned.sqlite" value="data/cloned.sqlite">
|
|
218
|
+
</div>
|
|
219
|
+
|
|
220
|
+
<!-- MySQL Config -->
|
|
221
|
+
<div id="configMySQL" style="display:none">
|
|
222
|
+
<div class="inline-group">
|
|
223
|
+
<div style="flex:2">
|
|
224
|
+
<label for="mysqlServer">Server</label>
|
|
225
|
+
<input type="text" id="mysqlServer" placeholder="127.0.0.1" value="127.0.0.1">
|
|
226
|
+
</div>
|
|
227
|
+
<div style="flex:1">
|
|
228
|
+
<label for="mysqlPort">Port</label>
|
|
229
|
+
<input type="number" id="mysqlPort" placeholder="3306" value="3306">
|
|
230
|
+
</div>
|
|
231
|
+
</div>
|
|
232
|
+
<div class="inline-group">
|
|
233
|
+
<div>
|
|
234
|
+
<label for="mysqlUser">User</label>
|
|
235
|
+
<input type="text" id="mysqlUser" placeholder="root" value="root">
|
|
236
|
+
</div>
|
|
237
|
+
<div>
|
|
238
|
+
<label for="mysqlPassword">Password</label>
|
|
239
|
+
<input type="password" id="mysqlPassword" placeholder="password">
|
|
240
|
+
</div>
|
|
241
|
+
</div>
|
|
242
|
+
<label for="mysqlDatabase">Database</label>
|
|
243
|
+
<input type="text" id="mysqlDatabase" placeholder="meadow_clone">
|
|
244
|
+
<div class="inline-group">
|
|
245
|
+
<div>
|
|
246
|
+
<label for="mysqlConnectionLimit">Connection Limit</label>
|
|
247
|
+
<input type="number" id="mysqlConnectionLimit" placeholder="20" value="20">
|
|
248
|
+
</div>
|
|
249
|
+
<div></div>
|
|
250
|
+
</div>
|
|
251
|
+
</div>
|
|
252
|
+
|
|
253
|
+
<!-- MSSQL Config -->
|
|
254
|
+
<div id="configMSSQL" style="display:none">
|
|
255
|
+
<div class="inline-group">
|
|
256
|
+
<div style="flex:2">
|
|
257
|
+
<label for="mssqlServer">Server</label>
|
|
258
|
+
<input type="text" id="mssqlServer" placeholder="127.0.0.1" value="127.0.0.1">
|
|
259
|
+
</div>
|
|
260
|
+
<div style="flex:1">
|
|
261
|
+
<label for="mssqlPort">Port</label>
|
|
262
|
+
<input type="number" id="mssqlPort" placeholder="1433" value="1433">
|
|
263
|
+
</div>
|
|
264
|
+
</div>
|
|
265
|
+
<div class="inline-group">
|
|
266
|
+
<div>
|
|
267
|
+
<label for="mssqlUser">User</label>
|
|
268
|
+
<input type="text" id="mssqlUser" placeholder="sa" value="sa">
|
|
269
|
+
</div>
|
|
270
|
+
<div>
|
|
271
|
+
<label for="mssqlPassword">Password</label>
|
|
272
|
+
<input type="password" id="mssqlPassword" placeholder="password">
|
|
273
|
+
</div>
|
|
274
|
+
</div>
|
|
275
|
+
<label for="mssqlDatabase">Database</label>
|
|
276
|
+
<input type="text" id="mssqlDatabase" placeholder="meadow_clone">
|
|
277
|
+
<div class="inline-group">
|
|
278
|
+
<div>
|
|
279
|
+
<label for="mssqlConnectionLimit">Connection Limit</label>
|
|
280
|
+
<input type="number" id="mssqlConnectionLimit" placeholder="20" value="20">
|
|
281
|
+
</div>
|
|
282
|
+
<div></div>
|
|
283
|
+
</div>
|
|
284
|
+
</div>
|
|
285
|
+
|
|
286
|
+
<!-- PostgreSQL Config -->
|
|
287
|
+
<div id="configPostgreSQL" style="display:none">
|
|
288
|
+
<div class="inline-group">
|
|
289
|
+
<div style="flex:2">
|
|
290
|
+
<label for="postgresqlHost">Host</label>
|
|
291
|
+
<input type="text" id="postgresqlHost" placeholder="127.0.0.1" value="127.0.0.1">
|
|
292
|
+
</div>
|
|
293
|
+
<div style="flex:1">
|
|
294
|
+
<label for="postgresqlPort">Port</label>
|
|
295
|
+
<input type="number" id="postgresqlPort" placeholder="5432" value="5432">
|
|
296
|
+
</div>
|
|
297
|
+
</div>
|
|
298
|
+
<div class="inline-group">
|
|
299
|
+
<div>
|
|
300
|
+
<label for="postgresqlUser">User</label>
|
|
301
|
+
<input type="text" id="postgresqlUser" placeholder="postgres" value="postgres">
|
|
302
|
+
</div>
|
|
303
|
+
<div>
|
|
304
|
+
<label for="postgresqlPassword">Password</label>
|
|
305
|
+
<input type="password" id="postgresqlPassword" placeholder="password">
|
|
306
|
+
</div>
|
|
307
|
+
</div>
|
|
308
|
+
<label for="postgresqlDatabase">Database</label>
|
|
309
|
+
<input type="text" id="postgresqlDatabase" placeholder="meadow_clone">
|
|
310
|
+
<div class="inline-group">
|
|
311
|
+
<div>
|
|
312
|
+
<label for="postgresqlConnectionLimit">Connection Pool Limit</label>
|
|
313
|
+
<input type="number" id="postgresqlConnectionLimit" placeholder="10" value="10">
|
|
314
|
+
</div>
|
|
315
|
+
<div></div>
|
|
316
|
+
</div>
|
|
317
|
+
</div>
|
|
318
|
+
|
|
319
|
+
<!-- Solr Config -->
|
|
320
|
+
<div id="configSolr" style="display:none">
|
|
321
|
+
<div class="inline-group">
|
|
322
|
+
<div style="flex:2">
|
|
323
|
+
<label for="solrHost">Host</label>
|
|
324
|
+
<input type="text" id="solrHost" placeholder="localhost" value="localhost">
|
|
325
|
+
</div>
|
|
326
|
+
<div style="flex:1">
|
|
327
|
+
<label for="solrPort">Port</label>
|
|
328
|
+
<input type="number" id="solrPort" placeholder="8983" value="8983">
|
|
329
|
+
</div>
|
|
330
|
+
</div>
|
|
331
|
+
<div class="inline-group">
|
|
332
|
+
<div style="flex:2">
|
|
333
|
+
<label for="solrCore">Core</label>
|
|
334
|
+
<input type="text" id="solrCore" placeholder="default" value="default">
|
|
335
|
+
</div>
|
|
336
|
+
<div style="flex:1">
|
|
337
|
+
<label for="solrPath">Path</label>
|
|
338
|
+
<input type="text" id="solrPath" placeholder="/solr" value="/solr">
|
|
339
|
+
</div>
|
|
340
|
+
</div>
|
|
341
|
+
<div class="checkbox-row">
|
|
342
|
+
<input type="checkbox" id="solrSecure">
|
|
343
|
+
<label for="solrSecure">Use HTTPS</label>
|
|
344
|
+
</div>
|
|
345
|
+
</div>
|
|
346
|
+
|
|
347
|
+
<!-- MongoDB Config -->
|
|
348
|
+
<div id="configMongoDB" style="display:none">
|
|
349
|
+
<div class="inline-group">
|
|
350
|
+
<div style="flex:2">
|
|
351
|
+
<label for="mongodbHost">Host</label>
|
|
352
|
+
<input type="text" id="mongodbHost" placeholder="127.0.0.1" value="127.0.0.1">
|
|
353
|
+
</div>
|
|
354
|
+
<div style="flex:1">
|
|
355
|
+
<label for="mongodbPort">Port</label>
|
|
356
|
+
<input type="number" id="mongodbPort" placeholder="27017" value="27017">
|
|
357
|
+
</div>
|
|
358
|
+
</div>
|
|
359
|
+
<div class="inline-group">
|
|
360
|
+
<div>
|
|
361
|
+
<label for="mongodbUser">User</label>
|
|
362
|
+
<input type="text" id="mongodbUser" placeholder="(optional)">
|
|
363
|
+
</div>
|
|
364
|
+
<div>
|
|
365
|
+
<label for="mongodbPassword">Password</label>
|
|
366
|
+
<input type="password" id="mongodbPassword" placeholder="(optional)">
|
|
367
|
+
</div>
|
|
368
|
+
</div>
|
|
369
|
+
<label for="mongodbDatabase">Database</label>
|
|
370
|
+
<input type="text" id="mongodbDatabase" placeholder="test" value="test">
|
|
371
|
+
<div class="inline-group">
|
|
372
|
+
<div>
|
|
373
|
+
<label for="mongodbConnectionLimit">Max Pool Size</label>
|
|
374
|
+
<input type="number" id="mongodbConnectionLimit" placeholder="10" value="10">
|
|
375
|
+
</div>
|
|
376
|
+
<div></div>
|
|
377
|
+
</div>
|
|
378
|
+
</div>
|
|
379
|
+
|
|
380
|
+
<!-- RocksDB Config -->
|
|
381
|
+
<div id="configRocksDB" style="display:none">
|
|
382
|
+
<label for="rocksdbFolder">RocksDB Folder Path</label>
|
|
383
|
+
<input type="text" id="rocksdbFolder" placeholder="data/rocksdb" value="data/rocksdb">
|
|
384
|
+
</div>
|
|
385
|
+
|
|
386
|
+
<!-- Bibliograph Config -->
|
|
387
|
+
<div id="configBibliograph" style="display:none">
|
|
388
|
+
<label for="bibliographFolder">Storage Folder Path</label>
|
|
389
|
+
<input type="text" id="bibliographFolder" placeholder="data/bibliograph" value="data/bibliograph">
|
|
390
|
+
</div>
|
|
391
|
+
|
|
392
|
+
<div id="connectionStatus"></div>
|
|
393
|
+
</div>
|
|
394
|
+
</div>
|
|
395
|
+
</div>
|
|
396
|
+
`
|
|
397
|
+
}
|
|
398
|
+
],
|
|
399
|
+
Renderables:
|
|
400
|
+
[
|
|
401
|
+
{
|
|
402
|
+
RenderableHash: 'DataCloner-Connection',
|
|
403
|
+
TemplateHash: 'DataCloner-Connection',
|
|
404
|
+
DestinationAddress: '#DataCloner-Section-Connection'
|
|
405
|
+
}
|
|
406
|
+
]
|
|
407
|
+
};
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
const libPictView = require('pict-view');
|
|
2
|
+
|
|
3
|
+
class DataClonerDeployView extends libPictView
|
|
4
|
+
{
|
|
5
|
+
constructor(pFable, pOptions, pServiceHash)
|
|
6
|
+
{
|
|
7
|
+
super(pFable, pOptions, pServiceHash);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
deploySchema()
|
|
11
|
+
{
|
|
12
|
+
let tmpSelectedTables = this.pict.views['DataCloner-Schema'].getSelectedTables();
|
|
13
|
+
|
|
14
|
+
if (tmpSelectedTables.length === 0)
|
|
15
|
+
{
|
|
16
|
+
this.pict.providers.DataCloner.setStatus('deployStatus', 'No tables selected. Fetch a schema and select tables first.', 'error');
|
|
17
|
+
this.pict.providers.DataCloner.setSectionPhase(4, 'error');
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
this.pict.providers.DataCloner.setSectionPhase(4, 'busy');
|
|
22
|
+
this.pict.providers.DataCloner.setStatus('deployStatus', 'Deploying ' + tmpSelectedTables.length + ' tables...', 'info');
|
|
23
|
+
|
|
24
|
+
let tmpSelf = this;
|
|
25
|
+
this.pict.providers.DataCloner.api('POST', '/clone/schema/deploy', { Tables: tmpSelectedTables })
|
|
26
|
+
.then(function(pData)
|
|
27
|
+
{
|
|
28
|
+
if (pData.Success)
|
|
29
|
+
{
|
|
30
|
+
tmpSelf.pict.providers.DataCloner.setStatus('deployStatus', pData.Message, 'ok');
|
|
31
|
+
tmpSelf.pict.providers.DataCloner.setSectionPhase(4, 'ok');
|
|
32
|
+
tmpSelf.pict.AppData.DataCloner.DeployedTables = pData.TablesDeployed || tmpSelectedTables;
|
|
33
|
+
tmpSelf.pict.providers.DataCloner.saveDeployedTables();
|
|
34
|
+
tmpSelf.pict.views['DataCloner-ViewData'].populateViewTableDropdown();
|
|
35
|
+
tmpSelf.pict.providers.DataCloner.updateAllPreviews();
|
|
36
|
+
}
|
|
37
|
+
else
|
|
38
|
+
{
|
|
39
|
+
tmpSelf.pict.providers.DataCloner.setStatus('deployStatus', 'Deploy failed: ' + (pData.Error || 'Unknown error'), 'error');
|
|
40
|
+
tmpSelf.pict.providers.DataCloner.setSectionPhase(4, 'error');
|
|
41
|
+
}
|
|
42
|
+
})
|
|
43
|
+
.catch(function(pError)
|
|
44
|
+
{
|
|
45
|
+
tmpSelf.pict.providers.DataCloner.setStatus('deployStatus', 'Request failed: ' + pError.message, 'error');
|
|
46
|
+
tmpSelf.pict.providers.DataCloner.setSectionPhase(4, 'error');
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
resetDatabase()
|
|
51
|
+
{
|
|
52
|
+
if (!confirm('This will delete ALL data in the local SQLite database. Continue?'))
|
|
53
|
+
{
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
this.pict.providers.DataCloner.setStatus('deployStatus', 'Resetting database...', 'info');
|
|
58
|
+
|
|
59
|
+
let tmpSelf = this;
|
|
60
|
+
this.pict.providers.DataCloner.api('POST', '/clone/reset')
|
|
61
|
+
.then(function(pData)
|
|
62
|
+
{
|
|
63
|
+
if (pData.Success)
|
|
64
|
+
{
|
|
65
|
+
tmpSelf.pict.providers.DataCloner.setStatus('deployStatus', pData.Message, 'ok');
|
|
66
|
+
// Clear the sync progress display
|
|
67
|
+
let tmpSyncProgress = document.getElementById('syncProgress');
|
|
68
|
+
if (tmpSyncProgress) tmpSyncProgress.innerHTML = '';
|
|
69
|
+
}
|
|
70
|
+
else
|
|
71
|
+
{
|
|
72
|
+
tmpSelf.pict.providers.DataCloner.setStatus('deployStatus', 'Reset failed: ' + (pData.Error || 'Unknown error'), 'error');
|
|
73
|
+
}
|
|
74
|
+
})
|
|
75
|
+
.catch(function(pError)
|
|
76
|
+
{
|
|
77
|
+
tmpSelf.pict.providers.DataCloner.setStatus('deployStatus', 'Request failed: ' + pError.message, 'error');
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
module.exports = DataClonerDeployView;
|
|
83
|
+
|
|
84
|
+
module.exports.default_configuration =
|
|
85
|
+
{
|
|
86
|
+
ViewIdentifier: 'DataCloner-Deploy',
|
|
87
|
+
DefaultRenderable: 'DataCloner-Deploy',
|
|
88
|
+
DefaultDestinationAddress: '#DataCloner-Section-Deploy',
|
|
89
|
+
Templates:
|
|
90
|
+
[
|
|
91
|
+
{
|
|
92
|
+
Hash: 'DataCloner-Deploy',
|
|
93
|
+
Template: /*html*/`
|
|
94
|
+
<div class="accordion-row">
|
|
95
|
+
<div class="accordion-number">4</div>
|
|
96
|
+
<div class="accordion-card" id="section4" data-section="4">
|
|
97
|
+
<div class="accordion-header" onclick="pict.views['DataCloner-Layout'].toggleSection('section4')">
|
|
98
|
+
<div class="accordion-title">Deploy Schema</div>
|
|
99
|
+
<span class="accordion-phase" id="phase4"></span>
|
|
100
|
+
<div class="accordion-preview" id="preview4">Create selected tables in the local database</div>
|
|
101
|
+
<div class="accordion-actions">
|
|
102
|
+
<span class="accordion-go" onclick="event.stopPropagation(); pict.views['DataCloner-Deploy'].deploySchema()">go</span>
|
|
103
|
+
<label class="accordion-auto" onclick="event.stopPropagation()"><input type="checkbox" id="auto4"> <span class="auto-label">auto</span></label>
|
|
104
|
+
</div>
|
|
105
|
+
<div class="accordion-toggle">▼</div>
|
|
106
|
+
</div>
|
|
107
|
+
<div class="accordion-body">
|
|
108
|
+
<p style="font-size:0.9em; color:#666; margin-bottom:10px">Creates the selected tables in the local database and sets up CRUD endpoints (e.g. GET /1.0/Documents).</p>
|
|
109
|
+
<button class="primary" onclick="pict.views['DataCloner-Deploy'].deploySchema()">Deploy Selected Tables</button>
|
|
110
|
+
<button class="danger" onclick="pict.views['DataCloner-Deploy'].resetDatabase()">Reset Database</button>
|
|
111
|
+
<div id="deployStatus"></div>
|
|
112
|
+
</div>
|
|
113
|
+
</div>
|
|
114
|
+
</div>
|
|
115
|
+
`
|
|
116
|
+
}
|
|
117
|
+
],
|
|
118
|
+
Renderables:
|
|
119
|
+
[
|
|
120
|
+
{
|
|
121
|
+
RenderableHash: 'DataCloner-Deploy',
|
|
122
|
+
TemplateHash: 'DataCloner-Deploy',
|
|
123
|
+
DestinationAddress: '#DataCloner-Section-Deploy'
|
|
124
|
+
}
|
|
125
|
+
]
|
|
126
|
+
};
|