@mostajs/setup 1.4.5 → 1.4.6
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.
|
@@ -80,11 +80,61 @@ export function createUploadJarHandlers() {
|
|
|
80
80
|
}
|
|
81
81
|
catch { /* not a bridge */ }
|
|
82
82
|
}
|
|
83
|
+
// Check HSQLDB server status
|
|
84
|
+
let hsqldbServer = null;
|
|
85
|
+
try {
|
|
86
|
+
const { existsSync, readdirSync, readFileSync } = await import('fs');
|
|
87
|
+
const { join } = await import('path');
|
|
88
|
+
const jarDir = process.env.MOSTA_JAR_DIR || join(process.cwd(), 'jar_files');
|
|
89
|
+
if (existsSync(jarDir)) {
|
|
90
|
+
const serverPidFiles = readdirSync(jarDir).filter((f) => f.startsWith('.hsqldb-server-') && f.endsWith('.pid'));
|
|
91
|
+
for (const file of serverPidFiles) {
|
|
92
|
+
const portMatch = file.match(/\.hsqldb-server-(\d+)\.pid/);
|
|
93
|
+
if (!portMatch)
|
|
94
|
+
continue;
|
|
95
|
+
const port = parseInt(portMatch[1]);
|
|
96
|
+
const pidStr = readFileSync(join(jarDir, file), 'utf-8').trim();
|
|
97
|
+
const pid = parseInt(pidStr);
|
|
98
|
+
let alive = false;
|
|
99
|
+
if (pid > 0) {
|
|
100
|
+
try {
|
|
101
|
+
process.kill(pid, 0);
|
|
102
|
+
alive = true;
|
|
103
|
+
}
|
|
104
|
+
catch { /* dead */ }
|
|
105
|
+
}
|
|
106
|
+
if (alive) {
|
|
107
|
+
hsqldbServer = { running: true, port, pid };
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
// Clean stale PID file
|
|
111
|
+
try {
|
|
112
|
+
(await import('fs')).unlinkSync(join(jarDir, file));
|
|
113
|
+
}
|
|
114
|
+
catch { /* ignore */ }
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
// Also check port 9001 if no PID file found
|
|
119
|
+
if (!hsqldbServer) {
|
|
120
|
+
const { execSync } = await import('child_process');
|
|
121
|
+
try {
|
|
122
|
+
const out = execSync('fuser 9001/tcp 2>/dev/null', { encoding: 'utf-8' }).trim();
|
|
123
|
+
if (out) {
|
|
124
|
+
const pid = parseInt(out);
|
|
125
|
+
hsqldbServer = { running: true, port: 9001, pid: isNaN(pid) ? 0 : pid };
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
catch { /* not running */ }
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
catch { /* ignore */ }
|
|
83
132
|
return Response.json({
|
|
84
133
|
ok: true,
|
|
85
134
|
jars: listJarFiles(),
|
|
86
135
|
dialects: getJdbcDialectStatus(),
|
|
87
136
|
bridges,
|
|
137
|
+
hsqldbServer,
|
|
88
138
|
});
|
|
89
139
|
}
|
|
90
140
|
catch (err) {
|
|
@@ -139,15 +189,128 @@ export function createUploadJarHandlers() {
|
|
|
139
189
|
}
|
|
140
190
|
}
|
|
141
191
|
/**
|
|
142
|
-
* PATCH —
|
|
143
|
-
*
|
|
144
|
-
*
|
|
145
|
-
*
|
|
192
|
+
* PATCH — Manage JDBC bridge and HSQLDB server.
|
|
193
|
+
* start-server: { action: 'start-server', dialect, name, host?, port? }
|
|
194
|
+
* stop-server: { action: 'stop-server', port? }
|
|
195
|
+
* start: { action: 'start', dialect, host, port, name, user?, password? }
|
|
196
|
+
* stop: { action: 'stop', port, pid? }
|
|
146
197
|
*/
|
|
147
198
|
async function PATCH(req) {
|
|
148
199
|
try {
|
|
149
200
|
const body = await req.json();
|
|
150
201
|
const { action } = body;
|
|
202
|
+
// ── Start HSQLDB server ──
|
|
203
|
+
if (action === 'start-server') {
|
|
204
|
+
const { dialect, name, host, port: sgbdPort } = body;
|
|
205
|
+
if (dialect !== 'hsqldb') {
|
|
206
|
+
return Response.json({ ok: false, error: 'start-server supporte uniquement hsqldb' }, { status: 400 });
|
|
207
|
+
}
|
|
208
|
+
const actualPort = sgbdPort || 9001;
|
|
209
|
+
// Check if already running
|
|
210
|
+
try {
|
|
211
|
+
const check = await fetch(`http://${host || 'localhost'}:${actualPort}`, { signal: AbortSignal.timeout(500) });
|
|
212
|
+
void check;
|
|
213
|
+
return Response.json({ ok: true, message: `Serveur HSQLDB deja en marche sur le port ${actualPort}`, port: actualPort, alreadyRunning: true });
|
|
214
|
+
}
|
|
215
|
+
catch { /* not running — proceed */ }
|
|
216
|
+
// Find JAR
|
|
217
|
+
const { JdbcNormalizer } = await import('@mostajs/orm');
|
|
218
|
+
const jarPath = JdbcNormalizer.findJar('hsqldb');
|
|
219
|
+
if (!jarPath) {
|
|
220
|
+
return Response.json({ ok: false, error: 'JAR HSQLDB non trouve. Uploadez hsqldb*.jar d\'abord.' });
|
|
221
|
+
}
|
|
222
|
+
// Launch server
|
|
223
|
+
const { spawn: spawnChild } = await import('child_process');
|
|
224
|
+
const { join } = await import('path');
|
|
225
|
+
const { writeFileSync, existsSync, mkdirSync } = await import('fs');
|
|
226
|
+
const dataDir = join(process.cwd(), 'data');
|
|
227
|
+
if (!existsSync(dataDir))
|
|
228
|
+
mkdirSync(dataDir, { recursive: true });
|
|
229
|
+
const dbAlias = name || 'mydb';
|
|
230
|
+
const serverProc = spawnChild('java', [
|
|
231
|
+
'-cp', jarPath,
|
|
232
|
+
'org.hsqldb.server.Server',
|
|
233
|
+
'--database.0', `file:${join(dataDir, dbAlias)}`,
|
|
234
|
+
'--dbname.0', dbAlias,
|
|
235
|
+
'--port', String(actualPort),
|
|
236
|
+
], {
|
|
237
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
238
|
+
detached: true,
|
|
239
|
+
});
|
|
240
|
+
serverProc.unref();
|
|
241
|
+
const serverPid = serverProc.pid || 0;
|
|
242
|
+
// Save PID file for cleanup
|
|
243
|
+
const jarDir = process.env.MOSTA_JAR_DIR || join(process.cwd(), 'jar_files');
|
|
244
|
+
if (existsSync(jarDir)) {
|
|
245
|
+
writeFileSync(join(jarDir, `.hsqldb-server-${actualPort}.pid`), String(serverPid));
|
|
246
|
+
}
|
|
247
|
+
// Log stderr
|
|
248
|
+
serverProc.stderr?.on('data', (data) => {
|
|
249
|
+
const msg = data.toString().trim();
|
|
250
|
+
if (msg)
|
|
251
|
+
console.error(`[HSQLDB:server] ${msg}`);
|
|
252
|
+
});
|
|
253
|
+
// Wait for server to be ready
|
|
254
|
+
const startTime = Date.now();
|
|
255
|
+
let serverReady = false;
|
|
256
|
+
while (Date.now() - startTime < 8000) {
|
|
257
|
+
try {
|
|
258
|
+
await new Promise(r => setTimeout(r, 500));
|
|
259
|
+
const sock = await fetch(`http://localhost:${actualPort}`, { signal: AbortSignal.timeout(500) });
|
|
260
|
+
void sock;
|
|
261
|
+
serverReady = true;
|
|
262
|
+
break;
|
|
263
|
+
}
|
|
264
|
+
catch {
|
|
265
|
+
// HSQLDB server doesn't speak HTTP, but we can check if the port is listening
|
|
266
|
+
// Try a TCP connection test via the bridge health check pattern
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
// Alternative: check if process is still alive and port is open
|
|
270
|
+
if (!serverReady) {
|
|
271
|
+
try {
|
|
272
|
+
process.kill(serverPid, 0); // check alive
|
|
273
|
+
// Port might be open but not HTTP — that's fine for HSQLDB
|
|
274
|
+
serverReady = true;
|
|
275
|
+
}
|
|
276
|
+
catch { /* process died */ }
|
|
277
|
+
}
|
|
278
|
+
if (!serverReady) {
|
|
279
|
+
return Response.json({ ok: false, error: 'Le serveur HSQLDB n\'a pas demarre dans le delai imparti' });
|
|
280
|
+
}
|
|
281
|
+
return Response.json({ ok: true, port: actualPort, pid: serverPid, message: `Serveur HSQLDB lance (port ${actualPort}, PID ${serverPid}, alias: ${dbAlias})` });
|
|
282
|
+
}
|
|
283
|
+
// ── Stop HSQLDB server ──
|
|
284
|
+
if (action === 'stop-server') {
|
|
285
|
+
const sgbdPort = body.port || 9001;
|
|
286
|
+
try {
|
|
287
|
+
const { execSync } = await import('child_process');
|
|
288
|
+
const { existsSync, unlinkSync, readFileSync } = await import('fs');
|
|
289
|
+
const { join } = await import('path');
|
|
290
|
+
const jarDir = process.env.MOSTA_JAR_DIR || join(process.cwd(), 'jar_files');
|
|
291
|
+
// Kill by PID file
|
|
292
|
+
const pidFile = join(jarDir, `.hsqldb-server-${sgbdPort}.pid`);
|
|
293
|
+
if (existsSync(pidFile)) {
|
|
294
|
+
const pid = parseInt(readFileSync(pidFile, 'utf-8').trim());
|
|
295
|
+
if (pid > 0) {
|
|
296
|
+
try {
|
|
297
|
+
process.kill(pid, 'SIGKILL');
|
|
298
|
+
}
|
|
299
|
+
catch { /* dead */ }
|
|
300
|
+
}
|
|
301
|
+
unlinkSync(pidFile);
|
|
302
|
+
}
|
|
303
|
+
// Also kill anything on the port
|
|
304
|
+
try {
|
|
305
|
+
execSync(`fuser -k ${sgbdPort}/tcp 2>/dev/null`, { stdio: 'ignore' });
|
|
306
|
+
}
|
|
307
|
+
catch { /* already free */ }
|
|
308
|
+
return Response.json({ ok: true, message: `Serveur HSQLDB arrete (port ${sgbdPort})` });
|
|
309
|
+
}
|
|
310
|
+
catch (err) {
|
|
311
|
+
return Response.json({ ok: false, error: err instanceof Error ? err.message : 'Erreur' });
|
|
312
|
+
}
|
|
313
|
+
}
|
|
151
314
|
if (action === 'stop') {
|
|
152
315
|
const bridgePort = body.port || 8765;
|
|
153
316
|
const bridgePid = body.pid || 0;
|
|
@@ -217,12 +217,12 @@ async function fetchRetry(url, init, retries = 3, delay = 2000) {
|
|
|
217
217
|
}
|
|
218
218
|
function JarUploadInline({ dialect, jarEndpoint, dbConfig }) {
|
|
219
219
|
const [uploading, setUploading] = useState(false);
|
|
220
|
-
const [
|
|
220
|
+
const [loading, setLoading] = useState(null); // tracks which action is loading
|
|
221
221
|
const [bridgePort, setBridgePort] = useState(null);
|
|
222
222
|
const [message, setMessage] = useState(null);
|
|
223
223
|
const [jarStatus, setJarStatus] = useState(null);
|
|
224
224
|
const [bridges, setBridges] = useState([]);
|
|
225
|
-
const [
|
|
225
|
+
const [serverInfo, setServerInfo] = useState(null);
|
|
226
226
|
const loadStatus = useCallback(() => {
|
|
227
227
|
fetch(jarEndpoint)
|
|
228
228
|
.then(r => r.json())
|
|
@@ -231,10 +231,15 @@ function JarUploadInline({ dialect, jarEndpoint, dbConfig }) {
|
|
|
231
231
|
const s = data.dialects?.find((d) => d.dialect === dialect);
|
|
232
232
|
setJarStatus(s || { hasJar: false, jarFile: null });
|
|
233
233
|
setBridges(data.bridges || []);
|
|
234
|
-
|
|
234
|
+
if (data.hsqldbServer)
|
|
235
|
+
setServerInfo(data.hsqldbServer);
|
|
236
|
+
else
|
|
237
|
+
setServerInfo(null);
|
|
235
238
|
const active = (data.bridges || []).find((b) => b.status === 'active');
|
|
236
239
|
if (active)
|
|
237
240
|
setBridgePort(active.port);
|
|
241
|
+
else
|
|
242
|
+
setBridgePort(null);
|
|
238
243
|
}
|
|
239
244
|
})
|
|
240
245
|
.catch(() => { });
|
|
@@ -267,63 +272,42 @@ function JarUploadInline({ dialect, jarEndpoint, dbConfig }) {
|
|
|
267
272
|
e.target.value = '';
|
|
268
273
|
}
|
|
269
274
|
};
|
|
270
|
-
const
|
|
271
|
-
|
|
272
|
-
setMessage(null);
|
|
273
|
-
try {
|
|
274
|
-
const res = await fetch(jarEndpoint, {
|
|
275
|
-
method: 'PATCH',
|
|
276
|
-
headers: { 'Content-Type': 'application/json' },
|
|
277
|
-
body: JSON.stringify({ action: 'start', dialect, ...dbConfig }),
|
|
278
|
-
});
|
|
279
|
-
const result = await res.json();
|
|
280
|
-
if (result.ok) {
|
|
281
|
-
setBridgePort(result.port || 8765);
|
|
282
|
-
setMessage({ ok: true, text: `Bridge JDBC lance sur le port ${result.port || 8765}` });
|
|
283
|
-
loadStatus();
|
|
284
|
-
}
|
|
285
|
-
else {
|
|
286
|
-
setMessage({ ok: false, text: result.error || 'Echec lancement du bridge' });
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
catch {
|
|
290
|
-
setMessage({ ok: false, text: 'Erreur reseau' });
|
|
291
|
-
}
|
|
292
|
-
finally {
|
|
293
|
-
setBridgeLoading(false);
|
|
294
|
-
}
|
|
295
|
-
};
|
|
296
|
-
const handleStopBridge = async (port, pid) => {
|
|
297
|
-
setKillingPort(port);
|
|
275
|
+
const patchAction = async (payload, actionLabel) => {
|
|
276
|
+
setLoading(actionLabel);
|
|
298
277
|
setMessage(null);
|
|
299
278
|
try {
|
|
300
279
|
const res = await fetch(jarEndpoint, {
|
|
301
280
|
method: 'PATCH',
|
|
302
281
|
headers: { 'Content-Type': 'application/json' },
|
|
303
|
-
body: JSON.stringify(
|
|
282
|
+
body: JSON.stringify(payload),
|
|
304
283
|
});
|
|
305
284
|
const result = await res.json();
|
|
306
285
|
if (result.ok) {
|
|
307
|
-
|
|
286
|
+
setMessage({ ok: true, text: result.message || actionLabel + ' OK' });
|
|
287
|
+
if (result.port && payload.action === 'start')
|
|
288
|
+
setBridgePort(result.port);
|
|
289
|
+
if (payload.action === 'stop')
|
|
308
290
|
setBridgePort(null);
|
|
309
|
-
setMessage({ ok: true, text: result.message || 'Bridge arrete' });
|
|
310
|
-
loadStatus();
|
|
311
291
|
}
|
|
312
292
|
else {
|
|
313
|
-
setMessage({ ok: false, text: result.error || 'Echec
|
|
293
|
+
setMessage({ ok: false, text: result.error || 'Echec ' + actionLabel });
|
|
314
294
|
}
|
|
295
|
+
loadStatus();
|
|
315
296
|
}
|
|
316
297
|
catch {
|
|
317
298
|
setMessage({ ok: false, text: 'Erreur reseau' });
|
|
318
299
|
}
|
|
319
300
|
finally {
|
|
320
|
-
|
|
301
|
+
setLoading(null);
|
|
321
302
|
}
|
|
322
303
|
};
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
304
|
+
const isHsqldb = dialect === 'hsqldb';
|
|
305
|
+
const btnSmall = (color, disabled) => ({
|
|
306
|
+
...S.btn('primary', disabled), fontSize: 12, padding: '6px 14px',
|
|
307
|
+
backgroundColor: disabled ? '#9ca3af' : color, cursor: disabled ? 'not-allowed' : 'pointer',
|
|
308
|
+
borderRadius: 6, border: 'none', color: '#fff', fontWeight: 600,
|
|
309
|
+
});
|
|
310
|
+
return (_jsxs("div", { style: S.jarBox, children: [_jsxs("div", { style: S.flex(8), children: [_jsx("span", { style: S.jarTitle, children: "Driver JDBC" }), jarStatus?.hasJar ? (_jsx("span", { style: { ...S.badge('installed'), marginLeft: 0 }, children: jarStatus.jarFile })) : (_jsx("span", { style: { fontSize: 12, color: '#6b7280' }, children: "Aucun JAR installe" }))] }), _jsxs("div", { style: { marginTop: 8 }, children: [_jsxs("label", { style: { ...S.btn('primary', uploading), cursor: uploading ? 'wait' : 'pointer', fontSize: 12, padding: '6px 12px' }, children: [uploading ? 'Upload...' : 'Uploader un .jar', _jsx("input", { type: "file", accept: ".jar", onChange: handleUpload, disabled: uploading, style: { display: 'none' } })] }), _jsx("span", { style: { fontSize: 11, color: '#9ca3af', marginLeft: 8 }, children: "Ex: hsqldb*.jar, ojdbc*.jar" })] }), isHsqldb && jarStatus?.hasJar && (_jsxs("div", { style: { marginTop: 10, padding: '10px 12px', backgroundColor: '#fef9c3', borderRadius: 6, border: '1px solid #fde68a' }, children: [_jsxs("div", { style: { fontSize: 12, fontWeight: 600, color: '#92400e', marginBottom: 6 }, children: ["Serveur HSQLDB", serverInfo?.running && (_jsxs("span", { style: { fontWeight: 400, color: '#059669', marginLeft: 8 }, children: ["En marche (port ", serverInfo.port, serverInfo.pid > 0 ? `, PID ${serverInfo.pid}` : '', ")"] })), !serverInfo?.running && (_jsx("span", { style: { fontWeight: 400, color: '#dc2626', marginLeft: 8 }, children: "Arrete" }))] }), _jsxs("div", { style: { display: 'flex', gap: 8 }, children: [_jsx("button", { style: btnSmall('#059669', loading === 'start-server' || serverInfo?.running), onClick: () => patchAction({ action: 'start-server', dialect, name: dbConfig.name, host: dbConfig.host, port: dbConfig.port }, 'start-server'), disabled: loading === 'start-server' || !!serverInfo?.running, children: loading === 'start-server' ? 'Demarrage...' : 'Demarrer le serveur' }), _jsx("button", { style: btnSmall('#dc2626', loading === 'stop-server' || !serverInfo?.running), onClick: () => patchAction({ action: 'stop-server', port: serverInfo?.port || dbConfig.port || 9001 }, 'stop-server'), disabled: loading === 'stop-server' || !serverInfo?.running, children: loading === 'stop-server' ? 'Arret...' : 'Arreter le serveur' })] })] })), jarStatus?.hasJar && (_jsxs("div", { style: { marginTop: 10, padding: '10px 12px', backgroundColor: '#f0fdf4', borderRadius: 6, border: '1px solid #bbf7d0' }, children: [_jsxs("div", { style: { fontSize: 12, fontWeight: 600, color: '#166534', marginBottom: 6 }, children: ["Bridge JDBC", bridgePort && _jsxs("span", { style: { fontWeight: 400, marginLeft: 8 }, children: ["Actif port ", bridgePort] }), !bridgePort && bridges.length === 0 && _jsx("span", { style: { fontWeight: 400, color: '#6b7280', marginLeft: 8 }, children: "Inactif" })] }), _jsx("div", { style: { display: 'flex', gap: 8, marginBottom: bridges.length > 0 ? 8 : 0 }, children: _jsx("button", { style: btnSmall('#059669', loading === 'start-bridge' || bridges.length > 0), onClick: () => patchAction({ action: 'start', dialect, ...dbConfig }, 'start-bridge'), disabled: loading === 'start-bridge' || bridges.length > 0, children: loading === 'start-bridge' ? 'Lancement...' : 'Lancer le bridge' }) }), bridges.map(b => (_jsxs("div", { style: { display: 'flex', alignItems: 'center', gap: 8, padding: '4px 0', fontSize: 12 }, children: [_jsx("span", { style: { width: 8, height: 8, borderRadius: '50%', backgroundColor: b.status === 'active' ? '#22c55e' : '#f59e0b', flexShrink: 0 } }), _jsxs("span", { style: { color: '#374151', fontFamily: 'monospace', fontSize: 11 }, children: [":", b.port, " ", b.pid > 0 ? `(PID ${b.pid})` : '', " ", b.jdbcUrl ? `— ${b.jdbcUrl}` : ''] }), _jsx("button", { style: { ...btnSmall('#dc2626', loading === `kill-${b.port}`), fontSize: 11, padding: '2px 8px', marginLeft: 'auto' }, onClick: () => patchAction({ action: 'stop', port: b.port, pid: b.pid }, `kill-${b.port}`), disabled: loading === `kill-${b.port}`, children: loading === `kill-${b.port}` ? '...' : 'Kill' })] }, b.port)))] })), message && (_jsx("p", { style: { fontSize: 12, color: message.ok ? '#059669' : '#dc2626', marginTop: 8 }, children: message.text }))] }));
|
|
327
311
|
}
|
|
328
312
|
// ── Main Component ───────────────────────────────────────────
|
|
329
313
|
export default function SetupWizard({ t: tProp, onComplete, endpoints = {}, dbNamePrefix = 'mydb', persistState = true, }) {
|
|
@@ -550,7 +534,7 @@ export default function SetupWizard({ t: tProp, onComplete, endpoints = {}, dbNa
|
|
|
550
534
|
const isSelected = selectedModules.includes(mod.key);
|
|
551
535
|
const isDetected = detectedModules.includes(mod.key);
|
|
552
536
|
return (_jsxs("div", { style: S.moduleCard(isSelected, !!mod.required), onClick: () => toggleModule(mod.key), children: [_jsxs("div", { style: S.moduleHeader, children: [_jsxs("div", { style: S.moduleLeft, children: [_jsx("span", { style: { fontSize: 20 }, children: mod.icon }), _jsx("span", { style: S.moduleName, children: mod.label })] }), _jsxs("div", { style: S.moduleBadges, children: [mod.discovered && _jsx("span", { style: S.badge('new'), children: "Nouveau" }), isDetected && _jsx("span", { style: S.badge('installed'), children: t('setup.modules.installed') }), mod.required && _jsx("span", { style: S.badge('required'), children: t('setup.modules.required') }), _jsx("input", { type: "checkbox", checked: isSelected, disabled: mod.required, readOnly: true, style: S.checkbox })] })] }), _jsx("div", { style: S.moduleDesc, children: mod.description }), mod.dependsOn?.length ? (_jsxs("div", { style: { fontSize: 11, color: '#9ca3af', marginTop: 4 }, children: ["Depend de : ", mod.dependsOn.join(', ')] })) : null] }, mod.key));
|
|
553
|
-
}) }), _jsxs("div", { style: S.navRow, children: [_jsxs("button", { style: S.btn('outline'), onClick: goBack, children: ["\u2190 ", t('setup.back')] }), _jsxs("button", { style: S.btn('primary', !canGoNext()), onClick: goNext, disabled: !canGoNext(), children: [t('setup.next'), " \u2192"] })] })] })), step === 'dialect' && (_jsxs("div", { children: [_jsxs("div", { style: S.sectionHeader, children: [_jsx("span", { style: S.sectionIcon, children: "\uD83D\uDCBE" }), _jsxs("div", { children: [_jsx("div", { style: S.sectionTitle, children: t('setup.dialect.title') }), _jsx("div", { style: S.sectionDesc, children: t('setup.dialect.description') })] })] }), _jsx("div", { style: S.grid3, children: DIALECT_INFO.map(d => (_jsxs("div", { style: S.dialectCard(dialect === d.key, !!d.premium), onClick: () => !d.premium && selectDialect(d.key), title: d.premium ? `${d.name} — disponible en version Premium` : d.name, children: [_jsx("div", { style: S.dialectIcon, children: d.icon }), _jsx("div", { style: S.dialectName, children: d.name }), d.premium && (_jsx("span", { style: { ...S.badge('premium'), marginLeft: 0, marginTop: 4 }, children: "Premium" }))] }, d.key))) }), _jsxs("div", { style: S.navRow, children: [_jsxs("button", { style: S.btn('outline'), onClick: goBack, children: ["\u2190 ", t('setup.back')] }), _jsxs("button", { style: S.btn('primary'), onClick: goNext, children: [t('setup.next'), " \u2192"] })] })] })), step === 'database' && (_jsxs("div", { children: [_jsxs("div", { style: S.sectionHeader, children: [_jsx("span", { style: S.sectionIcon, children: "\uD83D\uDDC4\uFE0F" }), _jsxs("div", { children: [_jsx("div", { style: S.sectionTitle, children: t('setup.database.title') }), _jsx("div", { style: S.sectionDesc, children: t('setup.database.description') })] })] }), dialect === 'sqlite' ? (_jsxs("div", { style: S.formGroup, children: [_jsx("label", { style: S.label, children: t('setup.database.name') }), _jsx("input", { style: S.input, value: dbConfig.name, onChange: e => { setDbConfig({ ...dbConfig, name: e.target.value }); setDbTestResult(null); }, placeholder: dbNamePrefix }), _jsxs("p", { style: { fontSize: 11, color: '#9ca3af', marginTop: 4 }, children: [t('setup.database.sqliteInfo'), " ", _jsxs("code", { style: { fontFamily: 'monospace', backgroundColor: '#f3f4f6', padding: '1px 4px', borderRadius: 3 }, children: ["./data/", dbConfig.name, ".db"] })] })] })) : dialect === 'spanner' ? (_jsxs("div", { style: S.formGroup, children: [_jsx("label", { style: S.label, children: t('setup.database.spannerPath') }), _jsx("input", { style: S.input, value: dbConfig.name, onChange: e => { setDbConfig({ ...dbConfig, name: e.target.value }); setDbTestResult(null); }, placeholder: "my-project/my-instance/mydb" }), _jsx("p", { style: { fontSize: 11, color: '#9ca3af', marginTop: 4 }, children: t('setup.database.spannerInfo') })] })) : (_jsxs(_Fragment, { children: [_jsxs("div", { style: S.formRow, children: [_jsxs("div", { style: S.formGroup, children: [_jsx("label", { style: S.label, children: t('setup.database.host') }), _jsx("input", { style: S.input, value: dbConfig.host, onChange: e => { setDbConfig({ ...dbConfig, host: e.target.value }); setDbTestResult(null); } })] }), _jsxs("div", { style: S.formGroup, children: [_jsx("label", { style: S.label, children: t('setup.database.port') }), _jsx("input", { style: S.input, type: "number", value: dbConfig.port, onChange: e => { setDbConfig({ ...dbConfig, port: parseInt(e.target.value) || 0 }); setDbTestResult(null); } })] })] }), _jsxs("div", { style: S.formGroup, children: [_jsx("label", { style: S.label, children: t('setup.database.name') }), _jsx("input", { style: S.input, value: dbConfig.name, onChange: e => { setDbConfig({ ...dbConfig, name: e.target.value }); setDbTestResult(null); } })] }),
|
|
537
|
+
}) }), _jsxs("div", { style: S.navRow, children: [_jsxs("button", { style: S.btn('outline'), onClick: goBack, children: ["\u2190 ", t('setup.back')] }), _jsxs("button", { style: S.btn('primary', !canGoNext()), onClick: goNext, disabled: !canGoNext(), children: [t('setup.next'), " \u2192"] })] })] })), step === 'dialect' && (_jsxs("div", { children: [_jsxs("div", { style: S.sectionHeader, children: [_jsx("span", { style: S.sectionIcon, children: "\uD83D\uDCBE" }), _jsxs("div", { children: [_jsx("div", { style: S.sectionTitle, children: t('setup.dialect.title') }), _jsx("div", { style: S.sectionDesc, children: t('setup.dialect.description') })] })] }), _jsx("div", { style: S.grid3, children: DIALECT_INFO.map(d => (_jsxs("div", { style: S.dialectCard(dialect === d.key, !!d.premium), onClick: () => !d.premium && selectDialect(d.key), title: d.premium ? `${d.name} — disponible en version Premium` : d.name, children: [_jsx("div", { style: S.dialectIcon, children: d.icon }), _jsx("div", { style: S.dialectName, children: d.name }), d.premium && (_jsx("span", { style: { ...S.badge('premium'), marginLeft: 0, marginTop: 4 }, children: "Premium" }))] }, d.key))) }), _jsxs("div", { style: S.navRow, children: [_jsxs("button", { style: S.btn('outline'), onClick: goBack, children: ["\u2190 ", t('setup.back')] }), _jsxs("button", { style: S.btn('primary'), onClick: goNext, children: [t('setup.next'), " \u2192"] })] })] })), step === 'database' && (_jsxs("div", { children: [_jsxs("div", { style: S.sectionHeader, children: [_jsx("span", { style: S.sectionIcon, children: "\uD83D\uDDC4\uFE0F" }), _jsxs("div", { children: [_jsx("div", { style: S.sectionTitle, children: t('setup.database.title') }), _jsx("div", { style: S.sectionDesc, children: t('setup.database.description') })] })] }), dialect === 'sqlite' ? (_jsxs("div", { style: S.formGroup, children: [_jsx("label", { style: S.label, children: t('setup.database.name') }), _jsx("input", { style: S.input, value: dbConfig.name, onChange: e => { setDbConfig({ ...dbConfig, name: e.target.value }); setDbTestResult(null); }, placeholder: dbNamePrefix }), _jsxs("p", { style: { fontSize: 11, color: '#9ca3af', marginTop: 4 }, children: [t('setup.database.sqliteInfo'), " ", _jsxs("code", { style: { fontFamily: 'monospace', backgroundColor: '#f3f4f6', padding: '1px 4px', borderRadius: 3 }, children: ["./data/", dbConfig.name, ".db"] })] })] })) : dialect === 'spanner' ? (_jsxs("div", { style: S.formGroup, children: [_jsx("label", { style: S.label, children: t('setup.database.spannerPath') }), _jsx("input", { style: S.input, value: dbConfig.name, onChange: e => { setDbConfig({ ...dbConfig, name: e.target.value }); setDbTestResult(null); }, placeholder: "my-project/my-instance/mydb" }), _jsx("p", { style: { fontSize: 11, color: '#9ca3af', marginTop: 4 }, children: t('setup.database.spannerInfo') })] })) : (_jsxs(_Fragment, { children: [_jsxs("div", { style: S.formRow, children: [_jsxs("div", { style: S.formGroup, children: [_jsx("label", { style: S.label, children: t('setup.database.host') }), _jsx("input", { style: S.input, value: dbConfig.host, onChange: e => { setDbConfig({ ...dbConfig, host: e.target.value }); setDbTestResult(null); } })] }), _jsxs("div", { style: S.formGroup, children: [_jsx("label", { style: S.label, children: t('setup.database.port') }), _jsx("input", { style: S.input, type: "number", value: dbConfig.port, onChange: e => { setDbConfig({ ...dbConfig, port: parseInt(e.target.value) || 0 }); setDbTestResult(null); } })] })] }), _jsxs("div", { style: S.formGroup, children: [_jsx("label", { style: S.label, children: t('setup.database.name') }), _jsx("input", { style: S.input, value: dbConfig.name, onChange: e => { setDbConfig({ ...dbConfig, name: e.target.value }); setDbTestResult(null); } })] }), _jsxs("div", { style: S.formRow, children: [_jsxs("div", { style: S.formGroup, children: [_jsx("label", { style: S.label, children: t('setup.database.user') }), _jsx("input", { style: S.input, value: dbConfig.user, onChange: e => { setDbConfig({ ...dbConfig, user: e.target.value }); setDbTestResult(null); }, placeholder: dialect === 'hsqldb' ? 'SA' : '' })] }), _jsxs("div", { style: S.formGroup, children: [_jsx("label", { style: S.label, children: t('setup.database.password') }), _jsx("input", { style: S.input, type: "password", value: dbConfig.password, onChange: e => { setDbConfig({ ...dbConfig, password: e.target.value }); setDbTestResult(null); } })] })] })] })), dialect === 'hsqldb' && (_jsxs("div", { style: { ...S.alert('warning'), marginTop: 12, fontSize: 12 }, children: [_jsx("strong", { children: "Prerequis :" }), " Le serveur HSQLDB doit etre lance avant le bridge.", _jsx("br", {}), _jsxs("code", { style: { fontFamily: 'monospace', backgroundColor: '#fef3c7', padding: '2px 6px', borderRadius: 3, display: 'inline-block', marginTop: 4, fontSize: 11 }, children: ["java -cp hsqldb*.jar org.hsqldb.server.Server --database.0 file:./data/", dbConfig.name, " --dbname.0 ", dbConfig.name] })] })), dialect !== 'mongodb' && dialect !== 'sqlite' && (_jsxs("div", { style: { ...S.alert('warning'), marginTop: 12 }, children: [t('setup.database.driverHint'), ' ', _jsx("code", { style: { fontFamily: 'monospace', backgroundColor: '#fef3c7', padding: '1px 4px', borderRadius: 3 }, children: DRIVER_HINTS[dialect] })] })), JDBC_DIALECTS.includes(dialect) && (_jsx(JarUploadInline, { dialect: dialect, jarEndpoint: ep.uploadJar, dbConfig: dbConfig })), dialect !== 'sqlite' && dialect !== 'spanner' && (_jsxs("div", { style: { ...S.checkRow, marginTop: 12, padding: '10px 14px', backgroundColor: '#fffbeb', border: '1px solid #fde68a', borderRadius: 8 }, children: [_jsx("input", { type: "checkbox", style: S.checkbox, checked: createIfNotExists, onChange: e => setCreateIfNotExists(e.target.checked) }), _jsxs("div", { children: [_jsx("div", { style: { fontSize: 13, fontWeight: 500 }, children: t('setup.database.createIfNotExists') }), _jsx("div", { style: { fontSize: 12, color: '#92400e' }, children: t('setup.database.createIfNotExistsDesc') })] })] })), dialect !== 'sqlite' && dialect !== 'spanner' && (_jsxs("div", { style: { ...S.flex(16), marginTop: 16 }, children: [_jsxs("button", { style: S.btn('outline', dbTesting), onClick: testDb, disabled: dbTesting, children: [dbTesting ? '⏳ ' : '🗄️ ', dbTesting ? t('setup.database.testing') : t('setup.database.test')] }), dbTestResult && (_jsx("span", { style: { fontSize: 13, color: dbTestResult.ok ? '#059669' : '#dc2626' }, children: dbTestResult.ok
|
|
554
538
|
? `✅ ${t('setup.database.success')}${dbTestResult.dbVersion ? ` (v${dbTestResult.dbVersion})` : ''}`
|
|
555
539
|
: `❌ ${t('setup.database.error')}: ${dbTestResult.error}` }))] })), _jsxs("div", { style: S.navRow, children: [_jsxs("button", { style: S.btn('outline'), onClick: goBack, children: ["\u2190 ", t('setup.back')] }), _jsxs("button", { style: S.btn('primary', !canGoNext()), onClick: goNext, disabled: !canGoNext(), children: [t('setup.next'), " \u2192"] })] })] })), step === 'admin' && (_jsxs("div", { children: [_jsxs("div", { style: S.sectionHeader, children: [_jsx("span", { style: S.sectionIcon, children: "\uD83D\uDC64" }), _jsxs("div", { children: [_jsx("div", { style: S.sectionTitle, children: t('setup.admin.title') }), _jsx("div", { style: S.sectionDesc, children: t('setup.admin.description') })] })] }), _jsxs("div", { style: S.formRow, children: [_jsxs("div", { style: S.formGroup, children: [_jsx("label", { style: S.label, children: t('setup.admin.firstName') }), _jsx("input", { style: S.input, value: adminConfig.firstName, onChange: e => setAdminConfig({ ...adminConfig, firstName: e.target.value }) })] }), _jsxs("div", { style: S.formGroup, children: [_jsx("label", { style: S.label, children: t('setup.admin.lastName') }), _jsx("input", { style: S.input, value: adminConfig.lastName, onChange: e => setAdminConfig({ ...adminConfig, lastName: e.target.value }) })] })] }), _jsxs("div", { style: S.formGroup, children: [_jsx("label", { style: S.label, children: t('setup.admin.email') }), _jsx("input", { style: S.input, type: "email", value: adminConfig.email, onChange: e => setAdminConfig({ ...adminConfig, email: e.target.value }), placeholder: "admin@example.com" })] }), _jsxs("div", { style: S.formRow, children: [_jsxs("div", { style: S.formGroup, children: [_jsx("label", { style: S.label, children: t('setup.admin.password') }), _jsx("input", { style: S.input, type: "password", value: adminConfig.password, onChange: e => setAdminConfig({ ...adminConfig, password: e.target.value }) })] }), _jsxs("div", { style: S.formGroup, children: [_jsx("label", { style: S.label, children: t('setup.admin.confirmPassword') }), _jsx("input", { style: S.input, type: "password", value: adminConfig.confirmPassword, onChange: e => setAdminConfig({ ...adminConfig, confirmPassword: e.target.value }) })] })] }), adminConfig.password && adminConfig.confirmPassword && adminConfig.password !== adminConfig.confirmPassword && (_jsx("p", { style: { fontSize: 13, color: '#dc2626' }, children: t('setup.admin.passwordMismatch') })), _jsxs("div", { style: S.navRow, children: [_jsxs("button", { style: S.btn('outline'), onClick: goBack, children: ["\u2190 ", t('setup.back')] }), _jsxs("button", { style: S.btn('primary', !canGoNext()), onClick: goNext, disabled: !canGoNext(), children: [t('setup.next'), " \u2192"] })] })] })), step === 'summary' && (_jsxs("div", { children: [_jsxs("div", { style: S.sectionHeader, children: [_jsx("span", { style: S.sectionIcon, children: "\u2699\uFE0F" }), _jsxs("div", { children: [_jsx("div", { style: S.sectionTitle, children: t('setup.summary.title') }), _jsx("div", { style: S.sectionDesc, children: t('setup.summary.description') })] })] }), _jsxs("div", { style: S.summaryCard, children: [_jsx("div", { style: S.summaryTitle, children: t('setup.summary.dbConfig') }), _jsxs("div", { style: S.summaryText, children: [_jsx("span", { style: { fontFamily: 'monospace' }, children: dbSummaryLabel() }), dialect !== 'sqlite' && dbConfig.user && _jsxs("span", { style: { display: 'block', marginTop: 4 }, children: ["Utilisateur: ", dbConfig.user] })] })] }), _jsxs("div", { style: S.summaryCard, children: [_jsx("div", { style: S.summaryTitle, children: t('setup.summary.adminConfig') }), _jsxs("div", { style: S.summaryText, children: [_jsxs("div", { children: [adminConfig.firstName, " ", adminConfig.lastName] }), _jsx("div", { children: adminConfig.email })] })] }), _jsxs("div", { style: S.summaryCard, children: [_jsx("div", { style: S.summaryTitle, children: t('setup.modules.title') }), _jsx("div", { style: S.flexWrap, children: selectedModules.map(key => {
|
|
556
540
|
const mod = availableModules.find(m => m.key === key);
|
package/dist/lib/compose-uri.js
CHANGED
|
@@ -28,6 +28,8 @@ export function composeDbUri(dialect, config) {
|
|
|
28
28
|
case 'hana':
|
|
29
29
|
return `hana://${eu}:${ep}@${host}:${port}`;
|
|
30
30
|
case 'hsqldb':
|
|
31
|
+
if (user)
|
|
32
|
+
return `hsqldb:hsql://${eu}:${ep}@${host}:${port}/${name}`;
|
|
31
33
|
return `hsqldb:hsql://${host}:${port}/${name}`;
|
|
32
34
|
case 'spanner':
|
|
33
35
|
return `spanner://projects/${name}`;
|
package/package.json
CHANGED