9c69b3ff07
gates / gates (push) Successful in 27s
Evidence off the machine at the end of the phases that produced it (R-320). Teardown follows. PHASE 2 — the two database engines, through the REAL Update button: - MariaDB 11.6 -> 12.3 on nextcloud: PROVEN, and pressed through the button for the first time. All four SPIKE-r459 observables: the datadir's own record moved 11.6.2 -> 12.3.3; the engine itself says "already upgraded ... no need to run mariadb-upgrade again"; the entrypoint says "Major version upgrade detected ... Check required!" and then STARTED and FINISHED it (not the `skipped due to $MARIADB_AUTO_UPGRADE` line R-459 feared); and the engine took its own pre-upgrade backup, 631 905 B. The seeded Nextcloud account read back. - PostgreSQL 16 -> 17 on docmost: FAILED exactly as R-463 predicted and nobody had measured. 5.1 s to held; the pin named 17 while nothing ran; the restore brought it back in 29.1 s. The engine's REFUSAL LINE was destroyed by failAndHold before any probe could read it, so it was REPRODUCED INDEPENDENTLY with a control on every step (R-320). PHASE 3 — the bad days. B1 produced THE UNATTENDED HOLD, which this project has never had: the caller pressed once with nobody watching, the app held after 312.9 s, and passes 2 and 3 pressed nothing. B2 put the pin back on a pull failure in 1.0 s. B3 refused `busy` six times. B4 showed there is NO single-flight — 5 of 5 updates ran at once and all ended honest. B5 cut the power in `backing-up` and the box recovered itself and said so. B7 refused under the 2 GB floor. B9 found R-458's risk narrower than the row states. PHASE 4 — every badge on the box is TRUE, and the held app answers all four of Q4's questions. FINDINGS, five new and three corrections to existing rows. The one that matters: R-618 is P1 — two templates name a health probe the app does not answer, and because the guarded update waits on that same probe, a SUCCESSFUL update ends by STOPPING a working app. Measured: tandoor served HTTP 200 on the new version at four samples across five minutes and was then stopped. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
185 lines
49 KiB
JSON
185 lines
49 KiB
JSON
{
|
||
"harness_version": 1,
|
||
"app": "docmost",
|
||
"leg": "engine-major-postgres",
|
||
"venue": "guest 9202 demo-hp-scratch, controller 0.261.0",
|
||
"from": {
|
||
"docmost-postgres": "postgres:16-alpine"
|
||
},
|
||
"to": {
|
||
"docmost-postgres": "postgres:17-alpine"
|
||
},
|
||
"verdict": "failed",
|
||
"seed_read_before": true,
|
||
"seed_read_after": false,
|
||
"healthy_after": true,
|
||
"migration_observed": null,
|
||
"abort": "not-attempted",
|
||
"abort_detail": null,
|
||
"engine_state_before": "=== [1] PG_VERSION — the datadir's own record of its major\n16\nUnable to find image 'alpine:3.20' locally\n3.20: Pulling from library/alpine\n25f1d6b1951a: Already exists\nDigest: sha256:d9e853e87e55526f6b2917df91a2115c36dd7c696a35be12163d44e6e2a4b6bc\nStatus: Downloaded newer image for alpine:3.20\n16\n=== [2] the engine's REFUSAL, verbatim (the whole point of this leg)\n done\nserver started\nCREATE DATABASE\n\n\n/usr/local/bin/docker-entrypoint.sh: ignoring /docker-entrypoint-initdb.d/*\n\nwaiting for server to shut down....2026-09-21 21:42:03.450 CEST [41] LOG: received fast shutdown request\n2026-09-21 21:42:03.453 CEST [41] LOG: aborting any active transactions\n2026-09-21 21:42:03.456 CEST [41] LOG: background worker \"logical replication launcher\" (PID 47) exited with exit code 1\n2026-09-21 21:42:03.457 CEST [42] LOG: shutting down\n2026-09-21 21:42:03.459 CEST [42] LOG: checkpoint starting: shutdown immediate\n2026-09-21 21:42:03.544 CEST [42] LOG: checkpoint complete: wrote 926 buffers (5.7%); 0 WAL file(s) added, 0 removed, 0 recycled; write=0.022 s, sync=0.051 s, total=0.088 s; sync files=301, longest=0.022 s, average=0.001 s; distance=4283 kB, estimate=4283 kB; lsn=0/1925D58, redo lsn=0/1925D58\n2026-09-21 21:42:03.558 CEST [41] LOG: database system is shut down\n done\nserver stopped\n\nPostgreSQL init process complete; ready for start up.\n\n2026-09-21 21:42:03.687 CEST [1] LOG: starting PostgreSQL 16.15 on x86_64-pc-linux-musl, compiled by gcc (Alpine 15.2.0) 15.2.0, 64-bit\n2026-09-21 21:42:03.687 CEST [1] LOG: listening on IPv4 address \"0.0.0.0\", port 5432\n2026-09-21 21:42:03.687 CEST [1] LOG: listening on IPv6 address \"::\", port 5432\n2026-09-21 21:42:03.692 CEST [1] LOG: listening on Unix socket \"/var/run/postgresql/.s.PGSQL.5432\"\n2026-09-21 21:42:03.701 CEST [57] LOG: database system was shut down at 2026-09-21 21:42:03 CEST\n2026-09-21 21:42:03.710 CEST [1] LOG: database system is ready to accept connections\n=== [3] container state\nimage=postgres:16-alpine running=true restarts=0 exit=0\n=== [4] the version binary in the image\npostgres (PostgreSQL) 16.15\n",
|
||
"engine_state_after": "=== [1] PG_VERSION — the datadir's own record of its major\nError response from daemon: No such container: docmost-postgres\ndocker: invalid spec: :/d: empty section between colons\n\nRun 'docker run --help' for more information\n=== [2] the engine's REFUSAL, verbatim (the whole point of this leg)\nError response from daemon: No such container: docmost-postgres\n=== [3] container state\n\nerror: no such object: docmost-postgres\n=== [4] the version binary in the image\nError response from daemon: No such container: docmost-postgres\n(cannot exec — not running)\n",
|
||
"duration_s": 254.5,
|
||
"measured_at": "2026-09-21T19:40:47.708577+00:00",
|
||
"evidence": "apps/docmost-engine-postgres/",
|
||
"notes": [
|
||
"ended HELD or failed — a RESULT, not an error of the run"
|
||
],
|
||
"badge_catchup_seconds": 4.5,
|
||
"phases": [
|
||
{
|
||
"t": 0.0,
|
||
"phase": "safety-dump",
|
||
"label": "Adatbázis pillanatkép…",
|
||
"updating": true,
|
||
"error": null,
|
||
"hold": null
|
||
},
|
||
{
|
||
"t": 1.1,
|
||
"phase": "pulling",
|
||
"label": "Új verzió letöltése…",
|
||
"updating": true,
|
||
"error": null,
|
||
"hold": null
|
||
},
|
||
{
|
||
"t": 2.1,
|
||
"phase": "starting",
|
||
"label": "Indítás az új verzióval…",
|
||
"updating": true,
|
||
"error": null,
|
||
"hold": null
|
||
},
|
||
{
|
||
"t": 5.1,
|
||
"phase": "failed",
|
||
"label": "A frissítés nem sikerült",
|
||
"updating": false,
|
||
"error": "A(z) docmost frissítése 2026-09-21 21:44-kor nem sikerült, és az alkalmazás nem indult el az új verzióval. Az alkalmazás biztonsági okból leállítva marad, hogy az adatai ne sérüljenek. Visszaállítható a Mentések oldalon ebből a biztonsági mentésből: saját meghajtó, 2026-09-21 21:44 — ez a másolat a beállításokat, az adatbázist és az adatköteteket tartalmazza.",
|
||
"hold": "A(z) docmost frissítése 2026-09-21 21:44-kor nem sikerült, és az alkalmazás nem indult el az új verzióval. Az alkalmazás biztonsági okból leállítva marad, hogy az adatai ne sérüljenek. Visszaállítható a Mentések oldalon ebből a biztonsági mentésből: saját meghajtó, 2026-09-21 21:44 — ez a másolat a beállításokat, az adatbázist és az adatköteteket tartalmazza."
|
||
}
|
||
],
|
||
"final_phase": "failed",
|
||
"hold_reason": "A(z) docmost frissítése 2026-09-21 21:44-kor nem sikerült, és az alkalmazás nem indult el az új verzióval. Az alkalmazás biztonsági okból leállítva marad, hogy az adatai ne sérüljenek. Visszaállítható a Mentések oldalon ebből a biztonsági mentésből: saját meghajtó, 2026-09-21 21:44 — ez a másolat a beállításokat, az adatbázist és az adatköteteket tartalmazza.",
|
||
"update_error": "A(z) docmost frissítése 2026-09-21 21:44-kor nem sikerült, és az alkalmazás nem indult el az új verzióval. Az alkalmazás biztonsági okból leállítva marad, hogy az adatai ne sérüljenek. Visszaállítható a Mentések oldalon ebből a biztonsági mentésből: saját meghajtó, 2026-09-21 21:44 — ez a másolat a beállításokat, az adatbázist és az adatköteteket tartalmazza.",
|
||
"hold_sentences": {
|
||
"hu": [
|
||
"Docmost — Felhom.eu document.documentElement.className=document.documentElement.className.replace('no-js','js'); function csrfHeaders(){var el=document.querySelector('meta[name=\"csrf-token\"]');return el?{'X-CSRF-Token':el.content}:{};} function felhomConfirm(el,question,onYes){ if(!el||el.dataset.fcOpen)return; el.dataset.fcOpen='1'; var wrap=document.createElement('span');wrap.className='inline-confirm'; var q=document.createElement('span');q.className='inline-confirm-q';q.textContent=question; var yes=document.createElement('button');yes.type='button';yes.className='btn btn-xs btn-danger';yes.textContent='Igen'; var no=document.createElement('button');no.type='button';no.className='btn btn-xs btn-outline';no.textContent='Mégse'; wrap.appendChild(q);wrap.appendChild(yes);wrap.appendChild(no); el.style.display='none';el.parentNode.insertBefore(wrap,el.nextSibling); function close(){wrap.remove();el.style.display='';delete el.dataset.fcOpen;} no.addEventListener('click',close); yes.addEventListener('click',function(){close();onYes();}); } document.addEventListener('click',function(e){ var btn=e.target.closest?e.target.closest('[data-confirm]'):null; if(!btn)return; e.preventDefault(); felhomConfirm(btn,btn.getAttribute('data-confirm'),function(){ var form=btn.closest('form'); if(form){if(form.requestSubmit)form.requestSubmit(btn);else form.submit();} }); }); document.addEventListener('click',function(e){ var btn=e.target.closest?e.target.closest('.nav-group-toggle'):null; if(!btn)return; var group=btn.closest('.nav-group'); if(!group)return; var willOpen=!group.classList.contains('is-open'); document.querySelectorAll('.nav-group.is-open').forEach(function(g){ g.classList.remove('is-open'); var t=g.querySelector('.nav-group-toggle'); if(t)t.setAttribute('aria-expanded','false'); }); if(willOpen){group.classList.add('is-open');btn.setAttribute('aria-expanded','true');} }); function showAlert(msg){var o=document.createElement('div');o.className='modal-overlay';o.id='alert-modal';o.addEventListener('click',function(e){if(e.target===o)o.remove();});var c=document.createElement('div');c.className='modal-card';c.innerHTML=' Üzenet '+msg.replace(/&/g,'&').replace(/ /g,'>')+' OK ';o.appendChild(c);document.body.appendChild(o);} Indítópult Vezérlőpult Alkalmazások Tárhely Meghajtók Hálózati tárhely Biztonsági mentés Áttekintés Távoli mentés Alkalmazások Visszaállítás Megosztás Hálózati megosztás Rendszermonitor Debug Beállítások Rendszer Értesítések Biztonság és hozzáférés 0.261.0 Magyar English Kijelentkezés ↗ Hub kapcsolat kikapcsolva — a központi monitoring nem aktív Rendszermonitor → ← Alkalmazások Docmost Leállítva Frissítés elérhető — ma Megnyitás ↗ Napló Exportálás Beállítások A(z) docmost frissítése 2026-09-21 21:44-kor nem sikerült, és az alkalmazás nem indult el az új verzióval.",
|
||
"Visszaállítható a Mentések oldalon ebből a biztonsági mentésből: saját meghajtó, 2026-09-21 21:44 — ez a másolat a beállításokat, az adatbázist és az adatköteteket tartalmazza.",
|
||
"Mentések Modern wiki és dokumentáció platform Notion-szerű szerkesztővel ~200M RAM productivity Csak x86 Áthelyezés másik tárhelyre Ennek az alkalmazásnak az adatait másik csatlakoztatott tárhelyre helyezheted át.",
|
||
"Válassz céltárhelyet… SCRATCH HDD (/mnt/felhom-drives/scratch_hdd) Áthelyezés function appMigFmtGB(b){ return (Number(b||0)/1e9).toFixed(1)+' GB'; } function appMigRender(job){ var names={stop:'Leállítás',copy:'Adatok másolása',verify:'Ellenőrzés',flip:'Újratelepítés',redeploy:'Újratelepítés',cleanup:'Régi adatok törlése'}; var s=names[job.phase]||job.phase; if(job.phase==='copy'&&job.bytes_total>0){ s+=' ('+Math.floor(100*job.bytes_done/job.bytes_total)+'% — '+appMigFmtGB(job.bytes_done)+'/'+appMigFmtGB(job.bytes_total)+')'; } return s+'…'; } function appMigWatch(){ var panel=document.getElementById('app-migrate-progress'); if(panel) panel.style.display='block'; function tick(){ fetch('/api/storage/migrate/status').then(function(r){return r.json();}).then(function(d){ var job=d.data&&d.data.job; if(!job){ if(panel) panel.textContent='Nincs folyamatban áthelyezés.'; return; } if(panel) panel.innerHTML=appMigRender(job); if(job.phase==='done'){ if(panel) panel.innerHTML+=' Kész '; setTimeout(function(){location.reload();},1500); return; } if(job.phase==='aborted'){ if(panel) panel.innerHTML+=' Megszakadt: '+(job.error||'')+' A régi adatok érintetlenek.'; return; } setTimeout(tick,1500); }).catch(function(){ setTimeout(tick,2000); }); } tick(); } function appMigrate(btn,app,label){ var sel=document.getElementById('app-migrate-target'); var target=sel?sel.value:''; if(!target){ showAlert('Válassz céltárhelyet.'); return; } felhomConfirm(btn,'Áthelyezed a(z) '+label+' adatait ide: '+target+'?",
|
||
"A régi adatok csak sikeres áthelyezés után törlődnek.',function(){ fetch('/api/storage/migrate-app',{method:'POST',headers:Object.assign({'Content-Type':'application/json'},csrfHeaders()),body:JSON.stringify({app:app,target:target})}) .then(function(r){return r.json();}).then(function(d){ if(d.ok){ appMigWatch(); } else { showAlert('Hiba: '+(d.error||'ismeretlen')); } }) .catch(function(e){ showAlert('Hiba: '+e); }); }); } (function(){ fetch('/api/storage/migrate/status').then(function(r){return r.json();}).then(function(d){ if(d.data&&d.data.job){ appMigWatch(); } }).catch(function(){}); })(); Mire használható?",
|
||
"Csapat tudásbázis és belső dokumentáció Notion-szerű blokk szerkesztő valós idejű együttműködéssel Terek és oldalak hierarchikus szervezése Képek, táblázatok és kód blokkok beágyazása Keresés a teljes dokumentációban Első lépések Nyisd meg a docs.DOMAIN címet a böngészőben Az első regisztrált felhasználó automatikusan admin lesz Hozd létre az első teret (Space) a dokumentumoknak Kezdj el írni a Notion-szerű szerkesztőben Előfeltételek x86 processzor szükséges Legalább 768 MB szabad RAM (Docmost + PostgreSQL + Redis) Dokumentáció Hivatalos dokumentáció ↗ (function(){ var burger=document.querySelector('.nav-burger'); var sidebar=document.getElementById('sidebar'); var backdrop=document.querySelector('.nav-backdrop'); if(!burger||!sidebar||!backdrop)return; function setOpen(open){ sidebar.classList.toggle('is-open',open); document.body.classList.toggle('nav-open',open); backdrop.hidden=!open; burger.setAttribute('aria-expanded',open?'true':'false'); } burger.addEventListener('click',function(){setOpen(!sidebar.classList.contains('is-open'));}); backdrop.addEventListener('click',function(){setOpen(false);}); document.addEventListener('keydown',function(e){ if(e.key==='Escape'&&sidebar.classList.contains('is-open'))setOpen(false); }); })(); document.addEventListener('click', function(e) { if (e.target.closest('a, button, .btn, input, select, textarea, .app-row-actions, .stack-detail-actions')) return; var card = e.target.closest('[data-href]'); if (card) window.location.href = card.dataset.href; }); async function checkBeforeDeploy(e, name) { try { var resp = await fetch('/api/stacks/' + name); var data = await resp.json(); if (data.ok && data.data && data.data.deployed) { e.preventDefault(); showAlert('Ez az alkalmazás már telepítve van.'); window.location.reload(); return false; } } catch(err) {} return true; } async function syncTemplates() { const btn = document.getElementById('sync-btn'); const toast = document.getElementById('sync-toast'); if (!btn) return; const origText = btn.innerHTML; btn.disabled = true; btn.innerHTML = '↻ Frissítés...'; btn.classList.add('loading'); try { const resp = await fetch('/api/sync', { method: 'POST', headers: Object.assign({'Content-Type': 'application/json'}, csrfHeaders()) }); const data = await resp.json(); if (toast) { toast.textContent = data.ok ?",
|
||
"(data.message || 'Sablonok frissítve') : ('Hiba: ' + (data.error || 'Ismeretlen hiba')); toast.className = 'sync-toast ' + (data.ok ?",
|
||
"'sync-toast-ok' : 'sync-toast-err'); toast.style.display = 'block'; setTimeout(function() { toast.style.display = 'none'; }, 5000); } if (data.ok && data.data && (data.data.new_apps && data.data.new_apps.length > 0 || data.data.updated && data.data.updated.length > 0)) { setTimeout(function() { window.location.reload(); }, 1500); } } catch (err) { if (toast) { toast.textContent = 'Hálózati hiba: ' + err.message; toast.className = 'sync-toast sync-toast-err'; toast.style.display = 'block'; setTimeout(function() { toast.style.display = 'none'; }, 5000); } } btn.innerHTML = origText; btn.disabled = false; btn.classList.remove('loading'); } async function stackAction(event, name, action) { const btn = event.currentTarget; const origText = btn.textContent; btn.disabled = true; btn.textContent = 'Folyamatban...'; btn.classList.add('loading'); try { const resp = await fetch('/api/stacks/' + name + '/' + action, { method: 'POST', headers: Object.assign({'Content-Type': 'application/json'}, csrfHeaders()) }); const data = await resp.json(); if (!data.ok) { showAlert('Hiba: ' + (data.error || 'Ismeretlen hiba')); btn.textContent = origText; btn.disabled = false; btn.classList.remove('loading'); return; } if (action === 'update') { followUpdate(name, btn); return; } window.location.reload(); } catch (err) { showAlert('Hálózati hiba: ' + err.message); btn.textContent = origText; btn.disabled = false; btn.classList.remove('loading'); } } function followUpdate(name, btn) { var started = Date.now(); var timer = setInterval(async function() { if (Date.now() - started > 30 * 60 * 1000) { clearInterval(timer); window.location.reload(); return; } try { var r = await fetch('/api/stacks/' + name); var d = await r.json(); if (!d.ok || !d.data) return; if (d.data.update_phase_label) btn.textContent = d.data.update_phase_label; if (!d.data.updating) { clearInterval(timer); window.location.reload(); } } catch (e) {} }, 3000); } async function deleteOrphanStack(name) { var modal = document.createElement('div'); modal.className = 'modal-overlay'; modal.id = 'delete-modal'; modal.innerHTML = ' Betöltés...",
|
||
"'; modal.addEventListener('click', function(e) { if (e.target === modal) closeDeleteModal(); }); document.body.appendChild(modal); try { var resp = await fetch('/api/stacks/' + name + '/hdd-data'); var data = await resp.json(); var hddInfo = ''; var checkboxHTML = ''; if (data.ok && data.data && data.data.has_hdd_data) { hddInfo = ' Felhasználói adatok a merevlemezen: '; data.data.hdd_paths.forEach(function(p) { hddInfo += ' ' + p.path + ' (' + (p.exists ?",
|
||
"' + ' Ez a művelet nem visszavonható!",
|
||
"' + hddInfo + checkboxHTML + ' ' + ' Mégsem ' + ' Törlés ' + ' '; } catch (err) { modal.querySelector('.modal-card').innerHTML = ' Hiba Nem sikerült lekérni az adatokat: ' + err.message + ' ' + ' Bezárás '; } } function closeDeleteModal() { var modal = document.getElementById('delete-modal'); if (modal) modal.remove(); } async function confirmDelete(name) { var btn = document.getElementById('confirm-delete-btn'); var checkbox = document.getElementById('delete-hdd-check'); var removeHDD = checkbox ?",
|
||
"checkbox.checked : false; btn.disabled = true; btn.textContent = 'Törlés folyamatban...'; try { var resp = await fetch('/api/stacks/' + name, { method: 'DELETE', headers: Object.assign({'Content-Type': 'application/json'}, csrfHeaders()), body: JSON.stringify({remove_hdd_data: removeHDD}) }); var data = await resp.json(); if (data.ok) { var modal = document.getElementById('delete-modal'); var removedInfo = ''; if (data.data && data.data.hdd_paths_removed && data.data.hdd_paths_removed.length > 0) { removedInfo = ' Törölt adatok: ' + data.data.hdd_paths_removed.join(', ') + ' '; } var preservedInfo = ''; if (data.data && data.data.hdd_paths_preserved && data.data.hdd_paths_preserved.length > 0) { preservedInfo = ' Megőrzött adatok: ' + data.data.hdd_paths_preserved.join(', ') + ' '; } if (data.data && data.data.hdd_note) { preservedInfo += ' ' + data.data.hdd_note + ' '; } modal.querySelector('.modal-card').innerHTML = ' Sikeresen törölve!",
|
||
"' + removedInfo + preservedInfo + ' Bezárás '; } else { showAlert('Hiba: ' + (data.error || 'Ismeretlen hiba')); btn.disabled = false; btn.textContent = 'Törlés'; } } catch (err) { showAlert('Hálózati hiba: ' + err.message); btn.disabled = false; btn.textContent = 'Törlés'; } } async function removeStack(name) { var modal = document.createElement('div'); modal.className = 'modal-overlay'; modal.id = 'remove-modal'; modal.innerHTML = ' Betöltés...",
|
||
"'; modal.addEventListener('click', function(e) { if (e.target === modal) closeRemoveModal(); }); document.body.appendChild(modal); try { var [hddResp, backupResp] = await Promise.all([ fetch('/api/stacks/' + name + '/hdd-data').then(function(r) { return r.json(); }), fetch('/api/stacks/' + name + '/backup-data').then(function(r) { return r.json(); }) ]); var sections = ''; sections += ' ' + ' Mindig törlődik: ' + ' ' + ' Docker kötetek (adatbázis, alkalmazás konfiguráció) ' + ' Telepítési konfiguráció (app.yaml) ' + ' Másodlagos mentés ütemezése ' + ' '; var hddCheckbox = ''; if (hddResp.ok && hddResp.data && hddResp.data.has_hdd_data) { var hddPaths = ''; hddResp.data.hdd_paths.forEach(function(p) { hddPaths += ' ' + p.path + ' (' + (p.exists ?"
|
||
],
|
||
"en": [
|
||
"Docmost — Felhom.eu document.documentElement.className=document.documentElement.className.replace('no-js','js'); function csrfHeaders(){var el=document.querySelector('meta[name=\"csrf-token\"]');return el?{'X-CSRF-Token':el.content}:{};} function felhomConfirm(el,question,onYes){ if(!el||el.dataset.fcOpen)return; el.dataset.fcOpen='1'; var wrap=document.createElement('span');wrap.className='inline-confirm'; var q=document.createElement('span');q.className='inline-confirm-q';q.textContent=question; var yes=document.createElement('button');yes.type='button';yes.className='btn btn-xs btn-danger';yes.textContent='Yes'; var no=document.createElement('button');no.type='button';no.className='btn btn-xs btn-outline';no.textContent='Cancel'; wrap.appendChild(q);wrap.appendChild(yes);wrap.appendChild(no); el.style.display='none';el.parentNode.insertBefore(wrap,el.nextSibling); function close(){wrap.remove();el.style.display='';delete el.dataset.fcOpen;} no.addEventListener('click',close); yes.addEventListener('click',function(){close();onYes();}); } document.addEventListener('click',function(e){ var btn=e.target.closest?e.target.closest('[data-confirm]'):null; if(!btn)return; e.preventDefault(); felhomConfirm(btn,btn.getAttribute('data-confirm'),function(){ var form=btn.closest('form'); if(form){if(form.requestSubmit)form.requestSubmit(btn);else form.submit();} }); }); document.addEventListener('click',function(e){ var btn=e.target.closest?e.target.closest('.nav-group-toggle'):null; if(!btn)return; var group=btn.closest('.nav-group'); if(!group)return; var willOpen=!group.classList.contains('is-open'); document.querySelectorAll('.nav-group.is-open').forEach(function(g){ g.classList.remove('is-open'); var t=g.querySelector('.nav-group-toggle'); if(t)t.setAttribute('aria-expanded','false'); }); if(willOpen){group.classList.add('is-open');btn.setAttribute('aria-expanded','true');} }); function showAlert(msg){var o=document.createElement('div');o.className='modal-overlay';o.id='alert-modal';o.addEventListener('click',function(e){if(e.target===o)o.remove();});var c=document.createElement('div');c.className='modal-card';c.innerHTML=' Message '+msg.replace(/&/g,'&').replace(/ /g,'>')+' OK ';o.appendChild(c);document.body.appendChild(o);} Launcher Dashboard Apps Storage Drives Network storage Backup Overview Remote backup Apps Restore Sharing Network sharing System monitor Debug Settings System Notifications Security and access 0.261.0 Magyar English Sign out ↗ The hub connection is off — central monitoring is not running System monitor → ← Apps Docmost Stopped Update available — today Open ↗ Log Export Settings A(z) docmost frissítése 2026-09-21 21:44-kor nem sikerült, és az alkalmazás nem indult el az új verzióval.",
|
||
"Visszaállítható a Mentések oldalon ebből a biztonsági mentésből: saját meghajtó, 2026-09-21 21:44 — ez a másolat a beállításokat, az adatbázist és az adatköteteket tartalmazza.",
|
||
"Backups A modern wiki and documentation platform with a Notion-like editor ~200M RAM productivity x86 only Move to another storage You can move this app’s data to another connected storage.",
|
||
"Choose a target storage… SCRATCH HDD (/mnt/felhom-drives/scratch_hdd) Move function appMigFmtGB(b){ return (Number(b||0)/1e9).toFixed(1)+' GB'; } function appMigRender(job){ var names={stop:'Stopping',copy:'Copying data',verify:'Checking',flip:'Reinstalling',redeploy:'Reinstalling',cleanup:'Deleting old data'}; var s=names[job.phase]||job.phase; if(job.phase==='copy'&&job.bytes_total>0){ s+=' ('+Math.floor(100*job.bytes_done/job.bytes_total)+'% — '+appMigFmtGB(job.bytes_done)+'/'+appMigFmtGB(job.bytes_total)+')'; } return s+'…'; } function appMigWatch(){ var panel=document.getElementById('app-migrate-progress'); if(panel) panel.style.display='block'; function tick(){ fetch('/api/storage/migrate/status').then(function(r){return r.json();}).then(function(d){ var job=d.data&&d.data.job; if(!job){ if(panel) panel.textContent='No move in progress.'; return; } if(panel) panel.innerHTML=appMigRender(job); if(job.phase==='done'){ if(panel) panel.innerHTML+=' Done '; setTimeout(function(){location.reload();},1500); return; } if(job.phase==='aborted'){ if(panel) panel.innerHTML+=' Stopped: '+(job.error||'')+' The old data is untouched.'; return; } setTimeout(tick,1500); }).catch(function(){ setTimeout(tick,2000); }); } tick(); } function appMigrate(btn,app,label){ var sel=document.getElementById('app-migrate-target'); var target=sel?sel.value:''; if(!target){ showAlert('Choose a target storage.'); return; } felhomConfirm(btn,'Move the '+label+' data to: '+target+'?",
|
||
"The old data is deleted only after a successful move.',function(){ fetch('/api/storage/migrate-app',{method:'POST',headers:Object.assign({'Content-Type':'application/json'},csrfHeaders()),body:JSON.stringify({app:app,target:target})}) .then(function(r){return r.json();}).then(function(d){ if(d.ok){ appMigWatch(); } else { showAlert('Error: '+(d.error||'unknown')); } }) .catch(function(e){ showAlert('Error: '+e); }); }); } (function(){ fetch('/api/storage/migrate/status').then(function(r){return r.json();}).then(function(d){ if(d.data&&d.data.job){ appMigWatch(); } }).catch(function(){}); })(); What is it for?",
|
||
"A knowledge base and internal documentation for a team A Notion-like block editor several people can use at once Spaces and pages, arranged in a tree Embed images, tables and code blocks Search across all of it First steps Open docs.DOMAIN in your browser The first person to sign up becomes the admin Create your first Space for the documents Start writing in the Notion-like editor Before you start An x86 processor is needed At least 768 MB of free RAM (Docmost + PostgreSQL + Redis) Documentation Official documentation ↗ (function(){ var burger=document.querySelector('.nav-burger'); var sidebar=document.getElementById('sidebar'); var backdrop=document.querySelector('.nav-backdrop'); if(!burger||!sidebar||!backdrop)return; function setOpen(open){ sidebar.classList.toggle('is-open',open); document.body.classList.toggle('nav-open',open); backdrop.hidden=!open; burger.setAttribute('aria-expanded',open?'true':'false'); } burger.addEventListener('click',function(){setOpen(!sidebar.classList.contains('is-open'));}); backdrop.addEventListener('click',function(){setOpen(false);}); document.addEventListener('keydown',function(e){ if(e.key==='Escape'&&sidebar.classList.contains('is-open'))setOpen(false); }); })(); document.addEventListener('click', function(e) { if (e.target.closest('a, button, .btn, input, select, textarea, .app-row-actions, .stack-detail-actions')) return; var card = e.target.closest('[data-href]'); if (card) window.location.href = card.dataset.href; }); async function checkBeforeDeploy(e, name) { try { var resp = await fetch('/api/stacks/' + name); var data = await resp.json(); if (data.ok && data.data && data.data.deployed) { e.preventDefault(); showAlert('This app is already installed.'); window.location.reload(); return false; } } catch(err) {} return true; } async function syncTemplates() { const btn = document.getElementById('sync-btn'); const toast = document.getElementById('sync-toast'); if (!btn) return; const origText = btn.innerHTML; btn.disabled = true; btn.innerHTML = '↻ Refreshing...'; btn.classList.add('loading'); try { const resp = await fetch('/api/sync', { method: 'POST', headers: Object.assign({'Content-Type': 'application/json'}, csrfHeaders()) }); const data = await resp.json(); if (toast) { toast.textContent = data.ok ?",
|
||
"(data.message || 'Templates refreshed') : ('Error: ' + (data.error || 'Unknown error')); toast.className = 'sync-toast ' + (data.ok ?",
|
||
"'sync-toast-ok' : 'sync-toast-err'); toast.style.display = 'block'; setTimeout(function() { toast.style.display = 'none'; }, 5000); } if (data.ok && data.data && (data.data.new_apps && data.data.new_apps.length > 0 || data.data.updated && data.data.updated.length > 0)) { setTimeout(function() { window.location.reload(); }, 1500); } } catch (err) { if (toast) { toast.textContent = 'Network error: ' + err.message; toast.className = 'sync-toast sync-toast-err'; toast.style.display = 'block'; setTimeout(function() { toast.style.display = 'none'; }, 5000); } } btn.innerHTML = origText; btn.disabled = false; btn.classList.remove('loading'); } async function stackAction(event, name, action) { const btn = event.currentTarget; const origText = btn.textContent; btn.disabled = true; btn.textContent = 'In progress...'; btn.classList.add('loading'); try { const resp = await fetch('/api/stacks/' + name + '/' + action, { method: 'POST', headers: Object.assign({'Content-Type': 'application/json'}, csrfHeaders()) }); const data = await resp.json(); if (!data.ok) { showAlert('Error: ' + (data.error || 'Unknown error')); btn.textContent = origText; btn.disabled = false; btn.classList.remove('loading'); return; } if (action === 'update') { followUpdate(name, btn); return; } window.location.reload(); } catch (err) { showAlert('Network error: ' + err.message); btn.textContent = origText; btn.disabled = false; btn.classList.remove('loading'); } } function followUpdate(name, btn) { var started = Date.now(); var timer = setInterval(async function() { if (Date.now() - started > 30 * 60 * 1000) { clearInterval(timer); window.location.reload(); return; } try { var r = await fetch('/api/stacks/' + name); var d = await r.json(); if (!d.ok || !d.data) return; if (d.data.update_phase_label) btn.textContent = d.data.update_phase_label; if (!d.data.updating) { clearInterval(timer); window.location.reload(); } } catch (e) {} }, 3000); } async function deleteOrphanStack(name) { var modal = document.createElement('div'); modal.className = 'modal-overlay'; modal.id = 'delete-modal'; modal.innerHTML = ' Loading...",
|
||
"'; modal.addEventListener('click', function(e) { if (e.target === modal) closeDeleteModal(); }); document.body.appendChild(modal); try { var resp = await fetch('/api/stacks/' + name + '/hdd-data'); var data = await resp.json(); var hddInfo = ''; var checkboxHTML = ''; if (data.ok && data.data && data.data.has_hdd_data) { hddInfo = ' Your data on the hard drive: '; data.data.hdd_paths.forEach(function(p) { hddInfo += ' ' + p.path + ' (' + (p.exists ?",
|
||
"' + hddInfo + checkboxHTML + ' ' + ' Cancel ' + ' Delete ' + ' '; } catch (err) { modal.querySelector('.modal-card').innerHTML = ' Error Could not load the details: ' + err.message + ' ' + ' Close '; } } function closeDeleteModal() { var modal = document.getElementById('delete-modal'); if (modal) modal.remove(); } async function confirmDelete(name) { var btn = document.getElementById('confirm-delete-btn'); var checkbox = document.getElementById('delete-hdd-check'); var removeHDD = checkbox ?",
|
||
"checkbox.checked : false; btn.disabled = true; btn.textContent = 'Deleting...'; try { var resp = await fetch('/api/stacks/' + name, { method: 'DELETE', headers: Object.assign({'Content-Type': 'application/json'}, csrfHeaders()), body: JSON.stringify({remove_hdd_data: removeHDD}) }); var data = await resp.json(); if (data.ok) { var modal = document.getElementById('delete-modal'); var removedInfo = ''; if (data.data && data.data.hdd_paths_removed && data.data.hdd_paths_removed.length > 0) { removedInfo = ' Deleted data: ' + data.data.hdd_paths_removed.join(', ') + ' '; } var preservedInfo = ''; if (data.data && data.data.hdd_paths_preserved && data.data.hdd_paths_preserved.length > 0) { preservedInfo = ' Kept data: ' + data.data.hdd_paths_preserved.join(', ') + ' '; } if (data.data && data.data.hdd_note) { preservedInfo += ' ' + data.data.hdd_note + ' '; } modal.querySelector('.modal-card').innerHTML = ' Deleted!",
|
||
"' + removedInfo + preservedInfo + ' Close '; } else { showAlert('Error: ' + (data.error || 'Unknown error')); btn.disabled = false; btn.textContent = 'Delete'; } } catch (err) { showAlert('Network error: ' + err.message); btn.disabled = false; btn.textContent = 'Delete'; } } async function removeStack(name) { var modal = document.createElement('div'); modal.className = 'modal-overlay'; modal.id = 'remove-modal'; modal.innerHTML = ' Loading...",
|
||
"'; modal.addEventListener('click', function(e) { if (e.target === modal) closeRemoveModal(); }); document.body.appendChild(modal); try { var [hddResp, backupResp] = await Promise.all([ fetch('/api/stacks/' + name + '/hdd-data').then(function(r) { return r.json(); }), fetch('/api/stacks/' + name + '/backup-data').then(function(r) { return r.json(); }) ]); var sections = ''; sections += ' ' + ' Always deleted: ' + ' ' + ' Docker volumes (database, app configuration) ' + ' Install configuration (app.yaml) ' + ' Secondary backup schedule ' + ' '; var hddCheckbox = ''; if (hddResp.ok && hddResp.data && hddResp.data.has_hdd_data) { var hddPaths = ''; hddResp.data.hdd_paths.forEach(function(p) { hddPaths += ' ' + p.path + ' (' + (p.exists ?",
|
||
"Data you keep is NOT backed up automatically any more.' + ' '; hddCheckbox = '\\x3Cscript>document.getElementById(\"remove-hdd-check\").addEventListener(\"change\",function(){document.getElementById(\"remove-hdd-keep-warning\").style.display=this.checked?\"none\":\"\";}); '; } var backupCheckbox = ''; if (backupResp.ok && backupResp.data && backupResp.data.has_backups) { var bkPaths = ''; backupResp.data.backup_paths.forEach(function(p) { if (p.exists) bkPaths += ' ' + p.path + ' (' + p.size_human + ') '; }); if (bkPaths) { sections += ' ' + ' Backup data: ' + bkPaths + ' Delete backup data ' + ' ' + 'The nightly restic snapshots cannot be deleted one by one — they expire automatically under the retention rules.' + ' '; } } modal.querySelector('.modal-card').innerHTML = ' Remove app: ' + name + ' ' + ' The app goes back to \"Not installed\"."
|
||
]
|
||
},
|
||
"observables_after": {
|
||
"pinned_images": {
|
||
"docmost": "docmost/docmost:0.96.0",
|
||
"docmost-postgres": "postgres:17-alpine",
|
||
"docmost-redis": "redis:7-alpine"
|
||
},
|
||
"installed_images": {
|
||
"docmost": "docmost/docmost:0.96.0",
|
||
"docmost-postgres": "postgres:16-alpine",
|
||
"docmost-redis": "redis:7-alpine"
|
||
},
|
||
"catalog_images": {
|
||
"docmost": "docmost/docmost:0.96.0",
|
||
"docmost-postgres": "postgres:17-alpine",
|
||
"docmost-redis": "redis:7-alpine"
|
||
},
|
||
"live_compose_image_lines": [
|
||
"image: docmost/docmost:0.96.0",
|
||
"image: postgres:17-alpine",
|
||
"image: redis:7-alpine"
|
||
],
|
||
"docker_inspect": []
|
||
},
|
||
"way_out": {
|
||
"ok": true,
|
||
"snapshot_id": "helyi",
|
||
"snapshots": [
|
||
{
|
||
"time": "2026-09-21T19:44:15Z",
|
||
"short_id": "helyi",
|
||
"tier": 1,
|
||
"drive_label": "Belső SSD (rendszer)"
|
||
}
|
||
],
|
||
"http": "HTTP/2 302",
|
||
"location": [
|
||
"location: /backups/restore?flash=flash.restore.started"
|
||
],
|
||
"seconds": 30.4,
|
||
"state_after": "running",
|
||
"hold_after": null,
|
||
"observables_after": {
|
||
"pinned_images": {
|
||
"docmost": "docmost/docmost:0.96.0",
|
||
"docmost-postgres": "postgres:16-alpine",
|
||
"docmost-redis": "redis:7-alpine"
|
||
},
|
||
"installed_images": {
|
||
"docmost": "docmost/docmost:0.96.0",
|
||
"docmost-postgres": "postgres:16-alpine",
|
||
"docmost-redis": "redis:7-alpine"
|
||
},
|
||
"catalog_images": {
|
||
"docmost": "docmost/docmost:0.96.0",
|
||
"docmost-postgres": "postgres:17-alpine",
|
||
"docmost-redis": "redis:7-alpine"
|
||
},
|
||
"live_compose_image_lines": [
|
||
"image: docmost/docmost:0.96.0",
|
||
"image: postgres:16-alpine",
|
||
"image: redis:7-alpine"
|
||
],
|
||
"docker_inspect": [
|
||
"docmost docmost/docmost:0.96.0 running=true restarts=0",
|
||
"docmost-redis redis:7-alpine running=true restarts=0",
|
||
"docmost-postgres postgres:16-alpine running=true restarts=0"
|
||
]
|
||
}
|
||
},
|
||
"seed_read_after_restore": true,
|
||
"engine_state_after_restore": "=== [1] PG_VERSION — the datadir's own record of its major\n16\n16\n=== [2] the engine's REFUSAL, verbatim (the whole point of this leg)\n\nPostgreSQL Database directory appears to contain a database; Skipping initialization\n\n2026-09-21 21:44:28.155 CEST [1] LOG: starting PostgreSQL 16.15 on x86_64-pc-linux-musl, compiled by gcc (Alpine 15.2.0) 15.2.0, 64-bit\n2026-09-21 21:44:28.155 CEST [1] LOG: listening on IPv4 address \"0.0.0.0\", port 5432\n2026-09-21 21:44:28.155 CEST [1] LOG: listening on IPv6 address \"::\", port 5432\n2026-09-21 21:44:28.161 CEST [1] LOG: listening on Unix socket \"/var/run/postgresql/.s.PGSQL.5432\"\n2026-09-21 21:44:28.169 CEST [29] LOG: database system was shut down at 2026-09-21 21:42:44 CEST\n2026-09-21 21:44:28.183 CEST [1] LOG: database system is ready to accept connections\n=== [3] container state\nimage=postgres:16-alpine running=true restarts=0 exit=0\n=== [4] the version binary in the image\npostgres (PostgreSQL) 16.15\n",
|
||
"hold_sentences_after_restore": {
|
||
"hu": [
|
||
"Docmost — Felhom.eu document.documentElement.className=document.documentElement.className.replace('no-js','js'); function csrfHeaders(){var el=document.querySelector('meta[name=\"csrf-token\"]');return el?{'X-CSRF-Token':el.content}:{};} function felhomConfirm(el,question,onYes){ if(!el||el.dataset.fcOpen)return; el.dataset.fcOpen='1'; var wrap=document.createElement('span');wrap.className='inline-confirm'; var q=document.createElement('span');q.className='inline-confirm-q';q.textContent=question; var yes=document.createElement('button');yes.type='button';yes.className='btn btn-xs btn-danger';yes.textContent='Igen'; var no=document.createElement('button');no.type='button';no.className='btn btn-xs btn-outline';no.textContent='Mégse'; wrap.appendChild(q);wrap.appendChild(yes);wrap.appendChild(no); el.style.display='none';el.parentNode.insertBefore(wrap,el.nextSibling); function close(){wrap.remove();el.style.display='';delete el.dataset.fcOpen;} no.addEventListener('click',close); yes.addEventListener('click',function(){close();onYes();}); } document.addEventListener('click',function(e){ var btn=e.target.closest?e.target.closest('[data-confirm]'):null; if(!btn)return; e.preventDefault(); felhomConfirm(btn,btn.getAttribute('data-confirm'),function(){ var form=btn.closest('form'); if(form){if(form.requestSubmit)form.requestSubmit(btn);else form.submit();} }); }); document.addEventListener('click',function(e){ var btn=e.target.closest?e.target.closest('.nav-group-toggle'):null; if(!btn)return; var group=btn.closest('.nav-group'); if(!group)return; var willOpen=!group.classList.contains('is-open'); document.querySelectorAll('.nav-group.is-open').forEach(function(g){ g.classList.remove('is-open'); var t=g.querySelector('.nav-group-toggle'); if(t)t.setAttribute('aria-expanded','false'); }); if(willOpen){group.classList.add('is-open');btn.setAttribute('aria-expanded','true');} }); function showAlert(msg){var o=document.createElement('div');o.className='modal-overlay';o.id='alert-modal';o.addEventListener('click',function(e){if(e.target===o)o.remove();});var c=document.createElement('div');c.className='modal-card';c.innerHTML=' Üzenet '+msg.replace(/&/g,'&').replace(/ /g,'>')+' OK ';o.appendChild(c);document.body.appendChild(o);} Indítópult Vezérlőpult Alkalmazások Tárhely Meghajtók Hálózati tárhely Biztonsági mentés Áttekintés Távoli mentés Alkalmazások Visszaállítás Megosztás Hálózati megosztás Rendszermonitor Debug Beállítások Rendszer Értesítések Biztonság és hozzáférés 0.261.0 Magyar English Kijelentkezés ↗ Hub kapcsolat kikapcsolva — a központi monitoring nem aktív Rendszermonitor → ← Alkalmazások Docmost Fut Frissítés elérhető — ma Megnyitás ↗ Napló Exportálás Beállítások Modern wiki és dokumentáció platform Notion-szerű szerkesztővel ~200M RAM productivity Csak x86 Áthelyezés másik tárhelyre Ennek az alkalmazásnak az adatait másik csatlakoztatott tárhelyre helyezheted át.",
|
||
"Csapat tudásbázis és belső dokumentáció Notion-szerű blokk szerkesztő valós idejű együttműködéssel Terek és oldalak hierarchikus szervezése Képek, táblázatok és kód blokkok beágyazása Keresés a teljes dokumentációban Első lépések Nyisd meg a docs.DOMAIN címet a böngészőben Az első regisztrált felhasználó automatikusan admin lesz Hozd létre az első teret (Space) a dokumentumoknak Kezdj el írni a Notion-szerű szerkesztőben Előfeltételek x86 processzor szükséges Legalább 768 MB szabad RAM (Docmost + PostgreSQL + Redis) Dokumentáció Hivatalos dokumentáció ↗ (function(){ var burger=document.querySelector('.nav-burger'); var sidebar=document.getElementById('sidebar'); var backdrop=document.querySelector('.nav-backdrop'); if(!burger||!sidebar||!backdrop)return; function setOpen(open){ sidebar.classList.toggle('is-open',open); document.body.classList.toggle('nav-open',open); backdrop.hidden=!open; burger.setAttribute('aria-expanded',open?'true':'false'); } burger.addEventListener('click',function(){setOpen(!sidebar.classList.contains('is-open'));}); backdrop.addEventListener('click',function(){setOpen(false);}); document.addEventListener('keydown',function(e){ if(e.key==='Escape'&&sidebar.classList.contains('is-open'))setOpen(false); }); })(); document.addEventListener('click', function(e) { if (e.target.closest('a, button, .btn, input, select, textarea, .app-row-actions, .stack-detail-actions')) return; var card = e.target.closest('[data-href]'); if (card) window.location.href = card.dataset.href; }); async function checkBeforeDeploy(e, name) { try { var resp = await fetch('/api/stacks/' + name); var data = await resp.json(); if (data.ok && data.data && data.data.deployed) { e.preventDefault(); showAlert('Ez az alkalmazás már telepítve van.'); window.location.reload(); return false; } } catch(err) {} return true; } async function syncTemplates() { const btn = document.getElementById('sync-btn'); const toast = document.getElementById('sync-toast'); if (!btn) return; const origText = btn.innerHTML; btn.disabled = true; btn.innerHTML = '↻ Frissítés...'; btn.classList.add('loading'); try { const resp = await fetch('/api/sync', { method: 'POST', headers: Object.assign({'Content-Type': 'application/json'}, csrfHeaders()) }); const data = await resp.json(); if (toast) { toast.textContent = data.ok ?",
|
||
"(data.message || 'Sablonok frissítve') : ('Hiba: ' + (data.error || 'Ismeretlen hiba')); toast.className = 'sync-toast ' + (data.ok ?",
|
||
"'sync-toast-ok' : 'sync-toast-err'); toast.style.display = 'block'; setTimeout(function() { toast.style.display = 'none'; }, 5000); } if (data.ok && data.data && (data.data.new_apps && data.data.new_apps.length > 0 || data.data.updated && data.data.updated.length > 0)) { setTimeout(function() { window.location.reload(); }, 1500); } } catch (err) { if (toast) { toast.textContent = 'Hálózati hiba: ' + err.message; toast.className = 'sync-toast sync-toast-err'; toast.style.display = 'block'; setTimeout(function() { toast.style.display = 'none'; }, 5000); } } btn.innerHTML = origText; btn.disabled = false; btn.classList.remove('loading'); } async function stackAction(event, name, action) { const btn = event.currentTarget; const origText = btn.textContent; btn.disabled = true; btn.textContent = 'Folyamatban...'; btn.classList.add('loading'); try { const resp = await fetch('/api/stacks/' + name + '/' + action, { method: 'POST', headers: Object.assign({'Content-Type': 'application/json'}, csrfHeaders()) }); const data = await resp.json(); if (!data.ok) { showAlert('Hiba: ' + (data.error || 'Ismeretlen hiba')); btn.textContent = origText; btn.disabled = false; btn.classList.remove('loading'); return; } if (action === 'update') { followUpdate(name, btn); return; } window.location.reload(); } catch (err) { showAlert('Hálózati hiba: ' + err.message); btn.textContent = origText; btn.disabled = false; btn.classList.remove('loading'); } } function followUpdate(name, btn) { var started = Date.now(); var timer = setInterval(async function() { if (Date.now() - started > 30 * 60 * 1000) { clearInterval(timer); window.location.reload(); return; } try { var r = await fetch('/api/stacks/' + name); var d = await r.json(); if (!d.ok || !d.data) return; if (d.data.update_phase_label) btn.textContent = d.data.update_phase_label; if (!d.data.updating) { clearInterval(timer); window.location.reload(); } } catch (e) {} }, 3000); } async function deleteOrphanStack(name) { var modal = document.createElement('div'); modal.className = 'modal-overlay'; modal.id = 'delete-modal'; modal.innerHTML = ' Betöltés...",
|
||
"' + ' Ez a művelet nem visszavonható!",
|
||
"A megtartott adatok a továbbiakban NEM lesznek automatikusan mentve.' + ' '; hddCheckbox = '\\x3Cscript>document.getElementById(\"remove-hdd-check\").addEventListener(\"change\",function(){document.getElementById(\"remove-hdd-keep-warning\").style.display=this.checked?\"none\":\"\";}); '; } var backupCheckbox = ''; if (backupResp.ok && backupResp.data && backupResp.data.has_backups) { var bkPaths = ''; backupResp.data.backup_paths.forEach(function(p) { if (p.exists) bkPaths += ' ' + p.path + ' (' + p.size_human + ') '; }); if (bkPaths) { sections += ' ' + ' Mentési adatok: ' + bkPaths + ' Mentési adatok törlése ' + ' ' + 'Az éjszakai restic pillanatképek nem törölhetők egyenként — a megőrzési szabályok szerint automatikusan elavulnak.' + ' '; } } modal.querySelector('.modal-card').innerHTML = ' Alkalmazás eltávolítása: ' + name + ' ' + ' Az alkalmazás visszaáll \"Nincs telepítve\" állapotba.",
|
||
"' + ' Ez a művelet nem visszavonható!"
|
||
],
|
||
"en": [
|
||
"Docmost — Felhom.eu document.documentElement.className=document.documentElement.className.replace('no-js','js'); function csrfHeaders(){var el=document.querySelector('meta[name=\"csrf-token\"]');return el?{'X-CSRF-Token':el.content}:{};} function felhomConfirm(el,question,onYes){ if(!el||el.dataset.fcOpen)return; el.dataset.fcOpen='1'; var wrap=document.createElement('span');wrap.className='inline-confirm'; var q=document.createElement('span');q.className='inline-confirm-q';q.textContent=question; var yes=document.createElement('button');yes.type='button';yes.className='btn btn-xs btn-danger';yes.textContent='Yes'; var no=document.createElement('button');no.type='button';no.className='btn btn-xs btn-outline';no.textContent='Cancel'; wrap.appendChild(q);wrap.appendChild(yes);wrap.appendChild(no); el.style.display='none';el.parentNode.insertBefore(wrap,el.nextSibling); function close(){wrap.remove();el.style.display='';delete el.dataset.fcOpen;} no.addEventListener('click',close); yes.addEventListener('click',function(){close();onYes();}); } document.addEventListener('click',function(e){ var btn=e.target.closest?e.target.closest('[data-confirm]'):null; if(!btn)return; e.preventDefault(); felhomConfirm(btn,btn.getAttribute('data-confirm'),function(){ var form=btn.closest('form'); if(form){if(form.requestSubmit)form.requestSubmit(btn);else form.submit();} }); }); document.addEventListener('click',function(e){ var btn=e.target.closest?e.target.closest('.nav-group-toggle'):null; if(!btn)return; var group=btn.closest('.nav-group'); if(!group)return; var willOpen=!group.classList.contains('is-open'); document.querySelectorAll('.nav-group.is-open').forEach(function(g){ g.classList.remove('is-open'); var t=g.querySelector('.nav-group-toggle'); if(t)t.setAttribute('aria-expanded','false'); }); if(willOpen){group.classList.add('is-open');btn.setAttribute('aria-expanded','true');} }); function showAlert(msg){var o=document.createElement('div');o.className='modal-overlay';o.id='alert-modal';o.addEventListener('click',function(e){if(e.target===o)o.remove();});var c=document.createElement('div');c.className='modal-card';c.innerHTML=' Message '+msg.replace(/&/g,'&').replace(/ /g,'>')+' OK ';o.appendChild(c);document.body.appendChild(o);} Launcher Dashboard Apps Storage Drives Network storage Backup Overview Remote backup Apps Restore Sharing Network sharing System monitor Debug Settings System Notifications Security and access 0.261.0 Magyar English Sign out ↗ The hub connection is off — central monitoring is not running System monitor → ← Apps Docmost Running Update available — today Open ↗ Log Export Settings A modern wiki and documentation platform with a Notion-like editor ~200M RAM productivity x86 only Move to another storage You can move this app’s data to another connected storage.",
|
||
"'sync-toast-ok' : 'sync-toast-err'); toast.style.display = 'block'; setTimeout(function() { toast.style.display = 'none'; }, 5000); } if (data.ok && data.data && (data.data.new_apps && data.data.new_apps.length > 0 || data.data.updated && data.data.updated.length > 0)) { setTimeout(function() { window.location.reload(); }, 1500); } } catch (err) { if (toast) { toast.textContent = 'Network error: ' + err.message; toast.className = 'sync-toast sync-toast-err'; toast.style.display = 'block'; setTimeout(function() { toast.style.display = 'none'; }, 5000); } } btn.innerHTML = origText; btn.disabled = false; btn.classList.remove('loading'); } async function stackAction(event, name, action) { const btn = event.currentTarget; const origText = btn.textContent; btn.disabled = true; btn.textContent = 'In progress...'; btn.classList.add('loading'); try { const resp = await fetch('/api/stacks/' + name + '/' + action, { method: 'POST', headers: Object.assign({'Content-Type': 'application/json'}, csrfHeaders()) }); const data = await resp.json(); if (!data.ok) { showAlert('Error: ' + (data.error || 'Unknown error')); btn.textContent = origText; btn.disabled = false; btn.classList.remove('loading'); return; } if (action === 'update') { followUpdate(name, btn); return; } window.location.reload(); } catch (err) { showAlert('Network error: ' + err.message); btn.textContent = origText; btn.disabled = false; btn.classList.remove('loading'); } } function followUpdate(name, btn) { var started = Date.now(); var timer = setInterval(async function() { if (Date.now() - started > 30 * 60 * 1000) { clearInterval(timer); window.location.reload(); return; } try { var r = await fetch('/api/stacks/' + name); var d = await r.json(); if (!d.ok || !d.data) return; if (d.data.update_phase_label) btn.textContent = d.data.update_phase_label; if (!d.data.updating) { clearInterval(timer); window.location.reload(); } } catch (e) {} }, 3000); } async function deleteOrphanStack(name) { var modal = document.createElement('div'); modal.className = 'modal-overlay'; modal.id = 'delete-modal'; modal.innerHTML = ' Loading..."
|
||
]
|
||
}
|
||
} |