retold-data-service 2.0.43 → 2.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/publish-image.yml +66 -0
- package/BUILDING-AND-PUBLISHING.md +140 -0
- package/Dockerfile +21 -0
- package/package.json +25 -14
- package/source/services/data-cloner/DataCloner-Command-Connection.js +41 -1
- package/source/services/data-cloner/pict-app/Pict-Application-DataCloner.js +50 -16
- package/source/services/data-cloner/pict-app/providers/Pict-Provider-DataCloner.js +185 -96
- package/source/services/data-cloner/pict-app/views/PictView-DataCloner-Connection.js +181 -383
- package/source/services/data-cloner/pict-app/views/PictView-DataCloner-Export.js +34 -57
- package/source/services/data-cloner/web/data-cloner.js +1116 -530
- package/source/services/data-cloner/web/data-cloner.js.map +1 -1
- package/source/services/data-cloner/web/data-cloner.min.js +1 -1
- package/source/services/data-cloner/web/data-cloner.min.js.map +1 -1
|
@@ -1,5 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DataCloner — Database Connection (section 1)
|
|
3
|
+
*
|
|
4
|
+
* Thin accordion shell + connect/test wiring around the shared
|
|
5
|
+
* `pict-section-connection-form` view, which owns the schema-driven
|
|
6
|
+
* provider <select> + per-provider field rendering. The shared view
|
|
7
|
+
* is registered separately in Pict-Application-DataCloner.js and
|
|
8
|
+
* renders into the FormSlot below.
|
|
9
|
+
*
|
|
10
|
+
* Flow:
|
|
11
|
+
* 1. Layout renders, this view paints the accordion shell with an
|
|
12
|
+
* empty FormSlot + "Loading providers…" preview text.
|
|
13
|
+
* 2. Pict-Provider-DataCloner#bootstrapConnectionSchemas() fetches
|
|
14
|
+
* GET /clone/connection/schemas and calls setSchemas() on the
|
|
15
|
+
* shared view, which renders the per-provider form into FormSlot.
|
|
16
|
+
* 3. User clicks Connect / Test → this view delegates to the shared
|
|
17
|
+
* view's getProviderConfig() to assemble the wire-format payload,
|
|
18
|
+
* then POSTs to /clone/connection/{configure,test}.
|
|
19
|
+
*
|
|
20
|
+
* Earlier versions of this view contained the schema rendering inline;
|
|
21
|
+
* that logic has been lifted into pict-section-connection-form so
|
|
22
|
+
* retold-databeacon and retold-facto can share it. See:
|
|
23
|
+
* modules/pict/pict-section-connection-form/source/Pict-Section-ConnectionForm.js
|
|
24
|
+
*/
|
|
25
|
+
'use strict';
|
|
26
|
+
|
|
1
27
|
const libPictView = require('pict-view');
|
|
2
28
|
|
|
29
|
+
const _ViewConfiguration =
|
|
30
|
+
{
|
|
31
|
+
ViewIdentifier: 'DataCloner-Connection',
|
|
32
|
+
DefaultRenderable: 'DataCloner-Connection',
|
|
33
|
+
DefaultDestinationAddress: '#DataCloner-Section-Connection',
|
|
34
|
+
|
|
35
|
+
Templates:
|
|
36
|
+
[
|
|
37
|
+
{
|
|
38
|
+
Hash: 'DataCloner-Connection',
|
|
39
|
+
Template: /*html*/`
|
|
40
|
+
<div class="accordion-row">
|
|
41
|
+
<div class="accordion-number">1</div>
|
|
42
|
+
<div class="accordion-card" id="section1" data-section="1">
|
|
43
|
+
<div class="accordion-header" onclick="pict.views['DataCloner-Layout'].toggleSection('section1')">
|
|
44
|
+
<label class="accordion-auto" onclick="event.stopPropagation()"><input type="checkbox" id="auto1"> <span class="auto-label">auto</span></label>
|
|
45
|
+
<div class="accordion-title">Database Connection</div>
|
|
46
|
+
<span class="accordion-phase" id="phase1"></span>
|
|
47
|
+
<div class="accordion-preview" id="preview1">{~D:AppData.DataCloner.Connection.PreviewText~}</div>
|
|
48
|
+
<div class="accordion-actions">
|
|
49
|
+
<span class="accordion-go" onclick="event.stopPropagation(); pict.views['DataCloner-Connection'].connectProvider()">go</span>
|
|
50
|
+
</div>
|
|
51
|
+
<div class="accordion-toggle">▼</div>
|
|
52
|
+
</div>
|
|
53
|
+
<div class="accordion-body">
|
|
54
|
+
<p style="font-size:0.9em; color:#666; margin-bottom:10px">Configure the local database where cloned data will be stored. The provider list comes from the host's installed meadow-connection modules.</p>
|
|
55
|
+
|
|
56
|
+
<div class="inline-group" style="margin-bottom:10px">
|
|
57
|
+
<div style="flex:1; display:flex; align-items:flex-end; gap:8px; justify-content:flex-end">
|
|
58
|
+
<button class="primary" onclick="pict.views['DataCloner-Connection'].connectProvider()">Connect</button>
|
|
59
|
+
<button class="secondary" onclick="pict.views['DataCloner-Connection'].testConnection()">Test Connection</button>
|
|
60
|
+
</div>
|
|
61
|
+
</div>
|
|
62
|
+
|
|
63
|
+
<!-- pict-section-connection-form renders here -->
|
|
64
|
+
<div id="DataCloner-Connection-FormSlot"></div>
|
|
65
|
+
|
|
66
|
+
<div id="connectionStatus"></div>
|
|
67
|
+
</div>
|
|
68
|
+
</div>
|
|
69
|
+
</div>`
|
|
70
|
+
}
|
|
71
|
+
],
|
|
72
|
+
|
|
73
|
+
Renderables:
|
|
74
|
+
[
|
|
75
|
+
{
|
|
76
|
+
RenderableHash: 'DataCloner-Connection',
|
|
77
|
+
TemplateHash: 'DataCloner-Connection',
|
|
78
|
+
DestinationAddress: '#DataCloner-Section-Connection'
|
|
79
|
+
}
|
|
80
|
+
]
|
|
81
|
+
};
|
|
82
|
+
|
|
3
83
|
class DataClonerConnectionView extends libPictView
|
|
4
84
|
{
|
|
5
85
|
constructor(pFable, pOptions, pServiceHash)
|
|
@@ -7,126 +87,126 @@ class DataClonerConnectionView extends libPictView
|
|
|
7
87
|
super(pFable, pOptions, pServiceHash);
|
|
8
88
|
}
|
|
9
89
|
|
|
10
|
-
|
|
90
|
+
// ====================================================================
|
|
91
|
+
// Lifecycle
|
|
92
|
+
// ====================================================================
|
|
93
|
+
|
|
94
|
+
onBeforeRender(pRenderable)
|
|
11
95
|
{
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
96
|
+
// Make sure AppData has the slot the accordion preview reads
|
|
97
|
+
// from (the Provider's bootstrapConnectionSchemas() will fill in
|
|
98
|
+
// the live values once schemas arrive).
|
|
99
|
+
if (!this.pict.AppData.DataCloner) { this.pict.AppData.DataCloner = {}; }
|
|
100
|
+
if (!this.pict.AppData.DataCloner.Connection)
|
|
15
101
|
{
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
102
|
+
this.pict.AppData.DataCloner.Connection =
|
|
103
|
+
{
|
|
104
|
+
Schemas: [],
|
|
105
|
+
ActiveProvider: '',
|
|
106
|
+
PreviewText: 'Loading providers…'
|
|
107
|
+
};
|
|
21
108
|
}
|
|
22
|
-
|
|
109
|
+
return super.onBeforeRender(pRenderable);
|
|
23
110
|
}
|
|
24
111
|
|
|
25
|
-
|
|
112
|
+
// ====================================================================
|
|
113
|
+
// Helpers used by the provider's preview / persistence layer
|
|
114
|
+
// ====================================================================
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Build the section 1 accordion preview text. Reads live DOM
|
|
118
|
+
* values via the shared view if it's mounted, otherwise falls back
|
|
119
|
+
* to schema defaults.
|
|
120
|
+
*
|
|
121
|
+
* @param {{Schemas: object[], ActiveProvider: string}} pState
|
|
122
|
+
* @returns {string}
|
|
123
|
+
*/
|
|
124
|
+
_buildPreviewText(pState)
|
|
26
125
|
{
|
|
27
|
-
let
|
|
28
|
-
let
|
|
126
|
+
let tmpActive = pState.ActiveProvider;
|
|
127
|
+
let tmpSchema = (pState.Schemas || []).find((pS) => pS.Provider === tmpActive);
|
|
128
|
+
if (!tmpSchema) { return tmpActive || '(no provider selected)'; }
|
|
29
129
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
130
|
+
// Heuristics:
|
|
131
|
+
// - file-based providers (single Path field) → "<DisplayName> at <path>"
|
|
132
|
+
// - host/port/user providers → "<DisplayName> on host:port [as user]"
|
|
133
|
+
// Host/port/user are matched by canonical schema field names.
|
|
134
|
+
let tmpFields = tmpSchema.Fields || [];
|
|
135
|
+
let tmpPath = tmpFields.find((pF) => pF.Type === 'Path');
|
|
136
|
+
if (tmpPath)
|
|
35
137
|
{
|
|
36
|
-
|
|
37
|
-
|
|
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;
|
|
138
|
+
let tmpVal = this._readFieldValue(tmpSchema.Provider, tmpPath) || tmpPath.Default || '';
|
|
139
|
+
return `${tmpSchema.DisplayName} at ${tmpVal}`;
|
|
42
140
|
}
|
|
43
|
-
|
|
141
|
+
let tmpHostField = tmpFields.find((pF) => pF.Name === 'host' || pF.Name === 'server');
|
|
142
|
+
let tmpPortField = tmpFields.find((pF) => pF.Name === 'port');
|
|
143
|
+
let tmpUserField = tmpFields.find((pF) => pF.Name === 'user');
|
|
144
|
+
if (tmpHostField && tmpPortField)
|
|
44
145
|
{
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
tmpConfig.database = document.getElementById('mssqlDatabase').value.trim();
|
|
50
|
-
tmpConfig.connectionLimit = parseInt(document.getElementById('mssqlConnectionLimit').value, 10) || 20;
|
|
51
|
-
// Use ROW_NUMBER() pagination instead of OFFSET/FETCH for
|
|
52
|
-
// SQL Server 2008 R2 / 2012 or databases whose compatibility
|
|
53
|
-
// level is < 110 (the parser rejects OFFSET/FETCH syntax
|
|
54
|
-
// otherwise).
|
|
55
|
-
tmpConfig.LegacyPagination = document.getElementById('mssqlLegacyPagination').checked;
|
|
56
|
-
|
|
57
|
-
// Reliability tuning — pull from the advanced settings block.
|
|
58
|
-
// All are optional; the connection provider falls back to
|
|
59
|
-
// sensible defaults when a value is missing or zero.
|
|
60
|
-
let tmpReqSec = parseInt(document.getElementById('mssqlRequestTimeoutSec').value, 10);
|
|
61
|
-
if (tmpReqSec > 0) tmpConfig.RequestTimeoutMs = tmpReqSec * 1000;
|
|
62
|
-
let tmpConnSec = parseInt(document.getElementById('mssqlConnectionTimeoutSec').value, 10);
|
|
63
|
-
if (tmpConnSec > 0) tmpConfig.ConnectionTimeoutMs = tmpConnSec * 1000;
|
|
64
|
-
|
|
65
|
-
let tmpConnectAttempts = parseInt(document.getElementById('mssqlConnectMaxAttempts').value, 10);
|
|
66
|
-
let tmpDDLAttempts = parseInt(document.getElementById('mssqlDDLMaxAttempts').value, 10);
|
|
67
|
-
let tmpInitialDelaySec = parseInt(document.getElementById('mssqlRetryInitialDelaySec').value, 10);
|
|
68
|
-
let tmpMaxDelaySec = parseInt(document.getElementById('mssqlRetryMaxDelaySec').value, 10);
|
|
69
|
-
|
|
70
|
-
if (tmpConnectAttempts > 0 || tmpInitialDelaySec > 0 || tmpMaxDelaySec > 0)
|
|
71
|
-
{
|
|
72
|
-
tmpConfig.ConnectRetryOptions = {};
|
|
73
|
-
if (tmpConnectAttempts > 0) tmpConfig.ConnectRetryOptions.MaxAttempts = tmpConnectAttempts;
|
|
74
|
-
if (tmpInitialDelaySec > 0) tmpConfig.ConnectRetryOptions.InitialDelayMs = tmpInitialDelaySec * 1000;
|
|
75
|
-
if (tmpMaxDelaySec > 0) tmpConfig.ConnectRetryOptions.MaxDelayMs = tmpMaxDelaySec * 1000;
|
|
76
|
-
}
|
|
77
|
-
if (tmpDDLAttempts > 0 || tmpInitialDelaySec > 0 || tmpMaxDelaySec > 0)
|
|
146
|
+
let tmpHost = this._readFieldValue(tmpSchema.Provider, tmpHostField) || tmpHostField.Default || '';
|
|
147
|
+
let tmpPort = this._readFieldValue(tmpSchema.Provider, tmpPortField) || tmpPortField.Default || '';
|
|
148
|
+
let tmpPreview = `${tmpSchema.DisplayName} on ${tmpHost}:${tmpPort}`;
|
|
149
|
+
if (tmpUserField)
|
|
78
150
|
{
|
|
79
|
-
|
|
80
|
-
if (
|
|
81
|
-
if (tmpInitialDelaySec > 0) tmpConfig.DDLRetryOptions.InitialDelayMs = tmpInitialDelaySec * 1000;
|
|
82
|
-
if (tmpMaxDelaySec > 0) tmpConfig.DDLRetryOptions.MaxDelayMs = tmpMaxDelaySec * 1000;
|
|
151
|
+
let tmpUser = this._readFieldValue(tmpSchema.Provider, tmpUserField) || tmpUserField.Default || '';
|
|
152
|
+
if (tmpUser) { tmpPreview += ` as ${tmpUser}`; }
|
|
83
153
|
}
|
|
154
|
+
return tmpPreview;
|
|
84
155
|
}
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
{
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
tmpConfig.maxPoolSize = parseInt(document.getElementById('mongodbConnectionLimit').value, 10) || 10;
|
|
110
|
-
}
|
|
111
|
-
else if (tmpProvider === 'RocksDB')
|
|
156
|
+
return tmpSchema.DisplayName;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
_readFieldValue(pProvider, pField)
|
|
160
|
+
{
|
|
161
|
+
if (typeof(document) === 'undefined') { return ''; }
|
|
162
|
+
let tmpForm = this.pict.views['PictSection-ConnectionForm'];
|
|
163
|
+
if (!tmpForm) { return ''; }
|
|
164
|
+
let tmpEl = document.getElementById(tmpForm.fieldDOMId(pProvider, pField.Name));
|
|
165
|
+
if (!tmpEl) { return ''; }
|
|
166
|
+
if (pField.Type === 'Boolean') { return tmpEl.checked ? 'true' : ''; }
|
|
167
|
+
return tmpEl.value;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* DOM-id resolver for fields owned by the shared view. Forwarded
|
|
172
|
+
* to PictSection-ConnectionForm so the provider's persistence
|
|
173
|
+
* layer (saveField, restoreFields) can compute element ids without
|
|
174
|
+
* needing to know the prefix.
|
|
175
|
+
*/
|
|
176
|
+
fieldDOMId(pProvider, pFieldName)
|
|
177
|
+
{
|
|
178
|
+
let tmpForm = this.pict.views['PictSection-ConnectionForm'];
|
|
179
|
+
if (tmpForm && typeof(tmpForm.fieldDOMId) === 'function')
|
|
112
180
|
{
|
|
113
|
-
|
|
181
|
+
return tmpForm.fieldDOMId(pProvider, pFieldName);
|
|
114
182
|
}
|
|
115
|
-
|
|
183
|
+
// Fallback before the shared view is mounted.
|
|
184
|
+
let tmpProvider = String(pProvider || '').toLowerCase();
|
|
185
|
+
let tmpField = String(pFieldName || '').replace(/\./g, '_');
|
|
186
|
+
return `datacloner-conn-${tmpProvider}-${tmpField}`;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// ====================================================================
|
|
190
|
+
// Connect / Test — delegate field collection to the shared view
|
|
191
|
+
// ====================================================================
|
|
192
|
+
|
|
193
|
+
getProviderConfig()
|
|
194
|
+
{
|
|
195
|
+
let tmpForm = this.pict.views['PictSection-ConnectionForm'];
|
|
196
|
+
if (tmpForm && typeof(tmpForm.getProviderConfig) === 'function')
|
|
116
197
|
{
|
|
117
|
-
|
|
198
|
+
return tmpForm.getProviderConfig();
|
|
118
199
|
}
|
|
119
|
-
|
|
120
|
-
|
|
200
|
+
// Shared view not mounted yet (early bootstrap, or schemas
|
|
201
|
+
// failed to load). Surface a plain empty payload — the
|
|
202
|
+
// connect/test handlers downstream will report the failure
|
|
203
|
+
// from the server side.
|
|
204
|
+
return { Provider: '', Config: {} };
|
|
121
205
|
}
|
|
122
206
|
|
|
123
207
|
connectProvider()
|
|
124
208
|
{
|
|
125
|
-
|
|
126
|
-
if (this._connectInFlight)
|
|
127
|
-
{
|
|
128
|
-
return;
|
|
129
|
-
}
|
|
209
|
+
if (this._connectInFlight) { return; }
|
|
130
210
|
this._connectInFlight = true;
|
|
131
211
|
|
|
132
212
|
let tmpConnInfo = this.getProviderConfig();
|
|
@@ -199,291 +279,9 @@ class DataClonerConnectionView extends libPictView
|
|
|
199
279
|
}
|
|
200
280
|
})
|
|
201
281
|
.catch(
|
|
202
|
-
() =>
|
|
203
|
-
{
|
|
204
|
-
/* ignore */
|
|
205
|
-
});
|
|
282
|
+
() => { /* ignore */ });
|
|
206
283
|
}
|
|
207
284
|
}
|
|
208
285
|
|
|
209
286
|
module.exports = DataClonerConnectionView;
|
|
210
|
-
|
|
211
|
-
module.exports.default_configuration =
|
|
212
|
-
{
|
|
213
|
-
ViewIdentifier: 'DataCloner-Connection',
|
|
214
|
-
DefaultRenderable: 'DataCloner-Connection',
|
|
215
|
-
DefaultDestinationAddress: '#DataCloner-Section-Connection',
|
|
216
|
-
Templates:
|
|
217
|
-
[
|
|
218
|
-
{
|
|
219
|
-
Hash: 'DataCloner-Connection',
|
|
220
|
-
Template: /*html*/`
|
|
221
|
-
<div class="accordion-row">
|
|
222
|
-
<div class="accordion-number">1</div>
|
|
223
|
-
<div class="accordion-card" id="section1" data-section="1">
|
|
224
|
-
<div class="accordion-header" onclick="pict.views['DataCloner-Layout'].toggleSection('section1')">
|
|
225
|
-
<label class="accordion-auto" onclick="event.stopPropagation()"><input type="checkbox" id="auto1"> <span class="auto-label">auto</span></label>
|
|
226
|
-
<div class="accordion-title">Database Connection</div>
|
|
227
|
-
<span class="accordion-phase" id="phase1"></span>
|
|
228
|
-
<div class="accordion-preview" id="preview1">SQLite at data/cloned.sqlite</div>
|
|
229
|
-
<div class="accordion-actions">
|
|
230
|
-
<span class="accordion-go" onclick="event.stopPropagation(); pict.views['DataCloner-Connection'].connectProvider()">go</span>
|
|
231
|
-
</div>
|
|
232
|
-
<div class="accordion-toggle">▼</div>
|
|
233
|
-
</div>
|
|
234
|
-
<div class="accordion-body">
|
|
235
|
-
<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>
|
|
236
|
-
|
|
237
|
-
<div class="inline-group">
|
|
238
|
-
<div style="flex:0 0 200px">
|
|
239
|
-
<label for="connProvider">Provider</label>
|
|
240
|
-
<select id="connProvider" onchange="pict.views['DataCloner-Connection'].onProviderChange()">
|
|
241
|
-
<option value="SQLite" selected>SQLite</option>
|
|
242
|
-
<option value="MySQL">MySQL</option>
|
|
243
|
-
<option value="MSSQL">MSSQL</option>
|
|
244
|
-
<option value="PostgreSQL">PostgreSQL</option>
|
|
245
|
-
<option value="Solr">Solr</option>
|
|
246
|
-
<option value="MongoDB">MongoDB</option>
|
|
247
|
-
<option value="RocksDB">RocksDB</option>
|
|
248
|
-
<option value="Bibliograph">Bibliograph</option>
|
|
249
|
-
</select>
|
|
250
|
-
</div>
|
|
251
|
-
<div style="flex:1; display:flex; align-items:flex-end; gap:8px">
|
|
252
|
-
<button class="primary" onclick="pict.views['DataCloner-Connection'].connectProvider()">Connect</button>
|
|
253
|
-
<button class="secondary" onclick="pict.views['DataCloner-Connection'].testConnection()">Test Connection</button>
|
|
254
|
-
</div>
|
|
255
|
-
</div>
|
|
256
|
-
|
|
257
|
-
<!-- SQLite Config -->
|
|
258
|
-
<div id="configSQLite">
|
|
259
|
-
<label for="sqliteFilePath">SQLite File Path</label>
|
|
260
|
-
<input type="text" id="sqliteFilePath" placeholder="~/headlight-liveconnect-local/cloned.sqlite" value="~/headlight-liveconnect-local/cloned.sqlite">
|
|
261
|
-
</div>
|
|
262
|
-
|
|
263
|
-
<!-- MySQL Config -->
|
|
264
|
-
<div id="configMySQL" style="display:none">
|
|
265
|
-
<div class="inline-group">
|
|
266
|
-
<div style="flex:2">
|
|
267
|
-
<label for="mysqlServer">Server</label>
|
|
268
|
-
<input type="text" id="mysqlServer" placeholder="127.0.0.1" value="127.0.0.1">
|
|
269
|
-
</div>
|
|
270
|
-
<div style="flex:1">
|
|
271
|
-
<label for="mysqlPort">Port</label>
|
|
272
|
-
<input type="number" id="mysqlPort" placeholder="3306" value="3306">
|
|
273
|
-
</div>
|
|
274
|
-
</div>
|
|
275
|
-
<div class="inline-group">
|
|
276
|
-
<div>
|
|
277
|
-
<label for="mysqlUser">User</label>
|
|
278
|
-
<input type="text" id="mysqlUser" placeholder="root" value="root">
|
|
279
|
-
</div>
|
|
280
|
-
<div>
|
|
281
|
-
<label for="mysqlPassword">Password</label>
|
|
282
|
-
<input type="password" id="mysqlPassword" placeholder="password">
|
|
283
|
-
</div>
|
|
284
|
-
</div>
|
|
285
|
-
<label for="mysqlDatabase">Database</label>
|
|
286
|
-
<input type="text" id="mysqlDatabase" placeholder="meadow_clone">
|
|
287
|
-
<div class="inline-group">
|
|
288
|
-
<div>
|
|
289
|
-
<label for="mysqlConnectionLimit">Connection Limit</label>
|
|
290
|
-
<input type="number" id="mysqlConnectionLimit" placeholder="20" value="20">
|
|
291
|
-
</div>
|
|
292
|
-
<div></div>
|
|
293
|
-
</div>
|
|
294
|
-
</div>
|
|
295
|
-
|
|
296
|
-
<!-- MSSQL Config -->
|
|
297
|
-
<div id="configMSSQL" style="display:none">
|
|
298
|
-
<div class="inline-group">
|
|
299
|
-
<div style="flex:2">
|
|
300
|
-
<label for="mssqlServer">Server</label>
|
|
301
|
-
<input type="text" id="mssqlServer" placeholder="127.0.0.1" value="127.0.0.1">
|
|
302
|
-
</div>
|
|
303
|
-
<div style="flex:1">
|
|
304
|
-
<label for="mssqlPort">Port</label>
|
|
305
|
-
<input type="number" id="mssqlPort" placeholder="1433" value="1433">
|
|
306
|
-
</div>
|
|
307
|
-
</div>
|
|
308
|
-
<div class="inline-group">
|
|
309
|
-
<div>
|
|
310
|
-
<label for="mssqlUser">User</label>
|
|
311
|
-
<input type="text" id="mssqlUser" placeholder="sa" value="sa">
|
|
312
|
-
</div>
|
|
313
|
-
<div>
|
|
314
|
-
<label for="mssqlPassword">Password</label>
|
|
315
|
-
<input type="password" id="mssqlPassword" placeholder="password">
|
|
316
|
-
</div>
|
|
317
|
-
</div>
|
|
318
|
-
<label for="mssqlDatabase">Database</label>
|
|
319
|
-
<input type="text" id="mssqlDatabase" placeholder="meadow_clone">
|
|
320
|
-
<div class="inline-group">
|
|
321
|
-
<div>
|
|
322
|
-
<label for="mssqlConnectionLimit">Connection Limit</label>
|
|
323
|
-
<input type="number" id="mssqlConnectionLimit" placeholder="20" value="20">
|
|
324
|
-
</div>
|
|
325
|
-
<div></div>
|
|
326
|
-
</div>
|
|
327
|
-
<div style="margin-top:8px">
|
|
328
|
-
<input type="checkbox" id="mssqlLegacyPagination">
|
|
329
|
-
<label for="mssqlLegacyPagination" title="Enable for SQL Server 2008 R2 / 2012 or databases at compatibility_level < 110. Uses ROW_NUMBER() pagination instead of OFFSET/FETCH.">Legacy pagination (SQL Server < 2012 / compat level < 110)</label>
|
|
330
|
-
</div>
|
|
331
|
-
|
|
332
|
-
<details style="margin-top:8px">
|
|
333
|
-
<summary style="cursor:pointer; font-weight:600">Reliability & timeouts (advanced)</summary>
|
|
334
|
-
<p style="margin:8px 0; font-size:0.9em; color:#555">Tune these for slow / flaky customer networks. Connection and DDL operations will retry with exponential backoff, classifying each failure (NetworkError / RequestTimeout / PoolDegraded / ServerError) in the logs so the failure mode is obvious.</p>
|
|
335
|
-
<div class="inline-group">
|
|
336
|
-
<div>
|
|
337
|
-
<label for="mssqlRequestTimeoutSec">Request timeout (sec)</label>
|
|
338
|
-
<input type="number" id="mssqlRequestTimeoutSec" placeholder="120" value="120">
|
|
339
|
-
</div>
|
|
340
|
-
<div>
|
|
341
|
-
<label for="mssqlConnectionTimeoutSec">Connection timeout (sec)</label>
|
|
342
|
-
<input type="number" id="mssqlConnectionTimeoutSec" placeholder="60" value="60">
|
|
343
|
-
</div>
|
|
344
|
-
</div>
|
|
345
|
-
<div class="inline-group">
|
|
346
|
-
<div>
|
|
347
|
-
<label for="mssqlConnectMaxAttempts">Connect retries (max attempts)</label>
|
|
348
|
-
<input type="number" id="mssqlConnectMaxAttempts" placeholder="5" value="5" min="1" max="20">
|
|
349
|
-
</div>
|
|
350
|
-
<div>
|
|
351
|
-
<label for="mssqlDDLMaxAttempts">DDL retries (max attempts)</label>
|
|
352
|
-
<input type="number" id="mssqlDDLMaxAttempts" placeholder="5" value="5" min="1" max="20">
|
|
353
|
-
</div>
|
|
354
|
-
</div>
|
|
355
|
-
<div class="inline-group">
|
|
356
|
-
<div>
|
|
357
|
-
<label for="mssqlRetryInitialDelaySec">Retry initial delay (sec)</label>
|
|
358
|
-
<input type="number" id="mssqlRetryInitialDelaySec" placeholder="3" value="3" min="1" max="60">
|
|
359
|
-
</div>
|
|
360
|
-
<div>
|
|
361
|
-
<label for="mssqlRetryMaxDelaySec">Retry max delay (sec)</label>
|
|
362
|
-
<input type="number" id="mssqlRetryMaxDelaySec" placeholder="30" value="30" min="1" max="600">
|
|
363
|
-
</div>
|
|
364
|
-
</div>
|
|
365
|
-
</details>
|
|
366
|
-
</div>
|
|
367
|
-
|
|
368
|
-
<!-- PostgreSQL Config -->
|
|
369
|
-
<div id="configPostgreSQL" style="display:none">
|
|
370
|
-
<div class="inline-group">
|
|
371
|
-
<div style="flex:2">
|
|
372
|
-
<label for="postgresqlHost">Host</label>
|
|
373
|
-
<input type="text" id="postgresqlHost" placeholder="127.0.0.1" value="127.0.0.1">
|
|
374
|
-
</div>
|
|
375
|
-
<div style="flex:1">
|
|
376
|
-
<label for="postgresqlPort">Port</label>
|
|
377
|
-
<input type="number" id="postgresqlPort" placeholder="5432" value="5432">
|
|
378
|
-
</div>
|
|
379
|
-
</div>
|
|
380
|
-
<div class="inline-group">
|
|
381
|
-
<div>
|
|
382
|
-
<label for="postgresqlUser">User</label>
|
|
383
|
-
<input type="text" id="postgresqlUser" placeholder="postgres" value="postgres">
|
|
384
|
-
</div>
|
|
385
|
-
<div>
|
|
386
|
-
<label for="postgresqlPassword">Password</label>
|
|
387
|
-
<input type="password" id="postgresqlPassword" placeholder="password">
|
|
388
|
-
</div>
|
|
389
|
-
</div>
|
|
390
|
-
<label for="postgresqlDatabase">Database</label>
|
|
391
|
-
<input type="text" id="postgresqlDatabase" placeholder="meadow_clone">
|
|
392
|
-
<div class="inline-group">
|
|
393
|
-
<div>
|
|
394
|
-
<label for="postgresqlConnectionLimit">Connection Pool Limit</label>
|
|
395
|
-
<input type="number" id="postgresqlConnectionLimit" placeholder="10" value="10">
|
|
396
|
-
</div>
|
|
397
|
-
<div></div>
|
|
398
|
-
</div>
|
|
399
|
-
</div>
|
|
400
|
-
|
|
401
|
-
<!-- Solr Config -->
|
|
402
|
-
<div id="configSolr" style="display:none">
|
|
403
|
-
<div class="inline-group">
|
|
404
|
-
<div style="flex:2">
|
|
405
|
-
<label for="solrHost">Host</label>
|
|
406
|
-
<input type="text" id="solrHost" placeholder="localhost" value="localhost">
|
|
407
|
-
</div>
|
|
408
|
-
<div style="flex:1">
|
|
409
|
-
<label for="solrPort">Port</label>
|
|
410
|
-
<input type="number" id="solrPort" placeholder="8983" value="8983">
|
|
411
|
-
</div>
|
|
412
|
-
</div>
|
|
413
|
-
<div class="inline-group">
|
|
414
|
-
<div style="flex:2">
|
|
415
|
-
<label for="solrCore">Core</label>
|
|
416
|
-
<input type="text" id="solrCore" placeholder="default" value="default">
|
|
417
|
-
</div>
|
|
418
|
-
<div style="flex:1">
|
|
419
|
-
<label for="solrPath">Path</label>
|
|
420
|
-
<input type="text" id="solrPath" placeholder="/solr" value="/solr">
|
|
421
|
-
</div>
|
|
422
|
-
</div>
|
|
423
|
-
<div class="checkbox-row">
|
|
424
|
-
<input type="checkbox" id="solrSecure">
|
|
425
|
-
<label for="solrSecure">Use HTTPS</label>
|
|
426
|
-
</div>
|
|
427
|
-
</div>
|
|
428
|
-
|
|
429
|
-
<!-- MongoDB Config -->
|
|
430
|
-
<div id="configMongoDB" style="display:none">
|
|
431
|
-
<div class="inline-group">
|
|
432
|
-
<div style="flex:2">
|
|
433
|
-
<label for="mongodbHost">Host</label>
|
|
434
|
-
<input type="text" id="mongodbHost" placeholder="127.0.0.1" value="127.0.0.1">
|
|
435
|
-
</div>
|
|
436
|
-
<div style="flex:1">
|
|
437
|
-
<label for="mongodbPort">Port</label>
|
|
438
|
-
<input type="number" id="mongodbPort" placeholder="27017" value="27017">
|
|
439
|
-
</div>
|
|
440
|
-
</div>
|
|
441
|
-
<div class="inline-group">
|
|
442
|
-
<div>
|
|
443
|
-
<label for="mongodbUser">User</label>
|
|
444
|
-
<input type="text" id="mongodbUser" placeholder="(optional)">
|
|
445
|
-
</div>
|
|
446
|
-
<div>
|
|
447
|
-
<label for="mongodbPassword">Password</label>
|
|
448
|
-
<input type="password" id="mongodbPassword" placeholder="(optional)">
|
|
449
|
-
</div>
|
|
450
|
-
</div>
|
|
451
|
-
<label for="mongodbDatabase">Database</label>
|
|
452
|
-
<input type="text" id="mongodbDatabase" placeholder="test" value="test">
|
|
453
|
-
<div class="inline-group">
|
|
454
|
-
<div>
|
|
455
|
-
<label for="mongodbConnectionLimit">Max Pool Size</label>
|
|
456
|
-
<input type="number" id="mongodbConnectionLimit" placeholder="10" value="10">
|
|
457
|
-
</div>
|
|
458
|
-
<div></div>
|
|
459
|
-
</div>
|
|
460
|
-
</div>
|
|
461
|
-
|
|
462
|
-
<!-- RocksDB Config -->
|
|
463
|
-
<div id="configRocksDB" style="display:none">
|
|
464
|
-
<label for="rocksdbFolder">RocksDB Folder Path</label>
|
|
465
|
-
<input type="text" id="rocksdbFolder" placeholder="data/rocksdb" value="data/rocksdb">
|
|
466
|
-
</div>
|
|
467
|
-
|
|
468
|
-
<!-- Bibliograph Config -->
|
|
469
|
-
<div id="configBibliograph" style="display:none">
|
|
470
|
-
<label for="bibliographFolder">Storage Folder Path</label>
|
|
471
|
-
<input type="text" id="bibliographFolder" placeholder="data/bibliograph" value="data/bibliograph">
|
|
472
|
-
</div>
|
|
473
|
-
|
|
474
|
-
<div id="connectionStatus"></div>
|
|
475
|
-
</div>
|
|
476
|
-
</div>
|
|
477
|
-
</div>
|
|
478
|
-
`
|
|
479
|
-
}
|
|
480
|
-
],
|
|
481
|
-
Renderables:
|
|
482
|
-
[
|
|
483
|
-
{
|
|
484
|
-
RenderableHash: 'DataCloner-Connection',
|
|
485
|
-
TemplateHash: 'DataCloner-Connection',
|
|
486
|
-
DestinationAddress: '#DataCloner-Section-Connection'
|
|
487
|
-
}
|
|
488
|
-
]
|
|
489
|
-
};
|
|
287
|
+
module.exports.default_configuration = _ViewConfiguration;
|