+ {tab === 'general' &&
updateNested('service', { name })} help="A friendly name for this installation." /> undefined} disabled help="The registry identity cannot be changed from a device profile." />
Hardware profile {String(value.hardware?.profile || model)} is managed by the selected model.
}
+
+ {tab === 'connections' &&
{ const id = uniqueId('server', Object.keys(connections)); update({ connections: { ...connections, [id]: { name: 'New server', host: '', port: 64738, username: '', autoTrustServerCertificate: true } } }); }}> Add server}>{connectionEntries.map(([id, connection], index) =>
SERVER {index + 1}{id}
updateConnection(id, { name })} placeholder="Operations server" /> updateConnection(id, { host })} placeholder="voice.example.org" /> updateConnection(id, { port })} min={1} max={65535} /> updateConnection(id, { username })} /> setVisibleSecrets((state) => ({ ...state, [`server:${id}`]: !state[`server:${id}`] }))} onChange={(password) => updateConnection(id, { password })} /> updateConnection(id, { serverCertificateSha256 })} help="Leave blank to use the server trust policy." />
updateConnection(id, { autoTrustServerCertificate })} />)}
}
+
+ {tab === 'channels' &&
{ const id = uniqueId('channel', channels.map((channel) => channel.id)); const firstConnection = Object.keys(connections)[0] || 'server-1'; const next = [...channels, { id, label: 'New channel', alias: '', connectionId: firstConnection, path: '/', access: { mode: 'none' as const } }]; update({ channels: next }); }}> Add channel}>RADIO DEFAULTDefault channel
radio.defaultChannel is used for first connection or when the saved channel no longer exists. A valid last-selected channel still resumes after restart or reconnect.{channels.map((channel, index) =>
CHANNEL {index + 1}{channel.alias || channel.label || channel.id}
{value.radio?.defaultChannel === channel.id ? Default : }
updateChannel(index, { alias })} placeholder="Dispatch" help="Short name displayed prominently on Minimum." /> updateChannel(index, { label })} placeholder="Operations" /> updateChannel(index, { path: path.startsWith('/') ? path : `/${path}` })} placeholder="/PUBLIC/MAIN" /> updateChannel(index, { presetKey: presetKey.toUpperCase() })} placeholder="P1" help="Physical channel shortcut, such as P1 or P2." />{channel.access?.mode === 'public' && setVisibleSecrets((state) => ({ ...state, [`channel:${channel.id}`]: !state[`channel:${channel.id}`] }))} onChange={(token) => updateChannel(index, { access: { mode: 'public', token } })} help="Stored in this private device config and sent only to the selected server." />}
)}
}
+
+ {tab === 'behavior' &&
updateNested('radio', { autoConnect })} help="Connect to the saved channel when Minimum starts." /> updateNested('radio', { autoReconnect })} help="Use the backoff policy after a network interruption." /> updateNested('ptt', { allowScreenOff })} help="Keep PTT available while the display is off." />
updateNested('ptt', { maximumTxSeconds })} min={1} max={120} help="The service releases PTT when this limit is reached." />
Network-loss PTT release is always enabled for safety.
}
+
+ {tab === 'tracking' &&
{{value.hardware?.locationTrackingSupported ? `Location service available for ${model.toUpperCase()}` : `Location tracking is not available on ${model.toUpperCase()}`}
} updateNested('tracking', { enabled })} help="Publish health and position only when the hardware reports a fix." /> updateNested('tracking', { pttTriggered })} />
setVisibleSecrets((state) => ({ ...state, aprs: !state.aprs }))} onChange={updateNested} />}
+
+ {tab === 'advanced' &&
Manual JSON is validated when you apply it. Credentials and tokens remain hidden elsewhere in the console.
{advancedError && {advancedError}
}Applying JSON replaces the form values.
}
+