Unified endpoint config type: one Host/IP : Port control in admin
New configSchema type 'endpoint' declared in the module spec: anything
that points at a device or service on the network must be one endpoint
field, rendered identically for every module in /admin as a joined
Host/IP : Port control and stored/handed to the module server as
{ host, port }. Migrates all three connection modules — ProdCom (was a
full URL field), ProPresenter and Timers (were separate host + port
fields). Legacy stored configs (prodcomUrl / flat host+port) keep
working until the admin form is re-saved, at which point the new shape
replaces them. MODULE-GUIDE documents the type and the presentation
rule: no split host/port fields, and full URLs only for genuine web
addresses.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RNYUv9EyrGSFmCnmH7WYKH
This commit is contained in:
@@ -93,6 +93,12 @@ body { overflow: auto; }
|
||||
|
||||
.module-form { margin-top: 12px; border-top: 1px solid var(--border); padding-top: 12px; }
|
||||
.module-form .field { max-width: 420px; }
|
||||
|
||||
/* endpoint fields: every module's upstream is entered the same way */
|
||||
.field .endpoint-row { display: flex; align-items: center; gap: 7px; }
|
||||
.endpoint-row .ep-host { flex: 1; min-width: 0; }
|
||||
.endpoint-row .ep-port { width: 92px; flex: none; }
|
||||
.endpoint-row .ep-sep { color: var(--muted); font-weight: 600; }
|
||||
.module-form-empty { color: var(--muted); font-size: 12px; margin-top: 10px; }
|
||||
|
||||
.module-actions {
|
||||
|
||||
@@ -96,6 +96,32 @@ function fieldFor(key, spec, value, passwordSet) {
|
||||
input.checked = Boolean(value);
|
||||
field.append(input, document.createTextNode(label));
|
||||
read = () => input.checked;
|
||||
} else if (type === 'endpoint') {
|
||||
// One consistent "Host / IP : Port" control for every module's upstream.
|
||||
const span = document.createElement('span');
|
||||
span.textContent = label;
|
||||
const row = document.createElement('span');
|
||||
row.className = 'endpoint-row';
|
||||
const host = document.createElement('input');
|
||||
host.type = 'text';
|
||||
host.className = 'ep-host';
|
||||
host.placeholder = 'Host / IP';
|
||||
host.autocomplete = 'off';
|
||||
host.spellcheck = false;
|
||||
host.value = value?.host ? String(value.host) : '';
|
||||
const sep = document.createElement('span');
|
||||
sep.className = 'ep-sep';
|
||||
sep.textContent = ':';
|
||||
const port = document.createElement('input');
|
||||
port.type = 'number';
|
||||
port.className = 'ep-port';
|
||||
port.placeholder = 'Port';
|
||||
port.min = '1';
|
||||
port.max = '65535';
|
||||
port.value = value?.port ? String(value.port) : '';
|
||||
row.append(host, sep, port);
|
||||
field.append(span, row);
|
||||
read = () => ({ host: host.value.trim(), port: Number(port.value) || 0 });
|
||||
} else if (type === 'select' && Array.isArray(spec.options)) {
|
||||
const span = document.createElement('span');
|
||||
span.textContent = label;
|
||||
|
||||
Reference in New Issue
Block a user