{ "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "ai-endpoint-editor", "title": "AI Endpoint Editor", "description": "Controlled canonical Endpoint editor for Provider ownership, API connection, credentials, routing, tags, and extensions", "dependencies": ["@wener/ai@^0.1.21", "daisyui"], "registryDependencies": ["https://ui-components.wener.me/r/ai-config-editor.json"], "files": [ { "path": "registry/default/blocks/ai-endpoint-editor/ai-endpoint-editor-types.ts", "content": "import type { Endpoint } from '@wener/ai/schema';\nimport type { ComponentPropsWithRef } from 'react';\nimport type {\n\tAiConfigEditorOption,\n\tAiConfigEditorSlots,\n\tAiConfigSchema,\n\tAiConfigValidationMode,\n\tAiResourceEditorMessageOverrides,\n\tAiResourceEditorMessages,\n} from '../../ui/ai-config-editor';\n\nexport type AiEndpointEditorField =\n\t| 'id'\n\t| 'name'\n\t| 'providerId'\n\t| 'key'\n\t| 'title'\n\t| 'description'\n\t| 'apiType'\n\t| 'baseUrl'\n\t| 'apiKey'\n\t| 'headers'\n\t| 'env'\n\t| 'credentials'\n\t| 'proxy'\n\t| 'proxyMode'\n\t| 'capabilities'\n\t| 'tags'\n\t| 'labels'\n\t| 'options'\n\t| 'extensions'\n\t| 'enabled';\nexport type AiEndpointEditorSection = 'identity' | 'connection' | 'routing' | 'metadata';\nexport type AiEndpointEditorMessages = AiResourceEditorMessages;\nexport type AiEndpointEditorMessageOverrides = AiResourceEditorMessageOverrides<\n\tAiEndpointEditorField,\n\tAiEndpointEditorSection\n>;\n\nexport type AiEndpointEditorProps = Omit, 'onChange' | 'title'> & {\n\tvalue: Endpoint;\n\tonChange: (value: Endpoint) => void;\n\tonSubmit?: (value: Endpoint) => void;\n\tschema?: AiConfigSchema;\n\tvalidationMode?: AiConfigValidationMode;\n\tdisabled?: boolean;\n\treadOnly?: boolean;\n\tmessages?: AiEndpointEditorMessageOverrides;\n\tslots?: AiConfigEditorSlots;\n\tproviderOptions?: readonly AiConfigEditorOption[];\n\tapiTypeOptions?: readonly AiConfigEditorOption[];\n};\n", "type": "registry:lib", "target": "@components/blocks/ai-endpoint-editor/ai-endpoint-editor-types.ts" }, { "path": "registry/default/blocks/ai-endpoint-editor/ai-endpoint-editor.tsx", "content": "'use client';\n\nimport { DefaultApiRegistry, type Endpoint, EndpointSchema } from '@wener/ai/schema';\nimport type { ReactNode } from 'react';\nimport {\n\tAiConfigEditor,\n\tAiConfigFieldGrid,\n\tAiConfigFieldSlot,\n\tAiConfigFormSection,\n\tAiConfigKeyValueField,\n\tAiConfigSecretField,\n\tAiConfigSelectField,\n\tAiConfigStringListField,\n\tAiConfigTextareaField,\n\tAiConfigTextField,\n\tAiConfigToggleField,\n\taiConfigFieldError,\n\tJsonValueEditor,\n\tmergeResourceEditorMessages,\n\tuseAiConfigDraft,\n} from '../../ui/ai-config-editor';\nimport type {\n\tAiEndpointEditorField,\n\tAiEndpointEditorMessages,\n\tAiEndpointEditorProps,\n} from './ai-endpoint-editor-types';\n\nexport const defaultAiEndpoint: Endpoint = EndpointSchema.parse({\n\tid: 'endpoint-new',\n\tname: 'endpoint-new',\n\tenabled: true,\n});\n\nconst defaultApiTypeOptions = DefaultApiRegistry.apiTypes.map((apiType) => ({\n\tvalue: apiType.name,\n\tlabel: apiType.name,\n\tdescription: apiType.family.name,\n}));\n\nconst defaultMessages: AiEndpointEditorMessages = {\n\ttitle: 'AI Endpoint 配置',\n\tdescription: '编辑独立 Endpoint 的归属、连接、凭据、路由能力和扩展配置。',\n\tsections: {\n\t\tidentity: '身份与归属',\n\t\tconnection: '连接与凭据',\n\t\trouting: '路由与能力',\n\t\tmetadata: '元数据与扩展',\n\t},\n\tfields: {\n\t\tid: 'ID',\n\t\tname: '名称',\n\t\tproviderId: 'Provider 归属',\n\t\tkey: 'Endpoint Key',\n\t\ttitle: '显示名称',\n\t\tdescription: '描述',\n\t\tapiType: 'API 类型',\n\t\tbaseUrl: 'Base URL',\n\t\tapiKey: 'API Key',\n\t\theaders: '请求头',\n\t\tenv: '环境变量值',\n\t\tcredentials: 'Credentials',\n\t\tproxy: '启用代理',\n\t\tproxyMode: '代理模式',\n\t\tcapabilities: '能力',\n\t\ttags: '标签',\n\t\tlabels: 'Labels',\n\t\toptions: 'Options',\n\t\textensions: 'Extensions',\n\t\tenabled: '启用 Endpoint',\n\t},\n};\n\nexport function AiEndpointEditor({\n\tvalue,\n\tonChange,\n\tonSubmit,\n\tschema = EndpointSchema,\n\tvalidationMode,\n\tdisabled = false,\n\treadOnly = false,\n\tmessages: messageOverrides,\n\tslots,\n\tproviderOptions = [],\n\tapiTypeOptions = defaultApiTypeOptions,\n\t...props\n}: AiEndpointEditorProps) {\n\tconst messages = mergeResourceEditorMessages(defaultMessages, messageOverrides);\n\tconst controller = useAiConfigDraft({\n\t\tvalue,\n\t\tfallbackValue: defaultAiEndpoint,\n\t\tschema,\n\t\tonChange,\n\t\tonSubmit,\n\t\tvalidationMode,\n\t});\n\tconst draft = controller.draft;\n\tconst locked = disabled || readOnly;\n\tconst patch = (next: Partial) => controller.setDraft({ ...draft, ...next });\n\tconst field = (name: AiEndpointEditorField, defaultField: ReactNode) => (\n\t\t\n\t);\n\treturn (\n\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\t{field(\n\t\t\t\t\t\t'id',\n\t\t\t\t\t\t patch({ id })}\n\t\t\t\t\t\t/>,\n\t\t\t\t\t)}\n\t\t\t\t\t{field(\n\t\t\t\t\t\t'name',\n\t\t\t\t\t\t patch({ name })}\n\t\t\t\t\t\t/>,\n\t\t\t\t\t)}\n\t\t\t\t\t{field(\n\t\t\t\t\t\t'title',\n\t\t\t\t\t\t patch({ title: optional(title) })}\n\t\t\t\t\t\t/>,\n\t\t\t\t\t)}\n\t\t\t\t\t{field(\n\t\t\t\t\t\t'key',\n\t\t\t\t\t\t patch({ key: optional(key) })}\n\t\t\t\t\t\t/>,\n\t\t\t\t\t)}\n\t\t\t\t\t{field(\n\t\t\t\t\t\t'providerId',\n\t\t\t\t\t\t patch({ providerId: optional(providerId) })}\n\t\t\t\t\t\t/>,\n\t\t\t\t\t)}\n\t\t\t\t\n\t\t\t\t{field(\n\t\t\t\t\t'description',\n\t\t\t\t\t patch({ description: optional(description) })}\n\t\t\t\t\t/>,\n\t\t\t\t)}\n\t\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\t{field(\n\t\t\t\t\t\t'apiType',\n\t\t\t\t\t\t patch({ apiType: optional(apiType) })}\n\t\t\t\t\t\t/>,\n\t\t\t\t\t)}\n\t\t\t\t\t{field(\n\t\t\t\t\t\t'baseUrl',\n\t\t\t\t\t\t patch({ baseUrl: optional(baseUrl) })}\n\t\t\t\t\t\t/>,\n\t\t\t\t\t)}\n\t\t\t\t\n\t\t\t\t{field(\n\t\t\t\t\t'apiKey',\n\t\t\t\t\t patch({ apiKey: optional(apiKey) })}\n\t\t\t\t\t/>,\n\t\t\t\t)}\n\t\t\t\t
\n\t\t\t\t\t{field(\n\t\t\t\t\t\t'headers',\n\t\t\t\t\t\t patch({ headers })}\n\t\t\t\t\t\t/>,\n\t\t\t\t\t)}\n\t\t\t\t\t{field(\n\t\t\t\t\t\t'env',\n\t\t\t\t\t\t patch({ env })}\n\t\t\t\t\t\t/>,\n\t\t\t\t\t)}\n\t\t\t\t
\n\t\t\t\t{field(\n\t\t\t\t\t'credentials',\n\t\t\t\t\t patch({ credentials: credentials as Endpoint['credentials'] })}\n\t\t\t\t\t/>,\n\t\t\t\t)}\n\t\t\t
\n\t\t\t\n\t\t\t\t\n\t\t\t\t\t{field(\n\t\t\t\t\t\t'proxyMode',\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tpatch({ proxyMode: proxyMode ? (proxyMode as Endpoint['proxyMode']) : undefined })\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t/>,\n\t\t\t\t\t)}\n\t\t\t\t\t{field(\n\t\t\t\t\t\t'proxy',\n\t\t\t\t\t\t patch({ proxy })}\n\t\t\t\t\t\t/>,\n\t\t\t\t\t)}\n\t\t\t\t\n\t\t\t\t{field(\n\t\t\t\t\t'capabilities',\n\t\t\t\t\t patch({ capabilities })}\n\t\t\t\t\t/>,\n\t\t\t\t)}\n\t\t\t\n\t\t\t\n\t\t\t\t
\n\t\t\t\t\t{field(\n\t\t\t\t\t\t'tags',\n\t\t\t\t\t\t patch({ tags })}\n\t\t\t\t\t\t/>,\n\t\t\t\t\t)}\n\t\t\t\t\t{field(\n\t\t\t\t\t\t'labels',\n\t\t\t\t\t\t patch({ labels })}\n\t\t\t\t\t\t/>,\n\t\t\t\t\t)}\n\t\t\t\t
\n\t\t\t\t
\n\t\t\t\t\t{field(\n\t\t\t\t\t\t'options',\n\t\t\t\t\t\t patch({ options: options as Endpoint['options'] })}\n\t\t\t\t\t\t/>,\n\t\t\t\t\t)}\n\t\t\t\t\t{field(\n\t\t\t\t\t\t'extensions',\n\t\t\t\t\t\t patch({ extensions: extensions as Endpoint['extensions'] })}\n\t\t\t\t\t\t/>,\n\t\t\t\t\t)}\n\t\t\t\t
\n\t\t\t\t{field(\n\t\t\t\t\t'enabled',\n\t\t\t\t\t patch({ enabled })}\n\t\t\t\t\t/>,\n\t\t\t\t)}\n\t\t\t
\n\t\t\n\t);\n}\n\nfunction optional(value: string): string | undefined {\n\treturn value.trim() ? value : undefined;\n}\n", "type": "registry:component", "target": "@components/blocks/ai-endpoint-editor/ai-endpoint-editor.tsx" }, { "path": "registry/default/blocks/ai-endpoint-editor/index.ts", "content": "export * from './ai-endpoint-editor';\nexport * from './ai-endpoint-editor-types';\n", "type": "registry:component", "target": "@components/blocks/ai-endpoint-editor/index.ts" } ], "type": "registry:block" }