Skip to content

Commit 364e0de

Browse files
committed
fix(deploy): docker
1 parent 40db0f7 commit 364e0de

3 files changed

Lines changed: 63 additions & 0 deletions

File tree

app/api/server.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,20 @@ app.get('/api/status', requireAuth, async (_req, res) => {
9999
}
100100
});
101101

102+
app.post('/api/container/exec', requireAuth, async (req, res) => {
103+
const { name, cmd } = req.body;
104+
if (!name || !cmd) return res.status(400).json({ error: 'name et cmd requis' });
105+
try {
106+
const { execFile: ef } = await import('child_process');
107+
const { promisify } = await import('util');
108+
const exec = promisify(ef);
109+
const { stdout, stderr } = await exec('docker', ['exec', name, 'sh', '-c', cmd]);
110+
res.json({ ok: true, stdout: stdout.trim(), stderr: stderr.trim() });
111+
} catch (err) {
112+
res.status(500).json({ error: err.message, stdout: err.stdout?.trim(), stderr: err.stderr?.trim() });
113+
}
114+
});
115+
102116
app.post('/api/container/restart', requireAuth, async (req, res) => {
103117
const { name } = req.body;
104118
if (!name) return res.status(400).json({ error: 'name requis' });

app/public/app.js

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,7 @@ function renderDeployApps(apps) {
252252
${a.deployed
253253
? `<button onclick="updateDeployApp('${a.name}', this)">Mettre à jour</button>
254254
<button onclick="fullRestartApp('${a.name}', this)" title="Redémarre tous les containers (backend, frontend, BDD…) sur le même réseau">Redémarrage complet</button>
255+
<button onclick="openExecModal('${a.name}')">Exec</button>
255256
<button onclick="openEnvModal('${a.name}')">Éditer .env</button>`
256257
: `<button onclick="promptClone('${a.name}')">Déployer</button>`
257258
}
@@ -291,6 +292,33 @@ async function updateDeployApp(name, btn) {
291292
setTimeout(() => loadDeploy(), 1500);
292293
}
293294

295+
function openExecModal(appName) {
296+
document.getElementById('exec-modal-title').textContent = `Exec — ${appName}`;
297+
document.getElementById('exec-container').value = `${appName}-backend`;
298+
document.getElementById('exec-cmd').value = 'npm run seed:prod';
299+
document.getElementById('exec-output').textContent = '';
300+
document.getElementById('exec-modal').classList.remove('hidden');
301+
}
302+
303+
function closeExecModal() {
304+
document.getElementById('exec-modal').classList.add('hidden');
305+
}
306+
307+
async function runExec() {
308+
const name = document.getElementById('exec-container').value.trim();
309+
const cmd = document.getElementById('exec-cmd').value.trim();
310+
const out = document.getElementById('exec-output');
311+
if (!name || !cmd) return;
312+
out.textContent = '…';
313+
const res = await fetch('/api/container/exec', {
314+
method: 'POST',
315+
headers: { 'Content-Type': 'application/json' },
316+
body: JSON.stringify({ name, cmd }),
317+
});
318+
const data = await res.json().catch(() => ({}));
319+
out.textContent = [data.stdout, data.stderr, data.error].filter(Boolean).join('\n') || '(aucun output)';
320+
}
321+
294322
async function fullRestartApp(name, btn) {
295323
if (!confirm(`Redémarrer tous les containers de "${name}" ? (BDD incluse — quelques secondes d'interruption)`)) return;
296324
btn.disabled = true;

app/public/index.html

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,27 @@ <h2>Déployer une nouvelle app</h2>
141141
</div>
142142
</div>
143143

144+
<div id="exec-modal" class="modal-overlay hidden" onclick="if(event.target===this)closeExecModal()">
145+
<div class="modal">
146+
<div class="modal-header">
147+
<span id="exec-modal-title">Exec</span>
148+
<button class="modal-close" onclick="closeExecModal()"></button>
149+
</div>
150+
<div style="padding:.75rem 1rem;display:flex;flex-direction:column;gap:.5rem">
151+
<div style="display:flex;gap:.5rem;align-items:center">
152+
<label style="font-size:.85rem;white-space:nowrap">Container :</label>
153+
<input id="exec-container" type="text" style="flex:1;font-family:monospace;font-size:.85rem" />
154+
</div>
155+
<div style="display:flex;gap:.5rem;align-items:center">
156+
<label style="font-size:.85rem;white-space:nowrap">Commande :</label>
157+
<input id="exec-cmd" type="text" style="flex:1;font-family:monospace;font-size:.85rem" placeholder="npm run seed:prod" />
158+
</div>
159+
<button onclick="runExec()">Exécuter</button>
160+
</div>
161+
<pre id="exec-output" class="logs-content" style="min-height:80px"></pre>
162+
</div>
163+
</div>
164+
144165
<script src="app.js"></script>
145166
</body>
146167
</html>

0 commit comments

Comments
 (0)