@mostajs/setup 1.4.10 → 1.4.12

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.
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Factory for POST /api/setup/wire-module
3
+ * Calls @mostajs/socle installModule() or uninstallModule()
4
+ *
5
+ * Body: { action: 'install' | 'uninstall', module: string }
6
+ * Response: { data: { ok: boolean, module: string, steps: [...] } }
7
+ */
8
+ export declare function createWireModuleHandler(): {
9
+ GET: () => Promise<Response>;
10
+ POST: (req: Request) => Promise<Response>;
11
+ };
@@ -0,0 +1,126 @@
1
+ // @mostajs/setup — Wire module API route factory
2
+ // Author: Dr Hamid MADANI drmdh@msn.com
3
+ /**
4
+ * Factory for POST /api/setup/wire-module
5
+ * Calls @mostajs/socle installModule() or uninstallModule()
6
+ *
7
+ * Body: { action: 'install' | 'uninstall', module: string }
8
+ * Response: { data: { ok: boolean, module: string, steps: [...] } }
9
+ */
10
+ export function createWireModuleHandler() {
11
+ async function POST(req) {
12
+ let body;
13
+ try {
14
+ body = await req.json();
15
+ }
16
+ catch {
17
+ return Response.json({ error: { code: 'VALIDATION_ERROR', message: 'JSON invalide' } }, { status: 400 });
18
+ }
19
+ const { action, module: moduleName } = body;
20
+ if (!action || !moduleName) {
21
+ return Response.json({ error: { code: 'VALIDATION_ERROR', message: 'action et module requis' } }, { status: 400 });
22
+ }
23
+ if (!['install', 'uninstall'].includes(action)) {
24
+ return Response.json({ error: { code: 'VALIDATION_ERROR', message: "action doit etre 'install' ou 'uninstall'" } }, { status: 400 });
25
+ }
26
+ try {
27
+ // Dynamic import to avoid hard dependency on @mostajs/socle
28
+ // Dynamic import — string indirection to avoid TS static resolution
29
+ const pkg = '@mostajs' + '/socle';
30
+ const socle = await import(/* webpackIgnore: true */ pkg);
31
+ const logs = [];
32
+ const opts = {
33
+ projectRoot: process.cwd(),
34
+ log: (msg) => logs.push(msg),
35
+ };
36
+ const result = action === 'install'
37
+ ? socle.installModule(moduleName, opts)
38
+ : socle.uninstallModule(moduleName, opts);
39
+ return Response.json({
40
+ data: {
41
+ ok: result.success,
42
+ action,
43
+ module: moduleName,
44
+ steps: result.steps,
45
+ logs,
46
+ },
47
+ });
48
+ }
49
+ catch (err) {
50
+ const message = err instanceof Error ? err.message : String(err);
51
+ return Response.json({ error: { code: 'WIRE_ERROR', message } }, { status: 500 });
52
+ }
53
+ }
54
+ // GET — list available wire manifests
55
+ async function GET() {
56
+ try {
57
+ const fs = await import('fs');
58
+ const path = await import('path');
59
+ const root = process.cwd();
60
+ const found = [];
61
+ // Check modules/ directory (host overrides)
62
+ const modulesDir = path.join(root, 'modules');
63
+ if (fs.existsSync(modulesDir)) {
64
+ for (const f of fs.readdirSync(modulesDir).filter((f) => f.endsWith('.wire.json'))) {
65
+ const manifest = JSON.parse(fs.readFileSync(path.join(modulesDir, f), 'utf8'));
66
+ const name = f.replace('.wire.json', '');
67
+ // Check if already wired (has the package in package.json deps or schemas wired)
68
+ const pkg = JSON.parse(fs.readFileSync(path.join(root, 'package.json'), 'utf8'));
69
+ const installed = !!pkg.dependencies?.[manifest.package];
70
+ found.push({
71
+ name,
72
+ source: 'modules/',
73
+ package: manifest.package,
74
+ version: manifest.version,
75
+ type: manifest.type || 'functional',
76
+ installed,
77
+ });
78
+ }
79
+ }
80
+ // Check node_modules/@mostajs/*/<name>.wire.json
81
+ const mostaDir = path.join(root, 'node_modules', '@mostajs');
82
+ if (fs.existsSync(mostaDir)) {
83
+ for (const dir of fs.readdirSync(mostaDir)) {
84
+ if (found.some(f => f.name === dir))
85
+ continue;
86
+ const wireFile = path.join(mostaDir, dir, `${dir}.wire.json`);
87
+ if (fs.existsSync(wireFile)) {
88
+ const manifest = JSON.parse(fs.readFileSync(wireFile, 'utf8'));
89
+ // Check if already wired by looking at schemas or permissions in host files
90
+ const permFile = path.join(root, 'src/lib/permissions.ts');
91
+ let installed = false;
92
+ if (manifest.permissions?.permissionsConst && fs.existsSync(permFile)) {
93
+ installed = fs.readFileSync(permFile, 'utf8').includes(manifest.permissions.permissionsConst);
94
+ }
95
+ else if (manifest.schemas?.exports?.[0]) {
96
+ const regFile = path.join(root, 'src/dal/registry.ts');
97
+ if (fs.existsSync(regFile)) {
98
+ installed = fs.readFileSync(regFile, 'utf8').includes(manifest.schemas.exports[0]);
99
+ }
100
+ }
101
+ else if (manifest.menu?.name) {
102
+ const sidebarFile = path.join(root, 'src/components/layout/Sidebar.tsx');
103
+ if (fs.existsSync(sidebarFile)) {
104
+ installed = fs.readFileSync(sidebarFile, 'utf8').includes(manifest.menu.name);
105
+ }
106
+ }
107
+ found.push({
108
+ name: dir,
109
+ source: `@mostajs/${dir}/`,
110
+ package: manifest.package,
111
+ version: manifest.version,
112
+ type: manifest.type || 'functional',
113
+ installed,
114
+ });
115
+ }
116
+ }
117
+ }
118
+ return Response.json({ data: found });
119
+ }
120
+ catch (err) {
121
+ const message = err instanceof Error ? err.message : String(err);
122
+ return Response.json({ error: { code: 'LIST_ERROR', message } }, { status: 500 });
123
+ }
124
+ }
125
+ return { GET, POST };
126
+ }
@@ -5,6 +5,8 @@ export interface ReconfigPanelProps {
5
5
  detectEndpoint?: string;
6
6
  /** API endpoint for JAR upload (default: '/api/setup/upload-jar') */
7
7
  jarEndpoint?: string;
8
+ /** API endpoint for wire module install/uninstall (default: '/api/setup/wire-module') */
9
+ wireEndpoint?: string;
8
10
  /** Translate function */
9
11
  t?: (key: string) => string;
10
12
  /** Called after successful DB change */
@@ -16,4 +18,4 @@ export interface ReconfigPanelProps {
16
18
  /** Callback to run seed after DB change */
17
19
  onSeedRequested?: () => Promise<void>;
18
20
  }
19
- export default function ReconfigPanel({ apiEndpoint, detectEndpoint, jarEndpoint, t, onDbChanged, onModulesChanged, showSeedOption, onSeedRequested, }: ReconfigPanelProps): import("react/jsx-runtime").JSX.Element;
21
+ export default function ReconfigPanel({ apiEndpoint, detectEndpoint, jarEndpoint, wireEndpoint, t, onDbChanged, onModulesChanged, showSeedOption, onSeedRequested, }: ReconfigPanelProps): import("react/jsx-runtime").JSX.Element;
@@ -98,6 +98,38 @@ const S = {
98
98
  }),
