LAN access: bind 0.0.0.0 + expose LAN URL (capabilities.lan, UI badge)

This commit is contained in:
2026-08-10 20:46:06 +07:00
parent a0d8725541
commit d31e226f00
5 changed files with 112 additions and 6 deletions
+30
View File
@@ -15171,6 +15171,36 @@ const App = () => {
})
})));
}, [bpm]);
// LAN access badge (standalone): server bind 0.0.0.0 client browser máy
// khác trên mng m app qua http://<LAN-IP>:port. Hin URL trên máy ch;
// client LAN thy origin đang dùng.
useEffect(() => {
let mounted = true;
let bar = null;
let iv = null;
const tryShow = () => {
const caps = window.SonicRuntime && window.SonicRuntime.capabilities;
const lan = caps && caps.lan;
if (!lan || !lan.urls || !lan.urls.length) return false;
if (document.getElementById('sf-lan-bar')) return true;
const hostname = window.location.hostname;
const isLocal = hostname === 'localhost' || hostname === '127.0.0.1' || hostname === '::1';
bar = document.createElement('div');
bar.id = 'sf-lan-bar';
bar.style.cssText = 'position:fixed;top:8px;right:12px;z-index:9999;background:rgba(16,185,129,0.12);border:1px solid #10b981;color:#a7f3d0;font-size:11px;line-height:1.5;padding:6px 10px;border-radius:8px;max-width:min(70vw,420px);cursor:default;';
bar.title = 'Client browser ở máy khác trên LAN mở địa chỉ này để làm việc realtime với máy chạy SonicForge';
bar.innerHTML = isLocal
? '<b>LAN:</b> ' + lan.urls.map(function (u) { return '<a href="' + u + '" target="_blank" style="color:#a7f3d0;text-decoration:underline">' + u + '</a>'; }).join(' &nbsp;·&nbsp; ')
: '<b>Kết nối:</b> ' + window.location.origin;
document.body.appendChild(bar);
return true;
};
if (!tryShow()) {
iv = setInterval(function () { if (mounted && tryShow()) clearInterval(iv); }, 700);
setTimeout(function () { if (iv) clearInterval(iv); }, 20000);
}
return () => { mounted = false; if (iv) clearInterval(iv); if (bar && bar.parentNode) bar.parentNode.removeChild(bar); };
}, []);
const openPanel = id => {
if (id === 'export') setShowExportPanel(true); else if (id === 'ai') setShowAIPanel(true); else if (id === 'python_tools') setShowPythonToolsPanel(true); else if (id === 'selection') setShowSelectionPanel(true);
};