refactor(sat): one satellite list, and out of Hardware
Settings ▸ Lists ▸ Satellites is gone. It was a text box an operator typed their birds into by hand, and it had nothing to do with the satellites the tracker knew: the same station kept two lists of the same satellites and they drifted apart. The SAT_NAME box on the entry form now offers the followed set — or every satellite with a frequency plan when none is followed — merged with whatever that old list still holds, read and never written, because what it holds is somebody's past work. And the satellite section moved out of Hardware, which it never was. Which birds you chase, where your antenna stands and how old your elements are is operating; the rotator inside it is the only hardware there, and one block does not make a section a device.
This commit is contained in:
@@ -214,7 +214,6 @@ type SectionId =
|
||||
| 'lookup'
|
||||
| 'lists-bands'
|
||||
| 'lists-modes'
|
||||
| 'lists-satellites'
|
||||
| 'cluster'
|
||||
| 'dxhunter'
|
||||
| 'backup'
|
||||
@@ -297,7 +296,6 @@ function buildTree(flexAvailable: boolean, t: (k: string) => string): TreeNode[]
|
||||
const hardware: TreeNode[] = [
|
||||
{ kind: 'item', label: t('sec.cat'), id: 'cat' },
|
||||
{ kind: 'item', label: t('sec.rotator'), id: 'rotator' },
|
||||
{ kind: 'item', label: t('sec.satellite'), id: 'satellite' },
|
||||
{ kind: 'item', label: t('sec.winkeyer'), id: 'winkeyer' },
|
||||
{ kind: 'item', label: t('sec.antenna'), id: 'antenna' },
|
||||
{ kind: 'item', label: t('sec.antgenius'), id: 'antgenius', vendor: 'o3a' },
|
||||
@@ -314,6 +312,10 @@ function buildTree(flexAvailable: boolean, t: (k: string) => string): TreeNode[]
|
||||
{ kind: 'item', label: t('sec.station'), id: 'station' },
|
||||
{ kind: 'item', label: t('sec.profiles'), id: 'profiles' },
|
||||
{ kind: 'item', label: t('sec.operating'), id: 'operating' },
|
||||
// Not hardware, whatever the rotator block inside it suggests: which
|
||||
// satellites you chase, where your antenna stands and how old your
|
||||
// elements are is operating, and it sits with the rest of it.
|
||||
{ kind: 'item', label: t('sec.satellite'), id: 'satellite' },
|
||||
{ kind: 'item', label: t('sec.confirmations'), id: 'confirmations' },
|
||||
{ kind: 'item', label: t('sec.awards'), id: 'awards' },
|
||||
{ kind: 'item', label: t('sec.external'), id: 'external-services' },
|
||||
@@ -328,7 +330,6 @@ function buildTree(flexAvailable: boolean, t: (k: string) => string): TreeNode[]
|
||||
{ kind: 'group', label: t('nav.lists'), icon: Database, defaultOpen: true, children: [
|
||||
{ kind: 'item', label: t('sec.bands'), id: 'lists-bands' },
|
||||
{ kind: 'item', label: t('sec.modes'), id: 'lists-modes' },
|
||||
{ kind: 'item', label: t('sec.satellites'), id: 'lists-satellites' },
|
||||
]},
|
||||
{ kind: 'item', label: t('sec.cluster'), id: 'cluster' },
|
||||
{ kind: 'item', label: t('sec.dxhunter'), id: 'dxhunter' },
|
||||
@@ -359,7 +360,7 @@ function buildTree(flexAvailable: boolean, t: (k: string) => string): TreeNode[]
|
||||
// Map section id → i18n key (breadcrumb / placeholders).
|
||||
const SECTION_KEY: Partial<Record<SectionId, string>> = {
|
||||
station: 'sec.station', profiles: 'sec.profiles', operating: 'sec.operating', confirmations: 'sec.confirmations',
|
||||
'external-services': 'sec.external', appearance: 'sec.appearance', lookup: 'sec.lookup', 'lists-bands': 'sec.bands', 'lists-modes': 'sec.modes', 'lists-satellites': 'sec.satellites',
|
||||
'external-services': 'sec.external', appearance: 'sec.appearance', lookup: 'sec.lookup', 'lists-bands': 'sec.bands', 'lists-modes': 'sec.modes',
|
||||
cluster: 'sec.cluster', backup: 'sec.backup', database: 'sec.database', autostart: 'sec.autostart', udp: 'sec.udp',
|
||||
adifmon: 'sec.adifmon',
|
||||
foldersync: 'sec.foldersync',
|
||||
@@ -381,7 +382,6 @@ const SECTION_LABELS: Partial<Record<SectionId, string>> = {
|
||||
lookup: 'Callsign Lookup',
|
||||
'lists-bands': 'Bands',
|
||||
'lists-modes': 'Modes & default RST',
|
||||
'lists-satellites': 'Satellites',
|
||||
cluster: 'DX Cluster',
|
||||
backup: 'Database backup',
|
||||
database: 'Database',
|
||||
@@ -3277,39 +3277,6 @@ function SettingsModalImpl({ onClose, onSaved, initialSection, onMainPaneChanged
|
||||
);
|
||||
}
|
||||
|
||||
function SatellitesPanel() {
|
||||
const sats = lists.satellites ?? [];
|
||||
return (
|
||||
<>
|
||||
<SectionHeader title={t('sec.satellites')} hint={t('sat.hint')} />
|
||||
<div className="space-y-3 max-w-xl">
|
||||
<div className="space-y-1">
|
||||
<Label>{t('sat.listLabel')}</Label>
|
||||
{/* Raw text, one per line, parsed on change — not a row-per-entry
|
||||
editor with add and delete buttons. The list is short, edited
|
||||
twice a year, and usually arrives pasted from a satellite
|
||||
tracker; a textarea takes that paste in one gesture. */}
|
||||
<textarea
|
||||
className="w-full h-56 rounded-md border border-input bg-background p-2 font-mono text-xs"
|
||||
value={sats.join('\n')}
|
||||
placeholder={'AO-7\nAO-91\nRS-44\nSO-50'}
|
||||
onChange={(e) => {
|
||||
const next = e.target.value.split('\n').map((v) => v.trim());
|
||||
setLists((s) => ({ ...s, satellites: next }));
|
||||
}}
|
||||
onBlur={() => setLists((s) => ({
|
||||
// Tidied when the field is LEFT, never while typing: dropping an
|
||||
// empty line as it is typed makes the Enter key look broken.
|
||||
...s,
|
||||
satellites: Array.from(new Set((s.satellites ?? []).map((v) => v.trim().toUpperCase()).filter(Boolean))).sort(),
|
||||
}))}
|
||||
/>
|
||||
<p className="text-xs text-muted-foreground">{t('sat.listHint')}</p>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
function ModesPanel() {
|
||||
const selected = lists.modes ?? [];
|
||||
@@ -8675,7 +8642,6 @@ function SettingsModalImpl({ onClose, onSaved, initialSection, onMainPaneChanged
|
||||
lookup: LookupPanel,
|
||||
'lists-bands': BandsPanel,
|
||||
'lists-modes': ModesPanel,
|
||||
'lists-satellites': SatellitesPanel,
|
||||
cluster: ClusterPanel,
|
||||
dxhunter: DXHunterPanel,
|
||||
udp: UDPIntegrationsPanelWrapper,
|
||||
|
||||
Reference in New Issue
Block a user