)
@@ -248,13 +255,18 @@ export default function GenericSources() {
return (
- {/* Page description + action bar */}
+ {/* Section description + action bar */}
Point MeshAI at any public REST or GeoJSON feed — no code. Each source polls a URL,
maps its JSON fields to an event via dotted paths, and broadcasts through the normal
coverage-gated pipeline. Use Preview to fetch a
- URL and read its structure before filling in the paths.
+ URL and read its structure before filling in the paths. Once saved, a custom source
+ becomes a routable family —{' '}
+
+ enable its family in Notifications
+ {' '}
+ to route it to a channel.
{hasChanges && actionButtons}
@@ -264,7 +276,7 @@ export default function GenericSources() {
{sources.length === 0 && (
- No data sources yet. Click “Add source” to wire up a public feed.
+ No custom sources yet. Click “Add source” to wire up a public feed.
)}
diff --git a/work/dashboard-frontend/src/components/Layout.tsx b/work/dashboard-frontend/src/components/Layout.tsx
index 40740ff..cdd9885 100644
--- a/work/dashboard-frontend/src/components/Layout.tsx
+++ b/work/dashboard-frontend/src/components/Layout.tsx
@@ -50,7 +50,6 @@ const navGroups: NavGroup[] = [
{ path: '/', label: 'Dashboard', icon: LayoutDashboard },
{ path: '/config', label: 'Settings', icon: Settings },
{ path: '/environment', label: 'Data Feeds', icon: Cloud },
- { path: '/data-sources', label: 'Data Sources', icon: Layers },
{ path: '/activity', label: 'Activity Log', icon: Activity },
{ path: '/places', label: 'Places', icon: MapPin },
{ path: '/coverage', label: 'Coverage', icon: Map },
diff --git a/work/dashboard-frontend/src/pages/Environment.tsx b/work/dashboard-frontend/src/pages/Environment.tsx
index 689b482..4c69a7d 100644
--- a/work/dashboard-frontend/src/pages/Environment.tsx
+++ b/work/dashboard-frontend/src/pages/Environment.tsx
@@ -15,6 +15,7 @@ import {
import { TOGGLE_FAMILY_META, type NotificationToggle, type NotificationsConfig } from './Notifications'
import AdapterConfig, { CURATED_KEYS } from './AdapterConfig'
import { ManagedSecret } from '@/components/ManagedSecret'
+import GenericSourcesEditor from '@/components/GenericSourcesEditor'
type FeedSource = 'native' | 'central'
@@ -1893,6 +1894,20 @@ const save = async () => {
>
)}
+ {/* ── Custom Sources — generic no-code feeds, first-class data feeds ───── */}
+
+
+
+ Custom Sources
+
+
+ Point MeshAI at any public REST/GeoJSON feed; it becomes a routable family in
+ Notifications — sitting alongside the built-in feeds above.
+
+
+
+
+
{/* ── Advanced: Geocoder — infra, not a feed ──────────────────────────── */}