import { Alert, Badge, Checkbox, Group, PasswordInput, Select, Stack, Text, TextInput } from "@mantine/core"; import { IconCheck, IconKey, IconServer, IconX } from "@tabler/icons-react"; import type { CustomWidgetSecretKind, CustomWidgetSource, CustomWidgetSourceSetup, CustomWidgetSourceUrlIssue, } from "../core"; import { getCustomWidgetSourceSetupIssue } from "../core"; export interface CustomWidgetSourceSetupValue { baseUrl: string; networkScope: CustomWidgetSource["networkScope"]; urlConfirmed: boolean; secrets: Partial>; } export interface CustomWidgetSourceSetupMessages { title: string; description: string; suggestedUrl: string; baseUrl: string; networkScope: string; authentication: string; confirmUrl: string; ready: string; needsUrl: string; credentialsMissing: string; credentialsOptional: string; configured: string; secret(kind: CustomWidgetSecretKind): string; urlError(issue: CustomWidgetSourceUrlIssue): string; } export interface CustomWidgetSourceSetupPanelProps { setups: CustomWidgetSourceSetup[]; values: Record; messages: CustomWidgetSourceSetupMessages; onChange(sourceId: string, value: CustomWidgetSourceSetupValue): void; } export function createCustomWidgetSourceSetupValues( setups: readonly CustomWidgetSourceSetup[], ): Record { return Object.fromEntries( setups.map((setup) => [ setup.sourceId, { baseUrl: setup.baseUrl, networkScope: setup.networkScope, urlConfirmed: !setup.requiresUrlConfirmation, secrets: {} as Partial>, } satisfies CustomWidgetSourceSetupValue, ]), ); } export function isCustomWidgetSourceSetupReady( setups: readonly CustomWidgetSourceSetup[], values: Record, ) { return setups.every((setup) => { const value = values[setup.sourceId]; return Boolean(value && !getCustomWidgetSourceSetupIssue(value) && value.urlConfirmed); }); } export function CustomWidgetSourceSetupPanel({ setups, values, messages, onChange, }: CustomWidgetSourceSetupPanelProps) { if (setups.length === 0) return null; return ( }> {messages.title} {messages.description} {setups.map((setup) => { const value = values[setup.sourceId] ?? createCustomWidgetSourceSetupValues([setup])[setup.sourceId]; if (!value) return null; const issue = getCustomWidgetSourceSetupIssue(value); const missingCredentials = setup.credentialFields.filter( (field) => !field.configured && !value.secrets[field.kind]?.trim(), ); const urlReady = !issue && value.urlConfirmed; return (
{setup.sourceName} {setup.sourceId}
: } > {urlReady ? messages.ready : messages.needsUrl} {missingCredentials.length > 0 && ( }> {messages.credentialsMissing} )}
{messages.suggestedUrl}: {setup.suggestedBaseUrl} onChange(setup.sourceId, { ...value, baseUrl: event.currentTarget.value, urlConfirmed: true }) } /> } autoComplete="off" onChange={(event) => onChange(setup.sourceId, { ...value, secrets: { ...value.secrets, [field.kind]: event.currentTarget.value }, }) } /> ); })} {missingCredentials.length > 0 && ( {messages.credentialsOptional} )}
); })}
); }