Compare commits

..

1 Commits

Author SHA1 Message Date
5b48df2778 feat: register TfL source provider
Co-authored-by: Ona <no-reply@ona.com>
2026-03-29 14:32:00 +00:00
4 changed files with 4 additions and 73 deletions

View File

@@ -408,40 +408,6 @@ function FieldInput({
)
}
if (field.type === "multiselect" && field.options) {
const selected = Array.isArray(value) ? (value as string[]) : []
function toggle(optValue: string) {
const next = selected.includes(optValue)
? selected.filter((v) => v !== optValue)
: [...selected, optValue]
onChange(next)
}
return (
<div className="space-y-2">
<Label className="text-xs font-medium">
{labelContent}
</Label>
<div className="flex flex-wrap gap-1.5">
{field.options!.map((opt) => {
const isSelected = selected.includes(opt.value)
return (
<Badge
key={opt.value}
variant={isSelected ? "default" : "outline"}
className={`cursor-pointer select-none ${isSelected ? "" : "opacity-60 hover:opacity-100"}`}
onClick={() => !disabled && toggle(opt.value)}
>
{opt.label}
</Badge>
)
})}
</div>
</div>
)
}
if (field.type === "number") {
return (
<div className="space-y-2">
@@ -490,8 +456,6 @@ function buildInitialValues(
values[name] = saved[name]
} else if (field.defaultValue !== undefined) {
values[name] = field.defaultValue
} else if (field.type === "multiselect") {
values[name] = []
} else {
values[name] = field.type === "number" ? undefined : ""
}

View File

@@ -9,12 +9,12 @@ function serverBase() {
}
export interface ConfigFieldDef {
type: "string" | "number" | "select" | "multiselect"
type: "string" | "number" | "select"
label: string
required?: boolean
description?: string
secret?: boolean
defaultValue?: string | number | string[]
defaultValue?: string | number
options?: { label: string; value: string }[]
}
@@ -54,39 +54,6 @@ const sourceDefinitions: SourceDefinition[] = [
dailyLimit: { type: "number", label: "Daily Forecast Limit", defaultValue: 7, description: "Number of daily forecasts to include" },
},
},
{
id: "aelis.tfl",
name: "TfL",
description: "Transport for London tube line status alerts.",
fields: {
lines: {
type: "multiselect",
label: "Lines",
description: "Lines to monitor. Leave empty for all lines.",
defaultValue: [],
options: [
{ label: "Bakerloo", value: "bakerloo" },
{ label: "Central", value: "central" },
{ label: "Circle", value: "circle" },
{ label: "District", value: "district" },
{ label: "Hammersmith & City", value: "hammersmith-city" },
{ label: "Jubilee", value: "jubilee" },
{ label: "Metropolitan", value: "metropolitan" },
{ label: "Northern", value: "northern" },
{ label: "Piccadilly", value: "piccadilly" },
{ label: "Victoria", value: "victoria" },
{ label: "Waterloo & City", value: "waterloo-city" },
{ label: "Lioness", value: "lioness" },
{ label: "Mildmay", value: "mildmay" },
{ label: "Windrush", value: "windrush" },
{ label: "Weaver", value: "weaver" },
{ label: "Suffragette", value: "suffragette" },
{ label: "Liberty", value: "liberty" },
{ label: "Elizabeth", value: "elizabeth" },
],
},
},
},
]
export function fetchSources(): Promise<SourceDefinition[]> {

View File

@@ -6,7 +6,6 @@ import {
CircleDot,
CloudSun,
Loader2,
TrainFront,
LogOut,
MapPin,
Rss,
@@ -42,7 +41,6 @@ const SOURCE_ICONS: Record<string, React.ComponentType<{ className?: string }>>
"aelis.weather": CloudSun,
"aelis.caldav": CalendarDays,
"aelis.google-calendar": Calendar,
"aelis.tfl": TrainFront,
}
export const Route = createRoute({

View File

@@ -14,6 +14,7 @@ import { registerLocationHttpHandlers } from "./location/http.ts"
import { LocationSourceProvider } from "./location/provider.ts"
import { UserSessionManager } from "./session/index.ts"
import { registerSourcesHttpHandlers } from "./sources/http.ts"
import { TflSourceProvider } from "./tfl/provider.ts"
import { WeatherSourceProvider } from "./weather/provider.ts"
function main() {
@@ -45,6 +46,7 @@ function main() {
serviceId: process.env.WEATHERKIT_SERVICE_ID!,
},
}),
new TflSourceProvider({ apiKey: process.env.TFL_API_KEY! }),
],
feedEnhancer,
})