mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-06-30 18:46:00 +00:00
Fix update for Docker: show commands instead of one-click install
- Detect Docker environment (/.dockerenv) on server - Version check returns is_docker flag - Docker: show terminal commands for docker pull/restart - Git installs: keep one-click update button - Data safety hint shown in both modes
This commit is contained in:
@@ -277,6 +277,8 @@ const de = {
|
|||||||
'admin.update.failed': 'Update fehlgeschlagen',
|
'admin.update.failed': 'Update fehlgeschlagen',
|
||||||
'admin.update.backupHint': 'Wir empfehlen, vor dem Update ein Backup zu erstellen und herunterzuladen.',
|
'admin.update.backupHint': 'Wir empfehlen, vor dem Update ein Backup zu erstellen und herunterzuladen.',
|
||||||
'admin.update.backupLink': 'Zum Backup',
|
'admin.update.backupLink': 'Zum Backup',
|
||||||
|
'admin.update.howTo': 'Update-Anleitung',
|
||||||
|
'admin.update.dockerText': 'Deine NOMAD-Instanz läuft in Docker. Um auf {version} zu aktualisieren, führe folgende Befehle auf deinem Server aus:',
|
||||||
'admin.update.reloadHint': 'Bitte lade die Seite in wenigen Sekunden neu.',
|
'admin.update.reloadHint': 'Bitte lade die Seite in wenigen Sekunden neu.',
|
||||||
|
|
||||||
// Vacay addon
|
// Vacay addon
|
||||||
|
|||||||
@@ -277,6 +277,8 @@ const en = {
|
|||||||
'admin.update.failed': 'Update failed',
|
'admin.update.failed': 'Update failed',
|
||||||
'admin.update.backupHint': 'We recommend creating a backup before updating.',
|
'admin.update.backupHint': 'We recommend creating a backup before updating.',
|
||||||
'admin.update.backupLink': 'Go to Backup',
|
'admin.update.backupLink': 'Go to Backup',
|
||||||
|
'admin.update.howTo': 'How to Update',
|
||||||
|
'admin.update.dockerText': 'Your NOMAD instance runs in Docker. To update to {version}, run the following commands on your server:',
|
||||||
'admin.update.reloadHint': 'Please reload the page in a few seconds.',
|
'admin.update.reloadHint': 'Please reload the page in a few seconds.',
|
||||||
|
|
||||||
// Vacay addon
|
// Vacay addon
|
||||||
|
|||||||
@@ -277,13 +277,23 @@ export default function AdminPage() {
|
|||||||
{t('admin.update.button')}
|
{t('admin.update.button')}
|
||||||
</a>
|
</a>
|
||||||
)}
|
)}
|
||||||
<button
|
{updateInfo.is_docker ? (
|
||||||
onClick={() => setShowUpdateModal(true)}
|
<button
|
||||||
className="flex items-center gap-1.5 px-4 py-2 rounded-lg text-sm font-semibold transition-colors bg-slate-900 dark:bg-white text-white dark:text-slate-900 hover:bg-slate-700 dark:hover:bg-gray-200"
|
onClick={() => setShowUpdateModal(true)}
|
||||||
>
|
className="flex items-center gap-1.5 px-4 py-2 rounded-lg text-sm font-semibold transition-colors bg-slate-900 dark:bg-white text-white dark:text-slate-900 hover:bg-slate-700 dark:hover:bg-gray-200"
|
||||||
<Download className="w-4 h-4" />
|
>
|
||||||
{t('admin.update.install')}
|
<Download className="w-4 h-4" />
|
||||||
</button>
|
{t('admin.update.howTo')}
|
||||||
|
</button>
|
||||||
|
) : (
|
||||||
|
<button
|
||||||
|
onClick={() => setShowUpdateModal(true)}
|
||||||
|
className="flex items-center gap-1.5 px-4 py-2 rounded-lg text-sm font-semibold transition-colors bg-slate-900 dark:bg-white text-white dark:text-slate-900 hover:bg-slate-700 dark:hover:bg-gray-200"
|
||||||
|
>
|
||||||
|
<Download className="w-4 h-4" />
|
||||||
|
{t('admin.update.install')}
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@@ -874,42 +884,74 @@ export default function AdminPage() {
|
|||||||
|
|
||||||
{/* Body */}
|
{/* Body */}
|
||||||
<div style={{ padding: '20px 24px' }}>
|
<div style={{ padding: '20px 24px' }}>
|
||||||
<p className="text-gray-700 dark:text-gray-300" style={{ fontSize: 13, lineHeight: 1.6, margin: 0 }}>
|
{updateInfo?.is_docker ? (
|
||||||
{updateInfo && t('admin.update.confirmText').replace('{current}', `v${updateInfo.current}`).replace('{version}', `v${updateInfo.latest}`)}
|
<>
|
||||||
</p>
|
<p className="text-gray-700 dark:text-gray-300" style={{ fontSize: 13, lineHeight: 1.6, margin: 0 }}>
|
||||||
|
{t('admin.update.dockerText').replace('{version}', `v${updateInfo.latest}`)}
|
||||||
|
</p>
|
||||||
|
|
||||||
<div style={{ marginTop: 14, padding: '10px 12px', borderRadius: 10, fontSize: 12, lineHeight: 1.5 }}
|
<div style={{ marginTop: 14, padding: '12px 14px', borderRadius: 10, fontSize: 12, lineHeight: 1.8, fontFamily: 'monospace', whiteSpace: 'pre-wrap', wordBreak: 'break-all' }}
|
||||||
className="bg-emerald-50 dark:bg-emerald-900/30 text-emerald-700 dark:text-emerald-300 border border-emerald-200 dark:border-emerald-800"
|
className="bg-gray-900 dark:bg-gray-950 text-gray-100 border border-gray-700"
|
||||||
>
|
>
|
||||||
<div className="flex items-start gap-2">
|
{`docker pull mauriceboe/nomad:latest
|
||||||
<CheckCircle className="w-3.5 h-3.5 mt-0.5 flex-shrink-0" />
|
docker stop nomad && docker rm nomad
|
||||||
<span>{t('admin.update.dataInfo')}</span>
|
docker run -d --name nomad \\
|
||||||
</div>
|
-p 3000:3000 \\
|
||||||
</div>
|
-v /opt/nomad/data:/app/data \\
|
||||||
|
-v /opt/nomad/uploads:/app/uploads \\
|
||||||
|
--restart unless-stopped \\
|
||||||
|
mauriceboe/nomad:latest`}
|
||||||
|
</div>
|
||||||
|
|
||||||
<div style={{ marginTop: 10, padding: '10px 12px', borderRadius: 10, fontSize: 12, lineHeight: 1.5 }}
|
<div style={{ marginTop: 10, padding: '10px 12px', borderRadius: 10, fontSize: 12, lineHeight: 1.5 }}
|
||||||
className="bg-blue-50 dark:bg-blue-900/30 text-blue-700 dark:text-blue-300 border border-blue-200 dark:border-blue-800"
|
className="bg-emerald-50 dark:bg-emerald-900/30 text-emerald-700 dark:text-emerald-300 border border-emerald-200 dark:border-emerald-800"
|
||||||
>
|
>
|
||||||
<div className="flex items-start gap-2">
|
<div className="flex items-start gap-2">
|
||||||
<Download className="w-3.5 h-3.5 mt-0.5 flex-shrink-0" />
|
<CheckCircle className="w-3.5 h-3.5 mt-0.5 flex-shrink-0" />
|
||||||
<span>
|
<span>{t('admin.update.dataInfo')}</span>
|
||||||
{t('admin.update.backupHint')}{' '}
|
</div>
|
||||||
<button
|
</div>
|
||||||
onClick={() => { setShowUpdateModal(false); setActiveTab('backup') }}
|
</>
|
||||||
className="underline font-semibold hover:text-blue-950 dark:hover:text-blue-100"
|
) : (
|
||||||
>{t('admin.update.backupLink')}</button>
|
<>
|
||||||
</span>
|
<p className="text-gray-700 dark:text-gray-300" style={{ fontSize: 13, lineHeight: 1.6, margin: 0 }}>
|
||||||
</div>
|
{updateInfo && t('admin.update.confirmText').replace('{current}', `v${updateInfo.current}`).replace('{version}', `v${updateInfo.latest}`)}
|
||||||
</div>
|
</p>
|
||||||
|
|
||||||
<div style={{ marginTop: 10, padding: '10px 12px', borderRadius: 10, fontSize: 12, lineHeight: 1.5 }}
|
<div style={{ marginTop: 14, padding: '10px 12px', borderRadius: 10, fontSize: 12, lineHeight: 1.5 }}
|
||||||
className="bg-red-50 dark:bg-red-900/30 text-red-700 dark:text-red-300 border border-red-200 dark:border-red-800"
|
className="bg-emerald-50 dark:bg-emerald-900/30 text-emerald-700 dark:text-emerald-300 border border-emerald-200 dark:border-emerald-800"
|
||||||
>
|
>
|
||||||
<div className="flex items-start gap-2">
|
<div className="flex items-start gap-2">
|
||||||
<AlertTriangle className="w-3.5 h-3.5 mt-0.5 flex-shrink-0" />
|
<CheckCircle className="w-3.5 h-3.5 mt-0.5 flex-shrink-0" />
|
||||||
<span>{t('admin.update.warning')}</span>
|
<span>{t('admin.update.dataInfo')}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div style={{ marginTop: 10, padding: '10px 12px', borderRadius: 10, fontSize: 12, lineHeight: 1.5 }}
|
||||||
|
className="bg-blue-50 dark:bg-blue-900/30 text-blue-700 dark:text-blue-300 border border-blue-200 dark:border-blue-800"
|
||||||
|
>
|
||||||
|
<div className="flex items-start gap-2">
|
||||||
|
<Download className="w-3.5 h-3.5 mt-0.5 flex-shrink-0" />
|
||||||
|
<span>
|
||||||
|
{t('admin.update.backupHint')}{' '}
|
||||||
|
<button
|
||||||
|
onClick={() => { setShowUpdateModal(false); setActiveTab('backup') }}
|
||||||
|
className="underline font-semibold hover:text-blue-950 dark:hover:text-blue-100"
|
||||||
|
>{t('admin.update.backupLink')}</button>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style={{ marginTop: 10, padding: '10px 12px', borderRadius: 10, fontSize: 12, lineHeight: 1.5 }}
|
||||||
|
className="bg-red-50 dark:bg-red-900/30 text-red-700 dark:text-red-300 border border-red-200 dark:border-red-800"
|
||||||
|
>
|
||||||
|
<div className="flex items-start gap-2">
|
||||||
|
<AlertTriangle className="w-3.5 h-3.5 mt-0.5 flex-shrink-0" />
|
||||||
|
<span>{t('admin.update.warning')}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Footer */}
|
{/* Footer */}
|
||||||
@@ -922,19 +964,21 @@ export default function AdminPage() {
|
|||||||
>
|
>
|
||||||
{t('common.cancel')}
|
{t('common.cancel')}
|
||||||
</button>
|
</button>
|
||||||
<button
|
{!updateInfo?.is_docker && (
|
||||||
onClick={handleInstallUpdate}
|
<button
|
||||||
disabled={updating}
|
onClick={handleInstallUpdate}
|
||||||
className="bg-slate-900 dark:bg-white text-white dark:text-slate-900 hover:bg-slate-700 dark:hover:bg-gray-200 disabled:opacity-60 flex items-center gap-2"
|
disabled={updating}
|
||||||
style={{ padding: '9px 20px', borderRadius: 10, fontSize: 13, fontWeight: 600, border: 'none', cursor: 'pointer', fontFamily: 'inherit' }}
|
className="bg-slate-900 dark:bg-white text-white dark:text-slate-900 hover:bg-slate-700 dark:hover:bg-gray-200 disabled:opacity-60 flex items-center gap-2"
|
||||||
>
|
style={{ padding: '9px 20px', borderRadius: 10, fontSize: 13, fontWeight: 600, border: 'none', cursor: 'pointer', fontFamily: 'inherit' }}
|
||||||
{updating ? (
|
>
|
||||||
<Loader2 size={14} className="animate-spin" />
|
{updating ? (
|
||||||
) : (
|
<Loader2 size={14} className="animate-spin" />
|
||||||
<Download size={14} />
|
) : (
|
||||||
)}
|
<Download size={14} />
|
||||||
{updating ? t('admin.update.installing') : t('admin.update.confirm')}
|
)}
|
||||||
</button>
|
{updating ? t('admin.update.installing') : t('admin.update.confirm')}
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -156,6 +156,14 @@ router.post('/save-demo-baseline', (req, res) => {
|
|||||||
|
|
||||||
// ── Version check ──────────────────────────────────────────
|
// ── Version check ──────────────────────────────────────────
|
||||||
|
|
||||||
|
// Detect if running inside Docker
|
||||||
|
const isDocker = (() => {
|
||||||
|
try {
|
||||||
|
const fs = require('fs');
|
||||||
|
return fs.existsSync('/.dockerenv') || (fs.existsSync('/proc/1/cgroup') && fs.readFileSync('/proc/1/cgroup', 'utf8').includes('docker'));
|
||||||
|
} catch { return false }
|
||||||
|
})();
|
||||||
|
|
||||||
router.get('/version-check', async (req, res) => {
|
router.get('/version-check', async (req, res) => {
|
||||||
const { version: currentVersion } = require('../../package.json');
|
const { version: currentVersion } = require('../../package.json');
|
||||||
try {
|
try {
|
||||||
@@ -167,9 +175,9 @@ router.get('/version-check', async (req, res) => {
|
|||||||
const data = await resp.json();
|
const data = await resp.json();
|
||||||
const latest = (data.tag_name || '').replace(/^v/, '');
|
const latest = (data.tag_name || '').replace(/^v/, '');
|
||||||
const update_available = latest && latest !== currentVersion && compareVersions(latest, currentVersion) > 0;
|
const update_available = latest && latest !== currentVersion && compareVersions(latest, currentVersion) > 0;
|
||||||
res.json({ current: currentVersion, latest, update_available, release_url: data.html_url || '' });
|
res.json({ current: currentVersion, latest, update_available, release_url: data.html_url || '', is_docker: isDocker });
|
||||||
} catch {
|
} catch {
|
||||||
res.json({ current: currentVersion, latest: currentVersion, update_available: false });
|
res.json({ current: currentVersion, latest: currentVersion, update_available: false, is_docker: isDocker });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user