99
99
  checkbox: { marginRight: 8, width: 16, height: 16, cursor: 'pointer' },
100
100
  checkboxLabel: { display: 'flex', alignItems: 'center', fontSize: 13, cursor: 'pointer', padding: '8px 0' },
101
+ toggleBtn: (installed, busy) => ({
102
+ padding: '6px 16px',
103
+ border: 'none',
104
+ borderRadius: 6,
105
+ fontSize: 12,
106
+ fontWeight: 700,
107
+ cursor: busy ? 'wait' : 'pointer',
108
+ opacity: busy ? 0.6 : 1,
109
+ backgroundColor: installed ? '#dc2626' : '#059669',
110
+ color: '#fff',
111
+ transition: 'all 0.2s',
112
+ minWidth: 90,
113
+ }),
114
+ wireCard: (installed) => ({
115
+ padding: 16,
116
+ border: `2px solid ${installed ? '#059669' : '#e5e7eb'}`,
117
+ borderRadius: 10,
118
+ backgroundColor: installed ? '#f0fdf4' : '#fafafa',
119
+ transition: 'all 0.2s',
120
+ display: 'flex',
121
+ flexDirection: 'column',
122
+ gap: 8,
123
+ }),
124
+ wireStatus: (installed) => ({
125
+ display: 'inline-block',
126
+ width: 10,
127
+ height: 10,
128
+ borderRadius: '50%',
129
+ backgroundColor: installed ? '#22c55e' : '#ef4444',
130
+ marginRight: 6,
131
+ flexShrink: 0,
132
+ }),
101
133
  currentBadge: {
102
134
  display: 'inline-block',
103
135
  padding: '2px 8px',
@@ -110,7 +142,7 @@ const S = {
110
142
  },
111
143
  };
112
144
  // ── Component ────────────────────────────────────────────────
