Add shareable session deep links (#session=N)
This commit is contained in:
1 parent
66eb0b86e7
commit
cee1b6f7c3
1 file changed
+36
@@ -380,6 +380,7 @@ const STATE = {
|
|||||||
captureMode: '',
|
captureMode: '',
|
||||||
deviceConnected: null,
|
deviceConnected: null,
|
||||||
mapExpanded: new Set(),
|
mapExpanded: new Set(),
|
||||||
|
deepLinkHandled: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
const API_BASE = () => STATE.serverUrl;
|
const API_BASE = () => STATE.serverUrl;
|
||||||
@@ -1068,6 +1069,24 @@ function command_cat(ins) {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function session_link(id) {
|
||||||
|
return location.href.split('#')[0] + '#session=' + id;
|
||||||
|
}
|
||||||
|
|
||||||
|
function is_loopback() {
|
||||||
|
return ['localhost', '127.0.0.1', '::1', '[::1]', '0.0.0.0'].includes(location.hostname);
|
||||||
|
}
|
||||||
|
|
||||||
|
function copySessionLink(id) {
|
||||||
|
const url = session_link(id);
|
||||||
|
const prompt_ = () => prompt(t('Share link'), url);
|
||||||
|
if (navigator.clipboard && navigator.clipboard.writeText) {
|
||||||
|
navigator.clipboard.writeText(url).catch(prompt_);
|
||||||
|
} else {
|
||||||
|
prompt_();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function buildTraceMap() {
|
function buildTraceMap() {
|
||||||
const msgs = STATE.messages;
|
const msgs = STATE.messages;
|
||||||
const groups = [];
|
const groups = [];
|
||||||
@@ -1503,6 +1522,7 @@ async function loadSessions() {
|
|||||||
</div>
|
</div>
|
||||||
<div class="session-actions">
|
<div class="session-actions">
|
||||||
<a class="session-download" href="${API_BASE()}/api/sessions/${s.id}/pcap">${t('Download PCAP')}</a>
|
<a class="session-download" href="${API_BASE()}/api/sessions/${s.id}/pcap">${t('Download PCAP')}</a>
|
||||||
|
${is_loopback() ? '' : `<button class="session-copy" data-sid="${s.id}">${t('Copy link')}</button>`}
|
||||||
<button class="session-delete" data-sid="${s.id}">${t('Delete')}</button>
|
<button class="session-delete" data-sid="${s.id}">${t('Delete')}</button>
|
||||||
</div>
|
</div>
|
||||||
</div>`;
|
</div>`;
|
||||||
@@ -1536,6 +1556,12 @@ async function loadSessions() {
|
|||||||
showDeleteModal(sid);
|
showDeleteModal(sid);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
grid.querySelectorAll('.session-copy').forEach(btn => {
|
||||||
|
btn.addEventListener('click', e => {
|
||||||
|
e.stopPropagation();
|
||||||
|
copySessionLink(parseInt(btn.dataset.sid));
|
||||||
|
});
|
||||||
|
});
|
||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1576,6 +1602,7 @@ async function loadSession(id) {
|
|||||||
renderMessages();
|
renderMessages();
|
||||||
el('session-name-display').style.display = 'inline';
|
el('session-name-display').style.display = 'inline';
|
||||||
el('session-name-display').textContent = t('Session: ') + (data.session.name || '#' + id);
|
el('session-name-display').textContent = t('Session: ') + (data.session.name || '#' + id);
|
||||||
|
history.replaceState(null, '', '#session=' + id);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
alert(t('Failed to load session'));
|
alert(t('Failed to load session'));
|
||||||
}
|
}
|
||||||
@@ -1757,6 +1784,11 @@ async function checkConnection() {
|
|||||||
}
|
}
|
||||||
updateCaptureButton();
|
updateCaptureButton();
|
||||||
renderTraceEmptyState();
|
renderTraceEmptyState();
|
||||||
|
if (!STATE.deepLinkHandled) {
|
||||||
|
STATE.deepLinkHandled = true;
|
||||||
|
const m = location.hash.match(/^#session=(\d+)$/);
|
||||||
|
if (m) loadSession(parseInt(m[1]));
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
STATE.serverAvailable = false;
|
STATE.serverAvailable = false;
|
||||||
STATE.captureMode = '';
|
STATE.captureMode = '';
|
||||||
@@ -1900,6 +1932,8 @@ const LANG_RU = {
|
|||||||
'msgs': 'сообщ.',
|
'msgs': 'сообщ.',
|
||||||
'active': 'активна',
|
'active': 'активна',
|
||||||
'Download PCAP': 'Скачать PCAP',
|
'Download PCAP': 'Скачать PCAP',
|
||||||
|
'Copy link': 'Копировать ссылку',
|
||||||
|
'Share link': 'Ссылка для общего доступа',
|
||||||
'{n} messages': '{n} сообщений',
|
'{n} messages': '{n} сообщений',
|
||||||
'{n} session(s) · {size}': '{n} сессий · {size}',
|
'{n} session(s) · {size}': '{n} сессий · {size}',
|
||||||
'{n} session · {size}': '{n} сессия · {size}',
|
'{n} session · {size}': '{n} сессия · {size}',
|
||||||
@@ -2049,6 +2083,7 @@ function init() {
|
|||||||
STATE.sessionViewId = null;
|
STATE.sessionViewId = null;
|
||||||
STATE.currentSessionName = null;
|
STATE.currentSessionName = null;
|
||||||
updateCaptureButton();
|
updateCaptureButton();
|
||||||
|
history.replaceState(null, '', location.pathname);
|
||||||
}
|
}
|
||||||
startCapture();
|
startCapture();
|
||||||
});
|
});
|
||||||
@@ -2063,6 +2098,7 @@ function init() {
|
|||||||
STATE.sessionViewId = null;
|
STATE.sessionViewId = null;
|
||||||
STATE.currentSessionName = null;
|
STATE.currentSessionName = null;
|
||||||
updateCaptureButton();
|
updateCaptureButton();
|
||||||
|
history.replaceState(null, '', location.pathname);
|
||||||
switchTab('trace');
|
switchTab('trace');
|
||||||
startCapture();
|
startCapture();
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in new issue
Block a user