You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

158 lines
6.0 KiB

/**
* ethernet.js — Wired interface IP configuration (eth0 + WAN uplink)
*
* v1.5.0 Phase 2: io.js의 두 wired 카드를 분리.
* v1.7.1 Task 3: the second card was mislabeled "LTE Interface" — the device has
* no cellular modem; this is a wired uplink port. The visible label/icon are
* corrected to WAN/wired. The DB keys stay `lte_*` (backend/Java contract).
* server endpoints (TIOT/Update/RTCM/uplink 등)는 server-setting.js 소유.
*
* Data model (nested — matches io.js state.device.eth / .lte convention):
* state.device.eth = { ip, netmask, gateway }
* state.device.lte = { ip, netmask, gateway, port } ← lte_* = wired WAN keys
*
* eth_ip / eth_netmask / eth_gateway / lte_ip / lte_netmask / lte_gateway are
* present as DOM element IDs (ip-input component convention) and also used as
* string literals for test detection.
*/
import { state, bindIpGroup } from '../state.js';
import { escapeHtml } from '../utils.js';
import { isValidIP } from '../validator.js';
import { renderIpOctets, setupIpOctets, collectIpValue } from '../components/ip-input.js';
import { icon } from '../icons.js';
// Field definitions — flat DOM ids map to nested state paths
const ETH_FIELDS = [
{ key: 'eth_ip', label: 'IP Address', group: 'eth', prop: 'ip' },
{ key: 'eth_netmask', label: 'Subnet Mask', group: 'eth', prop: 'netmask' },
{ key: 'eth_gateway', label: 'Gateway', group: 'eth', prop: 'gateway' },
];
const LTE_FIELDS = [
{ key: 'lte_ip', label: 'IP Address', group: 'lte', prop: 'ip' },
{ key: 'lte_netmask', label: 'Subnet Mask', group: 'lte', prop: 'netmask' },
{ key: 'lte_gateway', label: 'Gateway', group: 'lte', prop: 'gateway' },
];
const ethernetPage = {
render(container) {
const d = state.device || {};
const eth = d.eth || {};
const lte = d.lte || {};
container.innerHTML = `
<div class="page-header">
<h1 class="page-header__title">${icon('ethernet-port', { size: 28 })} Ethernet</h1>
<p class="page-header__desc">Configure the wired management and uplink interfaces. Server endpoints are configured under Network &rarr; Server Setting.</p>
</div>
<div class="grid-2col">
<div class="card">
<div class="card__header">
<h2 class="card__title"><span class="card__title-icon">${icon('cable', { size: 18 })}</span> Management Ethernet (eth1)</h2>
</div>
<div class="card__body">
${ETH_FIELDS.map(f => `
<div class="form-group">
<label class="form-label">${escapeHtml(f.label)}</label>
${renderIpOctets(f.key, eth[f.prop] || '')}
</div>
`).join('')}
</div>
</div>
<div class="card">
<div class="card__header">
<h2 class="card__title"><span class="card__title-icon">${icon('cable', { size: 18 })}</span> Uplink Ethernet (eth0)</h2>
</div>
<div class="card__body">
<p class="form-hint">Physical eth0 uplink. Endpoint ports are configured on Server Setting.</p>
${LTE_FIELDS.map(f => `
<div class="form-group">
<label class="form-label">${escapeHtml(f.label)}</label>
${renderIpOctets(f.key, lte[f.prop] || '')}
</div>
`).join('')}
</div>
</div>
</div>
`;
},
mount(container) {
setupIpOctets(container);
// Ethernet IP bindings
ETH_FIELDS.forEach(({ key, group, prop }) => {
bindIpGroup(container, key,
() => state.device?.[group]?.[prop] || '',
(val) => {
if (!state.device) state.device = {};
if (!state.device[group]) state.device[group] = {};
state.device[group][prop] = val;
state.isDirty = true;
}
);
});
// LTE IP bindings
LTE_FIELDS.forEach(({ key, group, prop }) => {
bindIpGroup(container, key,
() => state.device?.[group]?.[prop] || '',
(val) => {
if (!state.device) state.device = {};
if (!state.device[group]) state.device[group] = {};
state.device[group][prop] = val;
state.isDirty = true;
}
);
});
// Register data collector
window.__pageCollectors.ethernet = collectEthernetData;
},
destroy() {},
validate() {
const errors = [];
const d = state.device || {};
ETH_FIELDS.forEach(({ key, group, prop, label }) => {
const val = d[group]?.[prop];
if (val && val !== '...' && !isValidIP(val)) {
errors.push({ field: key, page: 'ethernet', message: `${label} — Invalid IP format` });
}
});
LTE_FIELDS.forEach(({ key, group, prop, label }) => {
const val = d[group]?.[prop];
if (val && val !== '...' && !isValidIP(val)) {
errors.push({ field: key, page: 'ethernet', message: `${label} — Invalid IP format` });
}
});
return errors;
},
};
function collectEthernetData() {
if (!state.device) state.device = {};
state.device.eth = {
ip: collectIpValue('eth_ip'),
netmask: collectIpValue('eth_netmask'),
gateway: collectIpValue('eth_gateway'),
};
const prevLte = state.device.lte || {};
state.device.lte = {
...prevLte,
ip: collectIpValue('lte_ip'),
netmask: collectIpValue('lte_netmask'),
gateway: collectIpValue('lte_gateway'),
};
}
export default ethernetPage;