113
- export default function ReconfigPanel({ apiEndpoint = '/api/setup/reconfig', detectEndpoint = '/api/setup/detect-modules', jarEndpoint = '/api/setup/upload-jar', t = (k) => k, onDbChanged, onModulesChanged, showSeedOption = true, onSeedRequested, }) {
145
+ export default function ReconfigPanel({ apiEndpoint = '/api/setup/reconfig', detectEndpoint = '/api/setup/detect-modules', jarEndpoint = '/api/setup/upload-jar', wireEndpoint = '/api/setup/wire-module', t = (k) => k, onDbChanged, onModulesChanged, showSeedOption = true, onSeedRequested, }) {
114
146
  // --- State ---
115
147
  const [loading, setLoading] = useState(true);
116
148
  const [currentDialect, setCurrentDialect] = useState('');
@@ -140,6 +172,10 @@ export default function ReconfigPanel({ apiEndpoint = '/api/setup/reconfig', det
140
172
  // Module saving
141
173
  const [moduleSaving, setModuleSaving] = useState(false);
142
174
  const [moduleMessage, setModuleMessage] = useState(null);
175
+ const [wireModules, setWireModules] = useState([]);
176
+ const [wireLoading, setWireLoading] = useState(true);
177
+ const [wireBusy, setWireBusy] = useState(null);
178
+ const [wireMessage, setWireMessage] = useState(null);
143
179
  // --- Load current config ---
144
180
  const loadConfig = useCallback(async () => {
145
181
  setLoading(true);
@@ -197,6 +233,57 @@ export default function ReconfigPanel({ apiEndpoint = '/api/setup/reconfig', det
197
233
  }
198
234
  }, [apiEndpoint, detectEndpoint, jarEndpoint]);
199
235
  useEffect(() => { loadConfig(); }, [loadConfig]);
236
+ // --- Load wire modules ---
237
+ const loadWireModules = useCallback(async () => {
238
+ setWireLoading(true);
239
+ try {
240
+ const res = await fetch(wireEndpoint);
241
+ const data = await res.json();
242
+ if (data.data)
243
+ setWireModules(data.data);
244
+ }
245
+ catch {
246
+ // wire endpoint may not exist
247
+ }
248
+ finally {
249
+ setWireLoading(false);
250
+ }
251
+ }, [wireEndpoint]);
252
+ useEffect(() => { loadWireModules(); }, [loadWireModules]);
253
+ // --- Toggle wire module install/uninstall ---
254
+ const handleWireToggle = async (mod) => {
255
+ const action = mod.installed ? 'uninstall' : 'install';
256
+ setWireBusy(mod.name);
257
+ setWireMessage(null);
258
+ try {
259
+ const res = await fetch(wireEndpoint, {
260
+ method: 'POST',
261
+ headers: { 'Content-Type': 'application/json' },
262
+ body: JSON.stringify({ action, module: mod.name }),
263
+ });
264
+ const data = await res.json();
265
+ if (data.data?.ok) {
266
+ setWireMessage({
267
+ type: 'success',
268
+ text: action === 'install'
269
+ ? `${mod.package} cable avec succes`
270
+ : `${mod.package} decable avec succes`,
271
+ module: mod.name,
272
+ });
273
+ await loadWireModules();
274
+ }
275
+ else {
276
+ const errMsg = data.error?.message || data.data?.steps?.find((s) => s.status === 'error')?.detail || 'Erreur';
277
+ setWireMessage({ type: 'error', text: `${action} ${mod.package}: ${errMsg}`, module: mod.name });
278
+ }
279
+ }
280
+ catch {
281
+ setWireMessage({ type: 'error', text: 'Erreur reseau', module: mod.name });
282
+ }
283
+ finally {
284
+ setWireBusy(null);
285
+ }
286
+ };
200
287
  // --- JAR upload ---
201
288
  const handleJarUpload = async (e) => {
202
289
  const file = e.target.files?.[0];
@@ -413,7 +500,16 @@ export default function ReconfigPanel({ apiEndpoint = '/api/setup/reconfig', det
413
500
  }
414
501
  const dialectInfo = DIALECTS.find((d) => d.key === selectedDialect);
415
502
  const isSqlite = selectedDialect === 'sqlite';
416
- return (_jsxs("div", { style: S.panel, children: [_jsxs("div", { style: S.section, children: [_jsxs("div", { style: S.sectionTitle, children: [_jsx("span", { children: "\uD83D\uDCE6" }), " Modules actifs"] }), _jsx("div", { style: S.sectionDesc, children: "Activez ou desactivez les modules @mostajs. Les modules requis ne peuvent pas etre desactives. Seuls les modules installes (dans node_modules) peuvent etre actives." }), moduleMessage && (_jsx("div", { style: S.alert(moduleMessage.type), children: moduleMessage.text })), _jsx("div", { style: S.grid, children: allModules.map((mod) => {
503
+ return (_jsxs("div", { style: S.panel, children: [_jsxs("div", { style: S.section, children: [_jsxs("div", { style: S.sectionTitle, children: [_jsx("span", { children: "\uD83D\uDD0C" }), " Cablage des modules"] }), _jsx("div", { style: S.sectionDesc, children: "Installez ou desinstallez les modules @mostajs. Un module cable injecte ses schemas, routes API, pages, permissions et menus dans l'application hote. Les modules business (schemas + repos) sont marques." }), wireMessage && (_jsx("div", { style: S.alert(wireMessage.type), children: wireMessage.text })), wireLoading ? (_jsx("div", { style: { textAlign: 'center', padding: 20, color: '#6b7280' }, children: "Chargement des manifestes..." })) : wireModules.length === 0 ? (_jsx("div", { style: { textAlign: 'center', padding: 20, color: '#9ca3af' }, children: "Aucun manifeste de cablage trouve" })) : (_jsx("div", { style: S.grid, children: wireModules.map((mod) => (_jsxs("div", { style: S.wireCard(mod.installed), children: [_jsxs("div", { style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between' }, children: [_jsxs("div", { style: { display: 'flex', alignItems: 'center', gap: 8 }, children: [_jsx("span", { style: S.wireStatus(mod.installed) }), _jsxs("span", { style: { fontWeight: 700, fontSize: 14 }, children: ["@mostajs/", mod.name] })] }), _jsx("span", { style: {
504
+ fontSize: 10,
505
+ fontWeight: 600,
506
+ padding: '2px 6px',
507
+ borderRadius: 4,
508
+ backgroundColor: mod.type === 'business' ? '#dbeafe' : '#f3e8ff',
509
+ color: mod.type === 'business' ? '#1e40af' : '#6b21a8',
510
+ }, children: mod.type })] }), _jsxs("div", { style: { fontSize: 12, color: '#6b7280', fontFamily: 'monospace' }, children: ["v", mod.version, " \u2014 ", mod.source] }), _jsxs("div", { style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginTop: 4 }, children: [_jsx("span", { style: { fontSize: 12, fontWeight: 600, color: mod.installed ? '#059669' : '#6b7280' }, children: mod.installed ? 'Cable' : 'Non cable' }), _jsx("button", { style: S.toggleBtn(mod.installed, wireBusy === mod.name), onClick: () => handleWireToggle(mod), disabled: wireBusy !== null, children: wireBusy === mod.name
511
+ ? (mod.installed ? 'Decablage...' : 'Cablage...')
512
+ : (mod.installed ? 'Desinstaller' : 'Installer') })] })] }, mod.name))) }))] }), _jsxs("div", { style: S.section, children: [_jsxs("div", { style: S.sectionTitle, children: [_jsx("span", { children: "\uD83D\uDCE6" }), " Modules actifs"] }), _jsx("div", { style: S.sectionDesc, children: "Activez ou desactivez les modules @mostajs. Les modules requis ne peuvent pas etre desactives. Seuls les modules installes (dans node_modules) peuvent etre actives." }), moduleMessage && (_jsx("div", { style: S.alert(moduleMessage.type), children: moduleMessage.text })), _jsx("div", { style: S.grid, children: allModules.map((mod) => {
417
513
  const isInstalled = installedModules.includes(mod.key);
418
514
  const isActive = activeModules.has(mod.key);
419
515
  const isRequired = !!mod.required;
@@ -10,6 +10,7 @@ export interface SetupWizardProps {
10
10
  installModules?: string;
11
11
  install?: string;
12
12
  uploadJar?: string;
13
+ wireModule?: string;
13
14
  };
14
15
  /** Default database name prefix (e.g. 'secuaccessdb') */
15
16
  dbNamePrefix?: string;
@@ -167,6 +167,40 @@ const S = {
167
167
  flex: (gap = 8) => ({ display: 'flex', alignItems: 'center', gap }),
168
168
  flexBetween: { display: 'flex', justifyContent: 'space-between', alignItems: 'center' },
169
169
  flexWrap: { display: 'flex', flexWrap: 'wrap', gap: 8 },
170
+ // Wire module styles
171
+ wireGrid: { display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(280px, 1fr))', gap: 12, marginTop: 16 },
172
+ wireCard: (installed) => ({
173
+ padding: 16,
174
+ border: `2px solid ${installed ? '#059669' : '#e5e7eb'}`,
175
+ borderRadius: 10,
176
+ backgroundColor: installed ? '#f0fdf4' : '#fafafa',
177
+ transition: 'all 0.2s',
178
+ display: 'flex',
179
+ flexDirection: 'column',
180
+ gap: 8,
181
+ }),
182
+ wireStatus: (installed) => ({
183
+ display: 'inline-block',
184
+ width: 10,
185
+ height: 10,
186
+ borderRadius: '50%',
187
+ backgroundColor: installed ? '#22c55e' : '#ef4444',
188
+ marginRight: 6,
189
+ flexShrink: 0,
190
+ }),
191
+ toggleBtn: (installed, busy) => ({
192
+ padding: '6px 16px',
193
+ border: 'none',
194
+ borderRadius: 6,
195
+ fontSize: 12,
196
+ fontWeight: 700,
197
+ cursor: busy ? 'wait' : 'pointer',
198
+ opacity: busy ? 0.6 : 1,
199
+ backgroundColor: installed ? '#dc2626' : '#059669',
200
+ color: '#fff',
201
+ transition: 'all 0.2s',
202
+ minWidth: 90,
203
+ }),
170
204
  };
171
205
  // ── Helpers ──────────────────────────────────────────────────
172
206
  function resolveModuleDeps(selected, all) {
@@ -318,6 +352,7 @@ export default function SetupWizard({ t: tProp, onComplete, endpoints = {}, dbNa
318
352
  installModules: endpoints.installModules || '/api/setup/install-modules',
319
353
  install: endpoints.install || '/api/setup/install',
320
354
  uploadJar: endpoints.uploadJar || '/api/setup/upload-jar',
355
+ wireModule: endpoints.wireModule || '/api/setup/wire-module',
321
356
  };
322
357
  // --- State ---
323
358
  const [currentStep, setCurrentStep] = useState(0);
@@ -335,6 +370,10 @@ export default function SetupWizard({ t: tProp, onComplete, endpoints = {}, dbNa
335
370
  const [installing, setInstalling] = useState(false);
336
371
  const [installResult, setInstallResult] = useState(null);
337
372
  const [hydrated, setHydrated] = useState(false);
373
+ const [wireModules, setWireModules] = useState([]);
374
+ const [wireLoading, setWireLoading] = useState(false);
375
+ const [wireBusy, setWireBusy] = useState(null);
376
+ const [wireMessage, setWireMessage] = useState(null);
338
377
  const step = STEPS[currentStep];
339
378
  // --- Persist / Restore ---
340
379
  useEffect(() => {
@@ -420,6 +459,59 @@ export default function SetupWizard({ t: tProp, onComplete, endpoints = {}, dbNa
420
459
  }
421
460
  });
422
461
  }, [availableModules]);
462
+ // --- Wire modules (load after installation success) ---
463
+ const loadWireModules = useCallback(async () => {
464
+ setWireLoading(true);
465
+ try {
466
+ const res = await fetch(ep.wireModule);
467
+ const data = await res.json();
468
+ if (data.data)
469
+ setWireModules(data.data);
470
+ }
471
+ catch {
472
+ // wire endpoint may not exist
473
+ }
474
+ finally {
475
+ setWireLoading(false);
476
+ }
477
+ }, [ep.wireModule]);
478
+ // Auto-load wire modules on modules step and after install
479
+ useEffect(() => {
480
+ if (step === 'modules' || installResult?.ok)
481
+ loadWireModules();
482
+ }, [step, installResult?.ok, loadWireModules]);
483
+ const handleWireToggle = async (mod) => {
484
+ const action = mod.installed ? 'uninstall' : 'install';
485
+ setWireBusy(mod.name);
486
+ setWireMessage(null);
487
+ try {
488
+ const res = await fetch(ep.wireModule, {
489
+ method: 'POST',
490
+ headers: { 'Content-Type': 'application/json' },
491
+ body: JSON.stringify({ action, module: mod.name }),
492
+ });
493
+ const data = await res.json();
494
+ if (data.data?.ok) {
495
+ setWireMessage({
496
+ type: 'success',
497
+ text: action === 'install'
498
+ ? `${mod.package} cable avec succes`
499
+ : `${mod.package} decable avec succes`,
500
+ });
501
+ await loadWireModules();
502
+ }
503
+ else {
504
+ const errMsg = data.error?.message || 'Erreur';
505
+ setWireMessage({ type: 'error', text: `${action} ${mod.package}: ${errMsg}` });
506
+ }
507
+ }
508
+ catch {
509
+ setWireMessage({ type: 'error', text: 'Erreur reseau' });
510
+ }
511
+ finally {
512
+ setWireBusy(null);
513
+ }
514
+ };
423
515
  // --- Dialect select ---
424
516
  function selectDialect(d) {
425
517
  setDialect(d);
@@ -534,7 +626,13 @@ export default function SetupWizard({ t: tProp, onComplete, endpoints = {}, dbNa
534
626
  const isSelected = selectedModules.includes(mod.key);
535
627
  const isDetected = detectedModules.includes(mod.key);
536
628
  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));
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
629
+ }) }), _jsxs("div", { style: { marginTop: 28, paddingTop: 20, borderTop: '1px solid #e5e7eb' }, children: [_jsxs("div", { style: { display: 'flex', alignItems: 'center', gap: 8, marginBottom: 12 }, children: [_jsx("span", { style: { fontSize: 18 }, children: "\uD83D\uDD0C" }), _jsxs("div", { children: [_jsx("div", { style: { fontSize: 16, fontWeight: 700, color: '#111827' }, children: "Cablage des modules" }), _jsx("div", { style: { fontSize: 12, color: '#6b7280' }, children: "Cablez les modules pour injecter schemas, routes API, pages et permissions." })] })] }), wireMessage && (_jsx("div", { style: S.alert(wireMessage.type), children: wireMessage.text })), wireLoading ? (_jsx("div", { style: { textAlign: 'center', padding: 12, color: '#6b7280' }, children: "Chargement des manifestes..." })) : wireModules.length === 0 ? (_jsx("div", { style: { textAlign: 'center', padding: 12, color: '#9ca3af', fontSize: 13 }, children: "Aucun manifeste de cablage trouve. Les manifestes seront disponibles apres l'installation." })) : (_jsx("div", { style: S.wireGrid, children: wireModules.map((mod) => (_jsxs("div", { style: S.wireCard(mod.installed), children: [_jsxs("div", { style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between' }, children: [_jsxs("div", { style: { display: 'flex', alignItems: 'center', gap: 8 }, children: [_jsx("span", { style: S.wireStatus(mod.installed) }), _jsxs("span", { style: { fontWeight: 700, fontSize: 14 }, children: ["@mostajs/", mod.name] })] }), _jsx("span", { style: {
630
+ fontSize: 10, fontWeight: 600, padding: '2px 6px', borderRadius: 4,
631
+ backgroundColor: mod.type === 'business' ? '#dbeafe' : '#f3e8ff',
632
+ color: mod.type === 'business' ? '#1e40af' : '#6b21a8',
633
+ }, children: mod.type })] }), _jsxs("div", { style: { fontSize: 12, color: '#6b7280', fontFamily: 'monospace' }, children: ["v", mod.version] }), _jsxs("div", { style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginTop: 4 }, children: [_jsx("span", { style: { fontSize: 12, fontWeight: 600, color: mod.installed ? '#059669' : '#6b7280' }, children: mod.installed ? 'ON' : 'OFF' }), _jsx("button", { style: S.toggleBtn(mod.installed, wireBusy === mod.name), onClick: (e) => { e.stopPropagation(); handleWireToggle(mod); }, disabled: wireBusy !== null, children: wireBusy === mod.name
634
+ ? (mod.installed ? 'Decablage...' : 'Cablage...')
635
+ : (mod.installed ? 'Desinstaller' : 'Installer') })] })] }, mod.name))) }))] }), _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
538
636
  ? `✅ ${t('setup.database.success')}${dbTestResult.dbVersion ? ` (v${dbTestResult.dbVersion})` : ''}`
539
637
  : `❌ ${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 => {
540
638
  const mod = availableModules.find(m => m.key === key);
@@ -543,5 +641,11 @@ export default function SetupWizard({ t: tProp, onComplete, endpoints = {}, dbNa
543
641
  fontSize: 12, backgroundColor: '#f0f9ff', color: '#0369a1',
544
642
  border: '1px solid #bae6fd', borderRadius: 16, padding: '4px 10px',
545
643
  }, children: [mod.icon, " ", mod.label] }, key)) : null;
546
- }) })] }), _jsxs("div", { style: S.summaryCard, children: [_jsx("div", { style: S.summaryTitle, children: t('setup.summary.seedTitle') }), _jsx("p", { style: { ...S.summaryText, marginBottom: 12 }, children: t('setup.summary.seedInfo') }), _jsxs("div", { style: S.checkRow, children: [_jsx("input", { type: "checkbox", style: S.checkbox, checked: seedOptions.activities, onChange: e => setSeedOptions({ ...seedOptions, activities: e.target.checked, demoData: e.target.checked ? seedOptions.demoData : false }), disabled: installing || !!installResult?.ok }), _jsxs("div", { children: [_jsx("div", { style: { fontSize: 13, fontWeight: 500 }, children: t('setup.summary.seedActivities') }), _jsx("div", { style: { fontSize: 12, color: '#9ca3af' }, children: t('setup.summary.seedActivitiesDesc') })] })] }), _jsxs("div", { style: S.checkRow, children: [_jsx("input", { type: "checkbox", style: S.checkbox, checked: seedOptions.demoUsers, onChange: e => setSeedOptions({ ...seedOptions, demoUsers: e.target.checked }), disabled: installing || !!installResult?.ok }), _jsxs("div", { children: [_jsx("div", { style: { fontSize: 13, fontWeight: 500 }, children: t('setup.summary.seedDemoUsers') }), _jsx("div", { style: { fontSize: 12, color: '#9ca3af' }, children: t('setup.summary.seedDemoUsersDesc') })] })] }), _jsxs("div", { style: S.checkRow, children: [_jsx("input", { type: "checkbox", style: S.checkbox, checked: seedOptions.demoData, onChange: e => setSeedOptions({ ...seedOptions, demoData: e.target.checked, activities: e.target.checked ? true : seedOptions.activities }), disabled: installing || !!installResult?.ok }), _jsxs("div", { children: [_jsx("div", { style: { fontSize: 13, fontWeight: 500 }, children: t('setup.summary.seedDemoData') }), _jsx("div", { style: { fontSize: 12, color: '#9ca3af' }, children: t('setup.summary.seedDemoDataDesc') })] })] })] }), installResult && (_jsx("div", { style: S.alert(installResult.ok ? 'success' : 'error'), children: installResult.ok ? (_jsxs(_Fragment, { children: [_jsxs("div", { style: { fontWeight: 600, marginBottom: 4 }, children: ["\u2705 ", t('setup.summary.success')] }), _jsx("div", { children: t('setup.summary.successDesc') }), installResult.needsRestart && (_jsx("div", { style: { color: '#92400e', fontWeight: 500, marginTop: 8 }, children: t('setup.summary.needsRestart') }))] })) : (_jsxs("div", { children: ["\u274C ", installResult.error] })) })), _jsx("div", { style: S.navRow, children: !installResult?.ok ? (_jsxs(_Fragment, { children: [_jsxs("button", { style: S.btn('outline', installing), onClick: goBack, disabled: installing, children: ["\u2190 ", t('setup.back')] }), _jsxs("button", { style: S.btn('primary', installing), onClick: runInstallation, disabled: installing, children: [installing ? '⏳ ' : '⚙️ ', installing ? t('setup.summary.installing') : t('setup.summary.install')] })] })) : (_jsx("div", { style: { width: '100%', textAlign: 'center' }, children: _jsxs("button", { style: S.btn('lg'), onClick: handleComplete, children: [t('setup.summary.goToLogin'), " \u2192"] }) })) })] }))] })] }) }));
644
+ }) })] }), _jsxs("div", { style: S.summaryCard, children: [_jsx("div", { style: S.summaryTitle, children: t('setup.summary.seedTitle') }), _jsx("p", { style: { ...S.summaryText, marginBottom: 12 }, children: t('setup.summary.seedInfo') }), _jsxs("div", { style: S.checkRow, children: [_jsx("input", { type: "checkbox", style: S.checkbox, checked: seedOptions.activities, onChange: e => setSeedOptions({ ...seedOptions, activities: e.target.checked, demoData: e.target.checked ? seedOptions.demoData : false }), disabled: installing || !!installResult?.ok }), _jsxs("div", { children: [_jsx("div", { style: { fontSize: 13, fontWeight: 500 }, children: t('setup.summary.seedActivities') }), _jsx("div", { style: { fontSize: 12, color: '#9ca3af' }, children: t('setup.summary.seedActivitiesDesc') })] })] }), _jsxs("div", { style: S.checkRow, children: [_jsx("input", { type: "checkbox", style: S.checkbox, checked: seedOptions.demoUsers, onChange: e => setSeedOptions({ ...seedOptions, demoUsers: e.target.checked }), disabled: installing || !!installResult?.ok }), _jsxs("div", { children: [_jsx("div", { style: { fontSize: 13, fontWeight: 500 }, children: t('setup.summary.seedDemoUsers') }), _jsx("div", { style: { fontSize: 12, color: '#9ca3af' }, children: t('setup.summary.seedDemoUsersDesc') })] })] }), _jsxs("div", { style: S.checkRow, children: [_jsx("input", { type: "checkbox", style: S.checkbox, checked: seedOptions.demoData, onChange: e => setSeedOptions({ ...seedOptions, demoData: e.target.checked, activities: e.target.checked ? true : seedOptions.activities }), disabled: installing || !!installResult?.ok }), _jsxs("div", { children: [_jsx("div", { style: { fontSize: 13, fontWeight: 500 }, children: t('setup.summary.seedDemoData') }), _jsx("div", { style: { fontSize: 12, color: '#9ca3af' }, children: t('setup.summary.seedDemoDataDesc') })] })] })] }), installResult && (_jsx("div", { style: S.alert(installResult.ok ? 'success' : 'error'), children: installResult.ok ? (_jsxs(_Fragment, { children: [_jsxs("div", { style: { fontWeight: 600, marginBottom: 4 }, children: ["\u2705 ", t('setup.summary.success')] }), _jsx("div", { children: t('setup.summary.successDesc') }), installResult.needsRestart && (_jsx("div", { style: { color: '#92400e', fontWeight: 500, marginTop: 8 }, children: t('setup.summary.needsRestart') }))] })) : (_jsxs("div", { children: ["\u274C ", installResult.error] })) })), installResult?.ok && (_jsxs("div", { style: { ...S.summaryCard, marginTop: 16 }, children: [_jsxs("div", { style: { display: 'flex', alignItems: 'center', gap: 8, marginBottom: 12 }, children: [_jsx("span", { style: { fontSize: 18 }, children: "\uD83D\uDD0C" }), _jsx("div", { style: S.summaryTitle, children: "Cablage des modules" })] }), _jsx("div", { style: { fontSize: 13, color: '#6b7280', marginBottom: 12 }, children: "Cablez les modules pour injecter schemas, routes API, pages et permissions dans l'application." }), wireMessage && (_jsx("div", { style: S.alert(wireMessage.type), children: wireMessage.text })), wireLoading ? (_jsx("div", { style: { textAlign: 'center', padding: 12, color: '#6b7280' }, children: "Chargement..." })) : wireModules.length === 0 ? (_jsx("div", { style: { textAlign: 'center', padding: 12, color: '#9ca3af' }, children: "Aucun manifeste de cablage trouve" })) : (_jsx("div", { style: S.wireGrid, children: wireModules.map((mod) => (_jsxs("div", { style: S.wireCard(mod.installed), children: [_jsxs("div", { style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between' }, children: [_jsxs("div", { style: { display: 'flex', alignItems: 'center', gap: 8 }, children: [_jsx("span", { style: S.wireStatus(mod.installed) }), _jsxs("span", { style: { fontWeight: 700, fontSize: 14 }, children: ["@mostajs/", mod.name] })] }), _jsx("span", { style: {
645
+ fontSize: 10, fontWeight: 600, padding: '2px 6px', borderRadius: 4,
646
+ backgroundColor: mod.type === 'business' ? '#dbeafe' : '#f3e8ff',
647
+ color: mod.type === 'business' ? '#1e40af' : '#6b21a8',
648
+ }, children: mod.type })] }), _jsxs("div", { style: { fontSize: 12, color: '#6b7280', fontFamily: 'monospace' }, children: ["v", mod.version, " \u2014 ", mod.source] }), _jsxs("div", { style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginTop: 4 }, children: [_jsx("span", { style: { fontSize: 12, fontWeight: 600, color: mod.installed ? '#059669' : '#6b7280' }, children: mod.installed ? 'Cable' : 'Non cable' }), _jsx("button", { style: S.toggleBtn(mod.installed, wireBusy === mod.name), onClick: () => handleWireToggle(mod), disabled: wireBusy !== null, children: wireBusy === mod.name
649
+ ? (mod.installed ? 'Decablage...' : 'Cablage...')
650
+ : (mod.installed ? 'Desinstaller' : 'Installer') })] })] }, mod.name))) }))] })), _jsx("div", { style: S.navRow, children: !installResult?.ok ? (_jsxs(_Fragment, { children: [_jsxs("button", { style: S.btn('outline', installing), onClick: goBack, disabled: installing, children: ["\u2190 ", t('setup.back')] }), _jsxs("button", { style: S.btn('primary', installing), onClick: runInstallation, disabled: installing, children: [installing ? '⏳ ' : '⚙️ ', installing ? t('setup.summary.installing') : t('setup.summary.install')] })] })) : (_jsx("div", { style: { width: '100%', textAlign: 'center' }, children: _jsxs("button", { style: S.btn('lg'), onClick: handleComplete, children: [t('setup.summary.goToLogin'), " \u2192"] }) })) })] }))] })] }) }));
547
651
  }
package/dist/index.d.ts CHANGED
@@ -12,6 +12,7 @@ export { createDetectModulesHandler } from './api/detect-modules.route';
12
12
  export { createInstallModulesHandler } from './api/install-modules.route';
13
13
  export { createReconfigHandlers } from './api/reconfig.route';
14
14
  export { createUploadJarHandlers } from './api/upload-jar.route';
15
+ export { createWireModuleHandler } from './api/wire-module.route';
15
16
  export { default as ReconfigPanel } from './components/ReconfigPanel';
16
17
  export { default as SetupWizard } from './components/SetupWizard';
17
18
  export { setupMenuContribution } from './lib/menu';
package/dist/index.js CHANGED
@@ -18,6 +18,7 @@ export { createDetectModulesHandler } from './api/detect-modules.route';
18
18
  export { createInstallModulesHandler } from './api/install-modules.route';
19
19
  export { createReconfigHandlers } from './api/reconfig.route';
20
20
  export { createUploadJarHandlers } from './api/upload-jar.route';
21
+ export { createWireModuleHandler } from './api/wire-module.route';
21
22
  // Components
22
23
  export { default as ReconfigPanel } from './components/ReconfigPanel';
23
24
  export { default as SetupWizard } from './components/SetupWizard';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mostajs/setup",
3
- "version": "1.4.10",
3
+ "version": "1.4.12",
4
4
  "description": "Reusable setup wizard module — multi-dialect DB configuration, .env.local writer, seed runner",
5
5
  "author": "Dr Hamid MADANI <drmdh@msn.com>",
6
6
  "license": "MIT",
@@ -57,10 +57,16 @@
57
57
  "types": "./dist/api/upload-jar.route.d.ts",
58
58
  "import": "./dist/api/upload-jar.route.js",
59
59
  "default": "./dist/api/upload-jar.route.js"
60
+ },
61
+ "./api/wire-module": {
62
+ "types": "./dist/api/wire-module.route.d.ts",
63
+ "import": "./dist/api/wire-module.route.js",
64
+ "default": "./dist/api/wire-module.route.js"
60
65
  }
61
66
  },
62
67
  "files": [
63
68
  "dist",
69
+ "setup.wire.json",
64
70
  "LICENSE",
65
71
  "README.md"
66
72
  ],
@@ -98,12 +104,16 @@
98
104
  },
99
105
  "peerDependencies": {
100
106
  "@mostajs/menu": ">=1.0.2",
107
+ "@mostajs/socle": ">=1.0.0",
101
108
  "react": ">=18.0.0"
102
109
  },
103
110
  "peerDependenciesMeta": {
104
111
  "@mostajs/menu": {
105
112
  "optional": true
106
113
  },
114
+ "@mostajs/socle": {
115
+ "optional": true
116
+ },
107
117
  "react": {
108
118
  "optional": true
109
119
  }
@@ -0,0 +1,11 @@
1
+ {
2
+ "_doc": "Manifeste de câblage pour @mostajs/setup",
3
+ "package": "@mostajs/setup",
4
+ "version": "1.4.10",
5
+ "type": "functional",
6
+
7
+ "menu": {
8
+ "name": "setupMenuContribution",
9
+ "from": "@mostajs/setup/lib/menu"
10
+ }
11
+ }