mirror of
https://github.com/kennethnym/aris.git
synced 2026-04-15 22:31:19 +01:00
feat: add CalDAV source config to admin dashboard (#112)
Add source definition for aelis.caldav with server URL, username, password, look-ahead days, and timezone fields. Route per-user credentials through /api/sources/:id/credentials instead of the admin provider config endpoint, controlled by a perUserCredentials flag on the source definition. Co-authored-by: Ona <no-reply@ona.com>
This commit is contained in:
@@ -20,7 +20,13 @@ import {
|
|||||||
import { Separator } from "@/components/ui/separator"
|
import { Separator } from "@/components/ui/separator"
|
||||||
import { Switch } from "@/components/ui/switch"
|
import { Switch } from "@/components/ui/switch"
|
||||||
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip"
|
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip"
|
||||||
import { fetchSourceConfig, pushLocation, replaceSource, updateProviderConfig } from "@/lib/api"
|
import {
|
||||||
|
fetchSourceConfig,
|
||||||
|
pushLocation,
|
||||||
|
replaceSource,
|
||||||
|
updateProviderConfig,
|
||||||
|
updateSourceCredentials,
|
||||||
|
} from "@/lib/api"
|
||||||
|
|
||||||
interface SourceConfigPanelProps {
|
interface SourceConfigPanelProps {
|
||||||
source: SourceDefinition
|
source: SourceDefinition
|
||||||
@@ -83,7 +89,11 @@ export function SourceConfigPanel({ source, onUpdate }: SourceConfigPanelProps)
|
|||||||
(v) => typeof v === "string" && v.length > 0,
|
(v) => typeof v === "string" && v.length > 0,
|
||||||
)
|
)
|
||||||
if (hasCredentials) {
|
if (hasCredentials) {
|
||||||
promises.push(updateProviderConfig(source.id, { credentials: credentialFields }))
|
if (source.perUserCredentials) {
|
||||||
|
promises.push(updateSourceCredentials(source.id, credentialFields))
|
||||||
|
} else {
|
||||||
|
promises.push(updateProviderConfig(source.id, { credentials: credentialFields }))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await Promise.all(promises)
|
await Promise.all(promises)
|
||||||
|
|||||||
@@ -23,6 +23,8 @@ export interface SourceDefinition {
|
|||||||
name: string
|
name: string
|
||||||
description: string
|
description: string
|
||||||
alwaysEnabled?: boolean
|
alwaysEnabled?: boolean
|
||||||
|
/** When true, secret fields are stored as per-user credentials via /api/sources/:id/credentials. */
|
||||||
|
perUserCredentials?: boolean
|
||||||
fields: Record<string, ConfigFieldDef>
|
fields: Record<string, ConfigFieldDef>
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -78,6 +80,44 @@ const sourceDefinitions: SourceDefinition[] = [
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: "aelis.caldav",
|
||||||
|
name: "CalDAV",
|
||||||
|
description: "Calendar events from any CalDAV server (Nextcloud, Radicale, Baikal, etc.).",
|
||||||
|
perUserCredentials: true,
|
||||||
|
fields: {
|
||||||
|
serverUrl: {
|
||||||
|
type: "string",
|
||||||
|
label: "Server URL",
|
||||||
|
required: true,
|
||||||
|
secret: false,
|
||||||
|
description: "CalDAV server URL (e.g. https://nextcloud.example.com/remote.php/dav)",
|
||||||
|
},
|
||||||
|
username: {
|
||||||
|
type: "string",
|
||||||
|
label: "Username",
|
||||||
|
required: true,
|
||||||
|
secret: false,
|
||||||
|
},
|
||||||
|
password: {
|
||||||
|
type: "string",
|
||||||
|
label: "Password",
|
||||||
|
required: true,
|
||||||
|
secret: true,
|
||||||
|
},
|
||||||
|
lookAheadDays: {
|
||||||
|
type: "number",
|
||||||
|
label: "Look-ahead Days",
|
||||||
|
defaultValue: 0,
|
||||||
|
description: "Number of additional days beyond today to fetch events for",
|
||||||
|
},
|
||||||
|
timeZone: {
|
||||||
|
type: "string",
|
||||||
|
label: "Timezone",
|
||||||
|
description: "IANA timezone for determining \"today\" (e.g. Europe/London). Defaults to UTC.",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: "aelis.tfl",
|
id: "aelis.tfl",
|
||||||
name: "TfL",
|
name: "TfL",
|
||||||
@@ -164,6 +204,22 @@ export async function updateProviderConfig(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function updateSourceCredentials(
|
||||||
|
sourceId: string,
|
||||||
|
credentials: Record<string, unknown>,
|
||||||
|
): Promise<void> {
|
||||||
|
const res = await fetch(`${serverBase()}/sources/${sourceId}/credentials`, {
|
||||||
|
method: "PUT",
|
||||||
|
headers: { "Content-Type": "application/json" },
|
||||||
|
credentials: "include",
|
||||||
|
body: JSON.stringify(credentials),
|
||||||
|
})
|
||||||
|
if (!res.ok) {
|
||||||
|
const data = (await res.json()) as { error?: string }
|
||||||
|
throw new Error(data.error ?? `Failed to update credentials: ${res.status}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export interface LocationInput {
|
export interface LocationInput {
|
||||||
lat: number
|
lat: number
|
||||||
lng: number
|
lng: number
|
||||||
|
|||||||
Reference in New Issue
Block a user