@@ -1596,6 +1596,10 @@
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p class="modal-desc">Expose a local port as an hs:// tunnel. The generated URL can be shared with others.</p>
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="startServerLabel">Label <span style="color:var(--text4);font-weight:400;">(optional)</span></label>
|
||||
<input type="text" id="startServerLabel" class="input" placeholder="e.g. My Web App" autocomplete="off">
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="form-group" style="max-width:120px;">
|
||||
<label class="form-label" for="startServerPort">Port</label>
|
||||
|
||||
+44
-10
@@ -1333,10 +1333,11 @@ function initOvLists() {
|
||||
searchId: 'ovServersSearch', subtitleId: 'ovServersSubtitle',
|
||||
cols: 3, emptyMsg: 'No server tunnels',
|
||||
rowFn: s => {
|
||||
const key = s.hsUrl || '';
|
||||
const key = s.url || s.hsUrl || '';
|
||||
const short = key.length > 22 ? key.slice(0, 9) + '…' + key.slice(-7) : key;
|
||||
const display = s.label ? escapeHtml(s.label) : `<span class="mono" style="font-size:11px;color:var(--text3);">${escapeHtml(String(s.port || '—'))}</span>`;
|
||||
return `<tr>
|
||||
<td class="mono" style="font-size:12px;">${escapeHtml(String(s.port || '—'))}</td>
|
||||
<td style="font-size:12px;">${display}</td>
|
||||
<td>${stateTag(s.state)}</td>
|
||||
<td class="mono" style="font-size:11px;color:var(--text3);"
|
||||
title="${escapeHtml(key)}">${escapeHtml(short)}</td>
|
||||
@@ -1378,7 +1379,25 @@ function initOvLists() {
|
||||
|
||||
// Quick action buttons → open existing modals directly
|
||||
$('qaAddVhost') ?.addEventListener('click', () => openModal('modal-addVhost'));
|
||||
$('qaAddServer') ?.addEventListener('click', () => openModal('modal-startServer'));
|
||||
$('qaAddServer')?.addEventListener('click', () => {
|
||||
const editIdEl = $('serverEditId');
|
||||
if (editIdEl) editIdEl.value = '';
|
||||
const labelEl = $('startServerLabel');
|
||||
if (labelEl) labelEl.value = '';
|
||||
const portEl = $('startServerPort');
|
||||
if (portEl) portEl.value = '3000';
|
||||
const hostEl = $('startServerHost');
|
||||
if (hostEl) hostEl.value = '127.0.0.1';
|
||||
const secureEl = $('startServerSecure');
|
||||
if (secureEl) secureEl.checked = true;
|
||||
const tcpEl = $('startServerProtocolTcp');
|
||||
if (tcpEl) tcpEl.checked = true;
|
||||
const titleEl = $('modal-startServer-title');
|
||||
if (titleEl) titleEl.textContent = 'Start Server Tunnel';
|
||||
const submitEl = $('startServerSubmit');
|
||||
if (submitEl) submitEl.textContent = 'Start Server';
|
||||
openModal('modal-startServer');
|
||||
});
|
||||
$('qaAddSvc') ?.addEventListener('click', () => openModal('modal-addServiceTunnel'));
|
||||
$('qaAddSsh') ?.addEventListener('click', () => openAddSshModal(null));
|
||||
$('qaAddRdp') ?.addEventListener('click', () => openAddRdpModal(null));
|
||||
@@ -1589,9 +1608,13 @@ function updateSwarmsTable(state) {
|
||||
const id = s.id || s.serverId || '';
|
||||
const url = s.url || s.hsUrl || '';
|
||||
const safeId = id.replace(/"/g, '"');
|
||||
const label = s.label || '';
|
||||
return `
|
||||
<tr>
|
||||
<td class="mono" style="font-size:11px;color:var(--text3);">${escapeHtml(truncate(id, 20))}</td>
|
||||
<td>
|
||||
${label ? `<div style="font-weight:600;color:var(--text);margin-bottom:2px;">${escapeHtml(label)}</div>` : ''}
|
||||
<div class="mono" style="font-size:11px;color:var(--text3);">${escapeHtml(truncate(id, 20))}</div>
|
||||
</td>
|
||||
<td style="font-weight:600;color:var(--text);">${s.port ?? '—'}</td>
|
||||
<td>
|
||||
<div style="display:flex;align-items:center;gap:6px;">
|
||||
@@ -1630,9 +1653,11 @@ function updateSwarmsTable(state) {
|
||||
const server = (state.servers || []).find(s => (s.id || s.serverId) === serverId);
|
||||
if (!server) return;
|
||||
$('serverEditId').value = serverId;
|
||||
const labelEl = $('startServerLabel');
|
||||
const portEl = $('startServerPort');
|
||||
const hostEl = $('startServerHost');
|
||||
const secureEl = $('startServerSecure');
|
||||
if (labelEl) labelEl.value = server.label || '';
|
||||
if (portEl) portEl.value = server.port ?? 3000;
|
||||
if (hostEl) hostEl.value = server.host ?? '127.0.0.1';
|
||||
if (secureEl) secureEl.checked = server.secure !== false;
|
||||
@@ -2047,15 +2072,22 @@ function setupEvents() {
|
||||
|
||||
// ── Start Server ────────────────────────────────────────────────────────
|
||||
$('startServerBtn')?.addEventListener('click', () => {
|
||||
// Reset to "new server" mode
|
||||
const editIdEl = $('serverEditId');
|
||||
if (editIdEl) editIdEl.value = '';
|
||||
const labelEl = $('startServerLabel');
|
||||
if (labelEl) labelEl.value = '';
|
||||
const portEl = $('startServerPort');
|
||||
if (portEl) portEl.value = '3000';
|
||||
const hostEl = $('startServerHost');
|
||||
if (hostEl) hostEl.value = '127.0.0.1';
|
||||
const secureEl = $('startServerSecure');
|
||||
if (secureEl) secureEl.checked = true;
|
||||
const tcpEl = $('startServerProtocolTcp');
|
||||
if (tcpEl) tcpEl.checked = true;
|
||||
const titleEl = $('modal-startServer-title');
|
||||
if (titleEl) titleEl.textContent = 'Start Server Tunnel';
|
||||
const submitEl = $('startServerSubmit');
|
||||
if (submitEl) submitEl.textContent = 'Start Server';
|
||||
const tcpEl = $('startServerProtocolTcp');
|
||||
if (tcpEl) tcpEl.checked = true;
|
||||
openModal('modal-startServer');
|
||||
});
|
||||
|
||||
@@ -2063,18 +2095,21 @@ function setupEvents() {
|
||||
const portEl = $('startServerPort');
|
||||
const hostEl = $('startServerHost');
|
||||
const secureEl = $('startServerSecure');
|
||||
const labelEl = $('startServerLabel');
|
||||
const editIdEl = $('serverEditId');
|
||||
const port = parseInt(portEl?.value, 10) || 3000;
|
||||
const host = (hostEl?.value || '127.0.0.1').trim();
|
||||
const secure = secureEl?.checked !== false;
|
||||
const udp = document.querySelector('input[name="startServerProtocol"]:checked')?.value === 'udp';
|
||||
const editId = ($('serverEditId')?.value || '').trim();
|
||||
const label = (labelEl?.value || '').trim();
|
||||
const editId = (editIdEl?.value || '').trim();
|
||||
if (!port || port < 1 || port > 65535) { showModalError('modal-startServer', 'startServerError', 'Port must be 1–65535'); return; }
|
||||
const btn = $('startServerSubmit');
|
||||
if (btn) { btn.disabled = true; btn.textContent = editId ? 'Saving…' : 'Starting…'; }
|
||||
|
||||
const doStart = () => {
|
||||
chrome.runtime.sendMessage(
|
||||
{ target: 'holesail-native', action: 'send', payload: { type: 'startServer', payload: { port, host, secure, udp } } },
|
||||
{ target: 'holesail-native', action: 'send', payload: { type: 'startServer', payload: { port, host, secure, udp, label } } },
|
||||
(response) => {
|
||||
if (btn) { btn.disabled = false; btn.textContent = editId ? 'Save Changes' : 'Start Server'; }
|
||||
if (response?.ok) {
|
||||
@@ -2090,7 +2125,6 @@ function setupEvents() {
|
||||
};
|
||||
|
||||
if (editId) {
|
||||
// Stop old server first, then start new one with updated settings
|
||||
chrome.runtime.sendMessage(
|
||||
{ target: 'holesail-native', action: 'send', payload: { type: 'stopServer', payload: { serverId: editId } } },
|
||||
() => doStart()
|
||||
|
||||
@@ -86,7 +86,7 @@ function saveStateSync() {
|
||||
const file = getStatePath();
|
||||
const serversList = [];
|
||||
for (const [id, s] of servers) {
|
||||
serversList.push({ id, port: s.port, host: s.host, secure: s.secure, udp: s.udp || false });
|
||||
serversList.push({ id, port: s.port, host: s.host, secure: s.secure, udp: s.udp || false, label: s.label || '' });
|
||||
}
|
||||
const virtualHostsList = [];
|
||||
for (const [hostname, v] of virtualHosts) {
|
||||
@@ -309,8 +309,9 @@ async function startServer(payload) {
|
||||
const host = payload.host || '127.0.0.1';
|
||||
const secure = payload.secure !== false;
|
||||
const udp = payload.udp === true;
|
||||
const label = (payload.label || '').trim();
|
||||
const serverId = useServerId(payload.serverId);
|
||||
debugLog('startServer: serverId=', serverId, 'port=', port, 'host=', host, 'secure=', secure, 'udp=', udp);
|
||||
debugLog('startServer: serverId=', serverId, 'port=', port, 'host=', host, 'secure=', secure, 'udp=', udp, 'label=', label);
|
||||
if (servers.has(serverId)) {
|
||||
debugLog('startServer: serverId already in use');
|
||||
return { ok: false, error: 'Server id already in use' };
|
||||
@@ -325,6 +326,7 @@ async function startServer(payload) {
|
||||
host: hs.info.host,
|
||||
secure,
|
||||
udp,
|
||||
label,
|
||||
url,
|
||||
createdAt: Date.now()
|
||||
});
|
||||
@@ -337,7 +339,8 @@ async function startServer(payload) {
|
||||
port: hs.info.port,
|
||||
host: hs.info.host,
|
||||
secure,
|
||||
udp
|
||||
udp,
|
||||
label
|
||||
};
|
||||
} catch (e) {
|
||||
debugLog('startServer: error', e.message);
|
||||
@@ -372,6 +375,7 @@ function getServers() {
|
||||
url: s.url,
|
||||
secure: s.secure,
|
||||
udp: s.udp || false,
|
||||
label: s.label || '',
|
||||
createdAt: s.createdAt
|
||||
});
|
||||
}
|
||||
|
||||
+2
-1
@@ -107,7 +107,8 @@ async function restorePersistedTunnels(restored) {
|
||||
port: s.port,
|
||||
host: s.host || '127.0.0.1',
|
||||
secure: s.secure !== false,
|
||||
udp: s.udp === true
|
||||
udp: s.udp === true,
|
||||
label: s.label || ''
|
||||
});
|
||||
if (result.ok) serverOk++;
|
||||
else serverFail++;
|
||||
|
||||
Reference in New Issue
Block a user