fix(dashboard): hard-disable the Central feed_source option (retired backend) (#154)

Central's NATS broker is gone and its database was dropped 2026-07-15, but
the per-adapter Native/Central toggle on the Environment page still let an
operator pick "central" for 11 of 12 adapters and have it save successfully
(config.py's validator still accepts central|native; env/store.py's gate
just silently skips registration when feed_source != "native"). The result:
flip the switch, save cleanly, feed dies with no error anywhere.

This is a minimal stopgap, not the real fix. A separate refactor will strip
feed_source/hasCentral/nativeOnly and the whole toggle out once Central's
removal is complete; that's out of scope here and backend behavior (config
validator, store gate) is intentionally untouched so existing YAML with
feed_source: central doesn't break.

For now: hard-disable the Central button in FeedSourceToggle regardless of
hasCentral/nativeOnly (kept referenced, not deleted, for the pending
refactor), and make the accompanying copy tell the truth — "Central feed
source has been retired — native only" — instead of the old adapter-scoped
"not available for this adapter" text that no longer describes what's
happening.

Verified: GaugeSites.tsx only reads usgs.feed_source to gate its lookup
button, never writes it — not a second instance of this trap. tsc --noEmit
and the pytest suite show zero new failures vs. pre-edit baseline.

Co-authored-by: Matt Johnson <mj@k7zvx.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
malice 2026-07-17 14:07:27 -06:00 committed by GitHub
commit 12e7335add
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -208,7 +208,7 @@ function FeedSourceToggle({ value, onChange, disabled, centralDisabled }: {
<button
type="button"
disabled={disabled || centralDisabled}
title={centralDisabled ? 'Central not available for this adapter' : ''}
title={centralDisabled ? 'Central feed source has been retired — native only' : ''}
onClick={() => { if (!centralDisabled) onChange('central') }}
className={`${base} ${centralDisabled ? 'text-[#666] cursor-not-allowed' : value === 'central' ? 'bg-accent text-white' : 'text-[#777] hover:text-white'}`}
>central</button>
@ -228,7 +228,13 @@ function AdapterPanel({ title, subtitle, enabled, onEnabled, feedSource, onFeedS
/** Called when user toggles include_in_llm_context */
onLlmContext?: (v: boolean) => void
}) {
const centralDisabled = nativeOnly || !hasCentral
// The Central service was retired 2026-07-15 (NATS broker gone, DB dropped) — there is
// nothing left to serve a "central" feed_source for ANY adapter, so the button is
// hard-disabled here regardless of `hasCentral`/`nativeOnly`. Those two stay wired in
// (rather than deleted) because the full removal of feed_source/hasCentral/nativeOnly and
// this whole toggle is a separate, larger refactor still pending; this is just the stopgap
// that keeps operators from picking a feed source that silently stops working.
const centralDisabled = true || nativeOnly || !hasCentral
return (
<div className="border border-border p-4 space-y-3">
<div className="flex items-center justify-between">
@ -260,8 +266,8 @@ function AdapterPanel({ title, subtitle, enabled, onEnabled, feedSource, onFeedS
API key required set it in the field below
</div>
)}
{nativeOnly && (
<div className="text-[11px] text-[#666]">Central not available for this adapter native only</div>
{centralDisabled && (
<div className="text-[11px] text-[#666]">Central feed source has been retired native only</div>
)}
<div className={enabled ? 'space-y-3' : 'space-y-3 opacity-40 pointer-events-none select-none'}>
{children}