Added missed configs to network config

Fixed some layouts issues
This commit is contained in:
defnax 2026-07-25 13:06:05 +02:00
parent 545d388257
commit b97c739219

View File

@ -76,13 +76,15 @@ const SetNwMode = () => {
},
view: (vnode) => {
const isHiddenMode = vnode.attrs && vnode.attrs.isHiddenMode;
const hideLabel = vnode.attrs && vnode.attrs.hideLabel;
const modes = isHiddenMode ? hiddenModes : networkModes;
return [
m('p', isHiddenMode ? 'Discovery:' : 'Network mode:'),
!hideLabel && m('p', isHiddenMode ? 'Discovery:' : 'Network mode:'),
m(
'select',
{
style: 'flex: 1; max-width: 320px; padding: 0.4rem; border: 1px solid #cbd5e1; border-radius: 4px;',
value: selectedMode,
onchange: (e) => {
const idx = e.target.selectedIndex;
@ -130,52 +132,6 @@ const SetNwMode = () => {
};
};
const SetNAT = () => {
let sslId;
let netMode;
return {
oninit: () => {
rs.rsJsonApiRequest('/rsAccounts/getCurrentAccountId').then((res) => {
if (res.body.retval) {
sslId = res.body.id;
rs.rsJsonApiRequest('/rsPeers/getPeerDetails', {
sslId,
}).then((res) => {
if (res.body.retval) {
netMode = res.body.det.netMode;
}
});
}
});
},
view: () => [
m('p', 'NAT:'),
m(
'select',
{
value: netMode,
onchange: (e) => {
rs.rsJsonApiRequest('/rsPeers/setNetworkMode', {
sslId,
netMode,
}).then((res) => {
if (res.body.retval) {
netMode = e.target.value;
}
});
},
},
[
m('option', { value: util.RS_NETMODE_UPNP }, 'Automatic (UPnP)'),
m('option', { value: util.RS_NETMODE_UDP }, 'FireWalled'),
m('option', { value: util.RS_NETMODE_EXT }, 'Manually Forwarded Port'),
]
),
],
};
};
const SetLimits = () => {
let dlim = undefined;
let ulim = undefined;
@ -191,37 +147,41 @@ const SetLimits = () => {
ulim = data.outKb;
}),
view: () => [
m(
'p',
util.tooltip(
'The download limit covers the whole application. ' +
'However, in some situations, such as when transfering ' +
'many files at once, the estimated bandwidth becomes ' +
'unreliable and the total value reported by Retroshare ' +
'might exceed that limit.'
),
'Download limit(KB/s):'
),
m('input[type=number][name=download]', {
value: dlim,
oninput: (e) => (dlim = Number(e.target.value)),
onchange: setMaxRates,
}),
m(
'p',
util.tooltip(
'The upload limit covers the entire software. ' +
'Too small an upload limit may eventually block ' +
'low priority services(forums, channels). ' +
'A minimum recommended value is 50KB/s.'
),
'Upload limit(KB/s):'
),
m('input[type=number][name=upload]', {
value: ulim,
oninput: (e) => (ulim = Number(e.target.value)),
onchange: setMaxRates,
}),
m('.nw-config-row', { style: 'display: grid; grid-template-columns: 200px 1fr; gap: 1rem; align-items: center; margin-bottom: 0.75rem;' }, [
m('p', { style: 'font-weight: 600; color: #475569;' }, [
util.tooltip(
'The download limit covers the whole application. ' +
'However, in some situations, such as when transfering ' +
'many files at once, the estimated bandwidth becomes ' +
'unreliable and the total value reported by Retroshare ' +
'might exceed that limit.'
),
'Download limit(KB/s):'
]),
m('input[type=number][name=download]', {
style: 'padding: 0.4rem; border: 1px solid #cbd5e1; border-radius: 4px; max-width: 320px; width: 100%;',
value: dlim,
oninput: (e) => (dlim = Number(e.target.value)),
onchange: setMaxRates,
}),
]),
m('.nw-config-row', { style: 'display: grid; grid-template-columns: 200px 1fr; gap: 1rem; align-items: center; margin-bottom: 0.75rem;' }, [
m('p', { style: 'font-weight: 600; color: #475569;' }, [
util.tooltip(
'The upload limit covers the entire software. ' +
'Too small an upload limit may eventually block ' +
'low priority services(forums, channels). ' +
'A minimum recommended value is 50KB/s.'
),
'Upload limit(KB/s):'
]),
m('input[type=number][name=upload]', {
style: 'padding: 0.4rem; border: 1px solid #cbd5e1; border-radius: 4px; max-width: 320px; width: 100%;',
value: ulim,
oninput: (e) => (ulim = Number(e.target.value)),
onchange: setMaxRates,
}),
]),
],
};
};
@ -236,87 +196,241 @@ const SetOpMode = () => {
oninit: () =>
rs.rsJsonApiRequest('/rsConfig/getOperatingMode', {}, (data) => (opmode = data.retval)),
view: () => [
m(
'p',
'Operating mode:',
util.tooltip(
`No Anon D/L: Switches off file forwarding\n
Gaming Mode: 25% standard traffic and TODO: Reduced popups\n
Low traffic: 10% standard traffic and TODO: pause all file transfers\n`
)
),
m(
'select',
{
oninput: (e) => (opmode = e.target.value),
value: opmode,
onchange: setmode,
},
['Normal', 'No Anon D/L', 'Gaming', 'Low traffic'].map((val, i) =>
m(`option[value=${i + 1}]`, val)
)
),
m('.nw-config-row', { style: 'display: grid; grid-template-columns: 200px 1fr; gap: 1rem; align-items: center; margin-bottom: 0.75rem;' }, [
m('p', { style: 'font-weight: 600; color: #475569;' }, [
'Operating mode: ',
util.tooltip(
`No Anon D/L: Switches off file forwarding\n
Gaming Mode: 25% standard traffic and TODO: Reduced popups\n
Low traffic: 10% standard traffic and TODO: pause all file transfers\n`
)
]),
m(
'select',
{
style: 'padding: 0.4rem; border: 1px solid #cbd5e1; border-radius: 4px; max-width: 320px; width: 100%;',
oninput: (e) => (opmode = e.target.value),
value: opmode,
onchange: setmode,
},
['Normal', 'No Anon D/L', 'Gaming', 'Low traffic'].map((val, i) =>
m(`option[value=${i + 1}]`, val)
)
),
]),
],
};
};
const displayLocalIPAddress = () => {
return {
view: ({ attrs: { details } }) =>
details && [m('p', 'Local Address: '), m('p', details.localAddr)],
};
};
const displayExternalIPAddress = () => {
return {
view: ({ attrs: { details, isHiddenMode } }) =>
details && [m('p', 'External Address: '), m('p', isHiddenMode ? 'Hidden - See Config' : details.extAddr)],
};
};
const displayIPAddresses = () => {
return {
view: ({ attrs: { details } }) =>
details && [
m('p', 'External Address: '),
details && m('.nw-config-row', { style: 'display: grid; grid-template-columns: 200px 1fr; gap: 1rem; align-items: flex-start; margin-bottom: 0.75rem;' }, [
m('p', { style: 'font-weight: 600; color: #475569;' }, 'External Address: '),
m(
'ul.external-address',
details.ipAddressList.map((ip) => m('li', ip))
),
],
]),
};
};
const SetDynamicDNS = () => {
let addr = '';
const NetworkConfigForm = () => {
let sslId = '';
let details = {};
let netStatus = {};
let localAddr = '';
let localPort = 0;
let extAddr = '';
let extPort = 0;
let dyndns = '';
let netMode = util.RS_NETMODE_EXT;
const loadData = () => {
rs.rsJsonApiRequest('/rsAccounts/getCurrentAccountId').then((res) => {
if (res.body.retval) {
sslId = res.body.id;
rs.rsJsonApiRequest('/rsPeers/getPeerDetails', { sslId }).then((pRes) => {
if (pRes.body.retval) {
details = pRes.body.det;
localAddr = details.localAddr || '';
localPort = details.localPort || 0;
extAddr = details.extAddr || '';
extPort = details.extPort || 0;
dyndns = details.dyndns || '';
netMode = details.netMode || util.RS_NETMODE_EXT;
m.redraw();
}
});
rs.rsJsonApiRequest('/rsConfig/getConfigNetStatus', {}).then((nRes) => {
if (nRes.body) {
netStatus = nRes.body;
if (netStatus.localPort) localPort = netStatus.localPort;
if (netStatus.extPort) extPort = netStatus.extPort;
m.redraw();
}
});
}
});
};
const saveLocalAddress = () => {
if (!sslId) return;
rs.rsJsonApiRequest('/rsPeers/setLocalAddress', {
sslId,
addr: localAddr,
port: parseInt(localPort) || 0,
}).then(() => loadData());
};
const saveExtAddress = () => {
if (!sslId) return;
rs.rsJsonApiRequest('/rsPeers/setExtAddress', {
sslId,
addr: extAddr,
port: parseInt(extPort) || 0,
}).then(() => loadData());
};
const saveDynDNS = () => {
if (!sslId) return;
rs.rsJsonApiRequest('/rsPeers/setDynDNS', {
sslId,
addr: dyndns,
});
};
const saveNetMode = (newMode) => {
if (!sslId) return;
netMode = newMode;
rs.rsJsonApiRequest('/rsPeers/setNetworkMode', {
sslId,
netMode: parseInt(newMode),
}).then(() => loadData());
};
return {
oninit: () => {
rs.rsJsonApiRequest('/rsAccounts/getCurrentAccountId').then((res) => {
if (res.body.retval) {
sslId = res.body.id;
rs.rsJsonApiRequest('/rsPeers/getPeerDetails', {
sslId,
}).then((res) => {
if (res.body.retval) {
addr = res.body.det.dyndns;
}
});
}
});
loadData();
},
view: () => [
m('p', 'Set Dynamic DNS:'),
m('input[type=text]', {
value: addr,
oninput: (e) => (addr = e.target.value),
onchange: () => {
rs.rsJsonApiRequest('/rsPeers/setDynDNS', {
sslId,
addr,
});
},
}),
],
view: ({ attrs: { isHiddenMode } }) => {
const isUpnpOk = Boolean(netStatus.netUpnpOk || netStatus.uPnPActive);
const isLocalOk = Boolean(netStatus.netLocalOk !== false);
const isExtOk = Boolean(netStatus.netExtAddressOk);
return m('.network-config-form', {
style: {
display: 'flex',
flexDirection: 'column',
gap: '0.75rem',
width: '100%',
}
}, [
// Network Mode row
m('.nw-config-row', { style: 'display: grid; grid-template-columns: 200px 1fr; gap: 1rem; align-items: center;' }, [
m('label', { style: 'font-weight: 600; color: #475569;' }, 'Network Mode'),
m('.nw-mode-group', { style: 'display: flex; align-items: center; gap: 1rem;' }, [
m(SetNwMode, { isHiddenMode, hideLabel: true }),
isHiddenMode && m('.status-indicator', { style: 'display: flex; align-items: center; gap: 0.4rem;' }, [
m('.bullet', {
style: 'width: 10px; height: 10px; border-radius: 50%; background-color: #22c55e;'
}),
m('span', { style: 'font-size: 0.85rem; font-weight: 700; color: #000000;' }, '[Hidden mode]'),
]),
]),
]),
// NAT row + UPnP status bullet
!isHiddenMode && m('.nw-config-row', { style: 'display: grid; grid-template-columns: 200px 1fr; gap: 1rem; align-items: center;' }, [
m('label', { style: 'font-weight: 600; color: #475569;' }, 'NAT'),
m('.nat-control-group', { style: 'display: flex; align-items: center; gap: 1rem; flex-wrap: wrap;' }, [
m('select', {
style: 'flex: 1; max-width: 320px; padding: 0.4rem; border: 1px solid #cbd5e1; border-radius: 4px;',
value: netMode,
onchange: (e) => saveNetMode(e.target.value),
}, [
m('option', { value: util.RS_NETMODE_UPNP }, 'Automatic (UPnP)'),
m('option', { value: util.RS_NETMODE_UDP }, 'FireWalled'),
m('option', { value: util.RS_NETMODE_EXT }, 'Manually Forwarded Port'),
]),
m('.status-indicator', { style: 'display: flex; align-items: center; gap: 0.4rem;' }, [
m('.bullet', {
style: `width: 10px; height: 10px; border-radius: 50%; background-color: ${isUpnpOk ? '#22c55e' : '#475569'};`
}),
m('span', { style: 'font-size: 0.85rem; font-weight: 600; color: #334155;' }, 'UPnP'),
]),
]),
]),
// Local Address + Port + Local network status bullet
m('.nw-config-row', { style: 'display: grid; grid-template-columns: 200px 1fr; gap: 1rem; align-items: center;' }, [
m('label', { style: 'font-weight: 600; color: #475569;' }, 'Local Address'),
m('.addr-control-group', { style: 'display: flex; align-items: center; gap: 1rem; flex-wrap: wrap;' }, [
m('input[type=text]', {
style: 'flex: 1; max-width: 320px; padding: 0.4rem; border: 1px solid #cbd5e1; border-radius: 4px;',
value: localAddr,
oninput: (e) => (localAddr = e.target.value),
onchange: saveLocalAddress,
}),
m('.port-group', { style: 'display: flex; align-items: center; gap: 0.4rem;' }, [
m('span', { style: 'font-size: 0.85rem; font-weight: 600; color: #475569;' }, 'Port:'),
m('input[type=number]', {
style: 'width: 90px; padding: 0.4rem; border: 1px solid #cbd5e1; border-radius: 4px;',
value: localPort,
oninput: (e) => (localPort = parseInt(e.target.value) || 0),
onchange: saveLocalAddress,
}),
]),
!isHiddenMode && m('.status-indicator', { style: 'display: flex; align-items: center; gap: 0.4rem; margin-left: 0.5rem;' }, [
m('.bullet', {
style: `width: 10px; height: 10px; border-radius: 50%; background-color: ${isLocalOk ? '#22c55e' : '#ef4444'};`
}),
m('span', { style: 'font-size: 0.85rem; font-weight: 600; color: #334155;' }, 'Local network'),
]),
]),
]),
// External Address + Port + External ip address finder status bullet
m('.nw-config-row', { style: 'display: grid; grid-template-columns: 200px 1fr; gap: 1rem; align-items: center;' }, [
m('label', { style: 'font-weight: 600; color: #475569;' }, 'External Address'),
m('.addr-control-group', { style: 'display: flex; align-items: center; gap: 1rem; flex-wrap: wrap;' }, [
m('input[type=text]', {
style: 'flex: 1; max-width: 320px; padding: 0.4rem; border: 1px solid #cbd5e1; border-radius: 4px;',
value: isHiddenMode ? 'Hidden' : extAddr,
disabled: isHiddenMode,
oninput: (e) => (extAddr = e.target.value),
onchange: saveExtAddress,
}),
!isHiddenMode && m('.port-group', { style: 'display: flex; align-items: center; gap: 0.4rem;' }, [
m('span', { style: 'font-size: 0.85rem; font-weight: 600; color: #475569;' }, 'Port:'),
m('input[type=number]', {
style: 'width: 90px; padding: 0.4rem; border: 1px solid #cbd5e1; border-radius: 4px;',
value: extPort,
oninput: (e) => (extPort = parseInt(e.target.value) || 0),
onchange: saveExtAddress,
}),
]),
!isHiddenMode && m('.status-indicator', { style: 'display: flex; align-items: center; gap: 0.4rem; margin-left: 0.5rem;' }, [
m('.bullet', {
style: `width: 10px; height: 10px; border-radius: 50%; background-color: ${isExtOk ? '#22c55e' : '#808080'};`
}),
m('span', { style: 'font-size: 0.85rem; font-weight: 600; color: #334155;' }, 'External ip address finder'),
]),
]),
]),
// Dynamic DNS row
!isHiddenMode && m('.nw-config-row', { style: 'display: grid; grid-template-columns: 200px 1fr; gap: 1rem; align-items: center;' }, [
m('label', { style: 'font-weight: 600; color: #475569;' }, 'Dynamic DNS'),
m('input[type=text]', {
style: 'flex: 1; max-width: 320px; padding: 0.4rem; border: 1px solid #cbd5e1; border-radius: 4px;',
value: dyndns,
oninput: (e) => (dyndns = e.target.value),
onchange: saveDynDNS,
}),
]),
]);
}
};
};
@ -416,46 +530,45 @@ const SetSocksProxy = () => {
});
},
view: () =>
m('.proxy-server', [
m(
'p',
m('.proxy-server-form', { style: 'display: flex; flex-direction: column; gap: 0.75rem; width: 100%;' }, [
m('p.proxy-description', { style: 'margin-bottom: 0.5rem; color: #475569;' },
'Configure your TOR and I2P SOCKS proxy here. It will allow you to also connect to hidden nodes.'
),
m('.proxy-rows-container',
Object.keys(socksProxyObj).map((proxyItem) => {
const isTor = proxyItem === 'tor';
const labelText = isTor ? 'TOR Socks Proxy:' : 'I2P Socks Proxy:';
const outgoingText = isTor ? 'TOR outgoing' : 'I2P outgoing';
const notEnabledText = isTor ? 'Tor proxy is not enabled' : 'I2P proxy is not enabled';
const isOutgoing = socksProxyObj[proxyItem].outgoing;
return m('.proxy-row', [
m('label.proxy-label', labelText),
m('input[type=text].proxy-addr-input', {
value: socksProxyObj[proxyItem].addr,
Object.keys(socksProxyObj).map((proxyItem) => {
const isTor = proxyItem === 'tor';
const labelText = isTor ? 'TOR Socks Proxy:' : 'I2P Socks Proxy:';
const outgoingText = isTor ? 'TOR outgoing' : 'I2P outgoing';
const notEnabledText = isTor ? 'Tor proxy is not enabled' : 'I2P proxy is not enabled';
const isOutgoing = socksProxyObj[proxyItem].outgoing;
return m('.nw-config-row', { style: 'display: grid; grid-template-columns: 200px 1fr; gap: 1rem; align-items: center;' }, [
m('label', { style: 'font-weight: 600; color: #475569;' }, labelText),
m('.proxy-control-group', { style: 'display: flex; align-items: center; gap: 0.75rem; flex-wrap: wrap;' }, [
m('input[type=text]', {
style: 'flex: 1; max-width: 480px; min-width: 320px; padding: 0.4rem; border: 1px solid #cbd5e1; border-radius: 4px;',
value: socksProxyObj[proxyItem].addr || '',
oninput: (e) => (socksProxyObj[proxyItem].addr = e.target.value),
onchange: () => handleProxyChange(proxyItem),
}),
m('input[type=number].proxy-port-input', {
value: socksProxyObj[proxyItem].port,
oninput: (e) => (socksProxyObj[proxyItem].port = parseInt(e.target.value)),
m('input[type=number]', {
style: 'width: 90px; padding: 0.4rem; border: 1px solid #cbd5e1; border-radius: 4px;',
value: socksProxyObj[proxyItem].port || 0,
oninput: (e) => (socksProxyObj[proxyItem].port = parseInt(e.target.value) || 0),
onchange: () => handleProxyChange(proxyItem),
}),
socksProxyObj[proxyItem].outgoing !== undefined &&
m('.proxy-status-container', [
m('.proxy-status-bullet', {
style: {
backgroundColor: isOutgoing ? '#22c55e' : '#808080',
},
m('.status-indicator', { style: 'display: flex; align-items: center; gap: 0.4rem; margin-left: 0.5rem;' }, [
m('.bullet', {
style: `width: 10px; height: 10px; border-radius: 50%; background-color: ${isOutgoing ? '#22c55e' : '#808080'};`,
title: isOutgoing ? 'Proxy seems to work.' : notEnabledText,
}),
m(
'span.proxy-status-text',
m('span', { style: 'font-size: 0.85rem; font-weight: 600; color: #334155;' },
`${outgoingText} ${isOutgoing ? 'on' : 'off'}`
),
]),
]);
})
),
]),
]);
}),
]),
};
};
@ -464,27 +577,42 @@ const displayHiddenServiceInfo = () => {
return {
view: ({ attrs: { details } }) =>
details && details.hiddenNodeAddress &&
m('.proxy-server', [
m('p.proxy-description', details.hiddenType === 4
? 'I2P has been automatically configured by Retroshare. You shouldn\'t need to change anything here.'
: 'Tor has been automatically configured by Retroshare. You shouldn\'t need to change anything here.'
m('.hidden-service-info', { style: 'display: flex; flex-direction: column; gap: 0.75rem; width: 100%;' }, [
m('p.proxy-description', { style: 'margin-bottom: 0.5rem; color: #475569;' }, details.hiddenType === 4
? "I2P has been automatically configured by Retroshare. You shouldn't need to change anything here."
: "Tor has been automatically configured by Retroshare. You shouldn't need to change anything here."
),
m('hr'),
m('.proxy-row', [
m('label.proxy-label', 'Local Address:'),
m('span', details.localAddr || '127.0.0.1'),
// Local Address + Local Port row
m('.nw-config-row', { style: 'display: grid; grid-template-columns: 200px 1fr; gap: 1rem; align-items: center;' }, [
m('label', { style: 'font-weight: 600; color: #475569;' }, 'Local Address:'),
m('.addr-port-group', { style: 'display: flex; align-items: center; gap: 0.75rem; flex-wrap: wrap;' }, [
m('input[type=text]', {
style: 'flex: 1; max-width: 480px; min-width: 320px; padding: 0.4rem; border: 1px solid #cbd5e1; border-radius: 4px; background-color: #f8fafc; color: #334155;',
readOnly: true,
value: details.localAddr || '127.0.0.1',
}),
m('input[type=number]', {
style: 'width: 90px; padding: 0.4rem; border: 1px solid #cbd5e1; border-radius: 4px; background-color: #f8fafc; color: #334155;',
readOnly: true,
value: details.localPort || 0,
}),
]),
]),
m('.proxy-row', [
m('label.proxy-label', details.hiddenType === 4 ? 'I2P Address:' : 'Onion Address:'),
m('span', details.hiddenNodeAddress),
]),
details.hiddenNodePort && m('.proxy-row', [
m('label.proxy-label', 'Service Port:'),
m('span', String(details.hiddenNodePort)),
]),
m('.proxy-row', [
m('label.proxy-label', 'Local Port:'),
m('span', String(details.localPort)),
// Onion / I2P Address + Service Port row
m('.nw-config-row', { style: 'display: grid; grid-template-columns: 200px 1fr; gap: 1rem; align-items: center;' }, [
m('label', { style: 'font-weight: 600; color: #475569;' }, details.hiddenType === 4 ? 'I2P Address:' : 'Onion Address:'),
m('.addr-port-group', { style: 'display: flex; align-items: center; gap: 0.75rem; flex-wrap: wrap;' }, [
m('input[type=text]', {
style: 'flex: 1; max-width: 480px; min-width: 320px; padding: 0.4rem; border: 1px solid #cbd5e1; border-radius: 4px; background-color: #f8fafc; color: #334155; font-family: monospace;',
readOnly: true,
value: details.hiddenNodeAddress,
}),
details.hiddenNodePort && m('input[type=number]', {
style: 'width: 90px; padding: 0.4rem; border: 1px solid #cbd5e1; border-radius: 4px; background-color: #f8fafc; color: #334155;',
readOnly: true,
value: details.hiddenNodePort,
}),
]),
]),
]),
};
@ -517,20 +645,15 @@ const Component = () => {
});
},
view: () =>
m('.config-network', { style: 'display:flex; flex-direction:column; gap:0.5rem;' }, [
m('.config-network', { style: 'display:flex; flex-direction:column; gap:1rem;' }, [
m('.widget', [
m('.widget__heading', m('h3', 'Network Configuration')),
m('.widget__body', [
m('.grid-2col', [
m(SetNwMode, { isHiddenMode }),
!isHiddenMode && m(SetNAT),
m(displayLocalIPAddress, { details }),
m(displayExternalIPAddress, { details, isHiddenMode }),
!isHiddenMode && m(SetDynamicDNS),
m(SetLimits),
!isHiddenMode && m(SetOpMode),
!isHiddenMode && m(displayIPAddresses, { details }),
]),
m(NetworkConfigForm, { isHiddenMode }),
m('hr', { style: 'margin: 1rem 0; border: none; border-top: 1px solid #e2e8f0;' }),
m(SetLimits),
!isHiddenMode && m(SetOpMode),
!isHiddenMode && m(displayIPAddresses, { details }),
]),
]),
m('.widget', [