mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-10-29 17:35:13 +08:00
🤞 Sync 2026-09-30 23:44:05
This commit is contained in:
1 parent
e3fde93105
commit
44bb740ab2
206 files changed
+5736
-2799
No files matched your search
@@ -255,13 +255,17 @@ function renderLogs(logs_data) {
|
||||
}, lines);
|
||||
}
|
||||
|
||||
function renderDevices(status) {
|
||||
function renderPeerRows(status, query) {
|
||||
if (!status || !status.hasOwnProperty('status')) {
|
||||
return E('em', {}, _('Collecting data ...'));
|
||||
return [E('tr', { 'class': 'cbi-section-table-row' }, [
|
||||
E('td', { 'class': 'cbi-value-field', 'colspan': 8 }, E('em', {}, _('Collecting data ...')))
|
||||
])];
|
||||
}
|
||||
|
||||
if (status.status != 'running') {
|
||||
return E('em', {}, _('Tailscale status error'));
|
||||
return [E('tr', { 'class': 'cbi-section-table-row' }, [
|
||||
E('td', { 'class': 'cbi-value-field', 'colspan': 8 }, E('em', {}, _('Tailscale status error')))
|
||||
])];
|
||||
}
|
||||
|
||||
if (Object.keys(regionCodeMap).length === 0) {
|
||||
@@ -270,45 +274,28 @@ function renderDevices(status) {
|
||||
|
||||
const peers = status.peers;
|
||||
if (!peers || Object.keys(peers).length === 0) {
|
||||
return E('p', {}, _('No peer devices found.'));
|
||||
return [E('tr', { 'class': 'cbi-section-table-row' }, [
|
||||
E('td', { 'class': 'cbi-value-field', 'colspan': 8 }, E('p', {}, _('No peer devices found.')))
|
||||
])];
|
||||
}
|
||||
|
||||
const peerTableHeaders = [
|
||||
{ text: _('Status'), style: 'width: 80px;' },
|
||||
{ text: _('Hostname') },
|
||||
{ text: _('Tailscale IP') },
|
||||
{ text: _('OS') },
|
||||
{ text: _('Connection Info') },
|
||||
{ text: _('RX') },
|
||||
{ text: _('TX') },
|
||||
{ text: _('Last Seen') }
|
||||
];
|
||||
const q = (query || '').toLowerCase().trim();
|
||||
const td_style = 'padding-right: 20px;';
|
||||
const rows = [];
|
||||
|
||||
const existingFilter = document.getElementById('tailscale_devices_filter');
|
||||
const currentQuery = existingFilter ? existingFilter.value : '';
|
||||
|
||||
const searchInput = E('input', {
|
||||
'id': 'tailscale_devices_filter',
|
||||
'class': 'cbi-input-text',
|
||||
'type': 'text',
|
||||
'placeholder': _('Filter by hostname, IP, OS...'),
|
||||
'style': 'margin-bottom: 8px; width: 100%; max-width: 320px;'
|
||||
});
|
||||
if (currentQuery) {
|
||||
searchInput.value = currentQuery;
|
||||
}
|
||||
|
||||
const rows = Object.entries(peers).map(([peerid, peer]) => {
|
||||
const td_style = 'padding-right: 20px;';
|
||||
for (const id in peers) {
|
||||
const peer = peers[id];
|
||||
const hostname = peer.hostname || '';
|
||||
const ip = peer.ip || '';
|
||||
const ostype = peer.ostype || '';
|
||||
const searchText = `${hostname} ${ip} ${ostype}`.toLowerCase();
|
||||
|
||||
const tr = E('tr', {
|
||||
'class': 'cbi-rowstyle-1',
|
||||
'data-search-text': searchText
|
||||
}, [
|
||||
if (q && !hostname.toLowerCase().includes(q) &&
|
||||
!ip.toLowerCase().includes(q) &&
|
||||
!ostype.toLowerCase().includes(q)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
rows.push(E('tr', { 'class': 'cbi-rowstyle-1' }, [
|
||||
E('td', { 'class': 'cbi-value-field', 'style': td_style },
|
||||
E('span', {
|
||||
'style': `color:${peer.exit_node ? 'blue' : (peer.online ? 'green' : 'gray')};`,
|
||||
@@ -322,58 +309,71 @@ function renderDevices(status) {
|
||||
E('td', { 'class': 'cbi-value-field', 'style': td_style }, formatBytes(peer.rx)),
|
||||
E('td', { 'class': 'cbi-value-field', 'style': td_style }, formatBytes(peer.tx)),
|
||||
E('td', { 'class': 'cbi-value-field', 'style': td_style }, formatLastSeen(peer.lastseen))
|
||||
]);
|
||||
|
||||
if (currentQuery && !searchText.includes(currentQuery.toLowerCase().trim())) {
|
||||
tr.style.display = 'none';
|
||||
}
|
||||
|
||||
return tr;
|
||||
});
|
||||
|
||||
searchInput.addEventListener('input', function(ev) {
|
||||
const q = (ev.target.value || '').toLowerCase().trim();
|
||||
for (const tr of rows) {
|
||||
const text = tr.getAttribute('data-search-text') || '';
|
||||
tr.style.display = (!q || text.includes(q)) ? '' : 'none';
|
||||
}
|
||||
});
|
||||
|
||||
if (existingFilter && document.activeElement === existingFilter) {
|
||||
requestAnimationFrame(() => {
|
||||
searchInput.focus();
|
||||
const valLen = searchInput.value.length;
|
||||
searchInput.setSelectionRange(valLen, valLen);
|
||||
});
|
||||
]));
|
||||
}
|
||||
|
||||
const existingContainer = document.getElementById('tailscale_devices_table_container');
|
||||
const scrollPos = existingContainer ? existingContainer.scrollTop : 0;
|
||||
if (rows.length === 0) {
|
||||
return [E('tr', { 'class': 'cbi-section-table-row' }, [
|
||||
E('td', { 'class': 'cbi-value-field', 'colspan': 8 }, E('p', {}, _('No peer devices found.')))
|
||||
])];
|
||||
}
|
||||
|
||||
const table = E('table', { 'class': 'cbi-table' }, [
|
||||
E('tr', { 'class': 'cbi-table-header' }, peerTableHeaders.map(header => {
|
||||
let th_style = 'padding-right: 20px; text-align: left; position: sticky; top: 0; background: inherit; z-index: 1;';
|
||||
return rows;
|
||||
}
|
||||
|
||||
function renderDevices(status) {
|
||||
const thead = E('thead', {}, [
|
||||
E('tr', {
|
||||
'class': 'tr cbi-section-table-titles',
|
||||
'style': 'position: sticky; top: 0; z-index: 10; background-color: var(--background-color, #fff);'
|
||||
}, peerTableHeaders.map(function(header) {
|
||||
let th_style = 'padding-right: 20px; text-align: left;';
|
||||
if (header.style) {
|
||||
th_style += header.style;
|
||||
}
|
||||
return E('th', { 'class': 'cbi-table-cell', 'style': th_style }, header.text);
|
||||
})),
|
||||
...rows
|
||||
return E('th', { 'class': 'th cbi-table-cell', 'style': th_style }, header.text);
|
||||
}))
|
||||
]);
|
||||
|
||||
const tbody = E('tbody', { 'id': 'tailscale_devices_tbody' }, renderPeerRows(status, ''));
|
||||
|
||||
const table = E('table', { 'class': 'table cbi-table' }, [
|
||||
thead,
|
||||
tbody
|
||||
]);
|
||||
|
||||
const tableContainer = E('div', {
|
||||
'id': 'tailscale_devices_table_container',
|
||||
'style': 'max-height: 480px; overflow-y: auto; overflow-x: auto; border: 1px solid #ddd; border-radius: 3px;'
|
||||
'style': 'max-height: 480px; overflow-y: auto; overflow-x: auto;'
|
||||
}, [table]);
|
||||
|
||||
if (scrollPos > 0) {
|
||||
requestAnimationFrame(() => {
|
||||
tableContainer.scrollTop = scrollPos;
|
||||
});
|
||||
}
|
||||
const searchInput = E('input', {
|
||||
'id': 'tailscale_devices_filter',
|
||||
'type': 'text',
|
||||
'class': 'cbi-input-text',
|
||||
'placeholder': _('Filter peers by name, IP, or OS...'),
|
||||
'style': 'width: 100%; box-sizing: border-box;'
|
||||
});
|
||||
|
||||
searchInput.addEventListener('input', function() {
|
||||
const targetBody = document.getElementById('tailscale_devices_tbody');
|
||||
if (targetBody && lastDevicesStatus) {
|
||||
targetBody.replaceChildren(...renderPeerRows(lastDevicesStatus, this.value));
|
||||
}
|
||||
});
|
||||
|
||||
const filterContainer = E('div', {
|
||||
'style': 'display: flex; align-items: center; gap: 0.5em; margin-bottom: 0.5em;'
|
||||
}, [
|
||||
E('label', {
|
||||
'for': 'tailscale_devices_filter',
|
||||
'style': 'white-space: nowrap; font-weight: bold;'
|
||||
}, _('Filter:')),
|
||||
E('div', { 'style': 'flex: 1;' }, [searchInput])
|
||||
]);
|
||||
|
||||
return E('div', { 'style': 'width: 100%;' }, [
|
||||
searchInput,
|
||||
filterContainer,
|
||||
tableContainer
|
||||
]);
|
||||
}
|
||||
@@ -440,9 +440,12 @@ return view.extend({
|
||||
view.replaceChildren(content);
|
||||
}
|
||||
|
||||
const devicesView = document.getElementById("tailscale_devices_display");
|
||||
if (devicesView) {
|
||||
devicesView.replaceChildren(renderDevices(res));
|
||||
lastDevicesStatus = res;
|
||||
const devicesTbody = document.getElementById("tailscale_devices_tbody");
|
||||
if (devicesTbody) {
|
||||
const filterInput = document.getElementById("tailscale_devices_filter");
|
||||
const currentQuery = filterInput ? filterInput.value : '';
|
||||
devicesTbody.replaceChildren(...renderPeerRows(res, currentQuery));
|
||||
}
|
||||
|
||||
// login button only available when logged out
|
||||
@@ -644,6 +647,7 @@ return view.extend({
|
||||
s.tab('devices', _('Devices List'));
|
||||
const devicesSection = s.taboption('devices', form.DummyValue, '_devices');
|
||||
devicesSection.render = function () {
|
||||
lastDevicesStatus = status;
|
||||
return E('div', { 'id': 'tailscale_devices_display', 'class': 'cbi-value' }, renderDevices(status));
|
||||
};
|
||||
|
||||
|
||||
Reference in new issue
Block a user