纯库、零接线:不碰 gateway/frontend/Docs/.env*(本片刻意不接线,避免与在途切片争用文件面)。 - pkg/plugins/sdk:面板声明类型(JSON tag 与 design/09 §5.2 示例逐字同形); 字段类型与 section 类型都是**闭集**;When 三态 + **严格 UnmarshalJSON**(未知条件键报错, 不静默丢) - internal/capability/paneldecl:闭集校验(47 条拒绝用例,断言的是**分类哨兵 + JSON 路径**, 不是错误字符串)· catalog(并发安全、返回拷贝、按 (group, order, 登记序号) 的**全序**稳定排序)· when 求值(上下文由 Resolver 注入,本包不读环境变量/文件)· 角色过滤(viewer 只留 status/log/table 且摘掉 rowActions,纯写面板整体隐藏;未知角色 fail-closed) - 拒绝粒度:插件 id 非法 ⇒ 整插件拒绝;单个面板非法 ⇒ 只拒该面板 + 聚合显式报错(理由见报告) 【我的验收】隔离 worktree(19 文件)build/vet/linux/darwin 全过、69 包全绿; 我亲手打红变异:把同组同序的回退比较 反成 ⇒ TestCatalog_StableOrder FAIL。 (记录一条观察:比较器已靠 seq 构成全序,故 sort.SliceStable 的稳定性是冗余保护 —— 我第一次用「SliceStable→Slice」打不红,正是因为全序与算法无关;这不是测试虚护。)
81 lines
4.1 KiB
Go
81 lines
4.1 KiB
Go
package sdk
|
|
|
|
// 本文件是 design/09-插件生态 §5.2「字段类型集合(闭集)」在 Go 侧的唯一定义,
|
|
// 以及字段声明本身(form / status 区块的 `fields[]` 元素)。
|
|
|
|
// FieldType 是字段控件类型(闭集,§5.2:不许插件自定义渲染器)。
|
|
//
|
|
// 闭集的意义:每个形状都能复用既有 Miuix 组件(渠道配置那套字段渲染 + 虚拟滚动表格),
|
|
// 因此「插件声明 UI」在无任意代码注入的前提下依然够用 —— 配置类插件 90% 的需求就是
|
|
// 这几个形状。
|
|
type FieldType string
|
|
|
|
const (
|
|
// FieldText 是单行文本(示例 endpoint:接口地址)。
|
|
FieldText FieldType = "text"
|
|
// FieldSecret 是凭据输入(示例 apiKey)。读侧永不回显明文(§5.4.2),因此
|
|
// paneldecl 拒绝它声明默认值。
|
|
FieldSecret FieldType = "secret"
|
|
// FieldNumber 是数值输入(唯一接受 min/max 边界的类型)。
|
|
FieldNumber FieldType = "number"
|
|
// FieldSwitch 是布尔开关。
|
|
FieldSwitch FieldType = "switch"
|
|
// FieldSelect 是单选下拉(选项来自 optionsFrom)。
|
|
FieldSelect FieldType = "select"
|
|
// FieldMultiSelect 是多选下拉(选项来自 optionsFrom)。
|
|
FieldMultiSelect FieldType = "multiSelect"
|
|
// FieldDate 是日期。
|
|
FieldDate FieldType = "date"
|
|
// FieldKV 是键值对(§5.2 的例子:自定义 header)。
|
|
FieldKV FieldType = "kv"
|
|
)
|
|
|
|
// Valid 报告 t 是否属于字段类型闭集。
|
|
func (t FieldType) Valid() bool {
|
|
switch t {
|
|
case FieldText, FieldSecret, FieldNumber, FieldSwitch,
|
|
FieldSelect, FieldMultiSelect, FieldDate, FieldKV:
|
|
return true
|
|
default:
|
|
return false
|
|
}
|
|
}
|
|
|
|
// Sensitive 报告该类型是否承载凭据。§5.4.2 要求读侧永不回显明文(只回「是否已配置」+
|
|
// 尾 4 位或哈希前缀),所以敏感字段不得声明任何默认值 —— 校验在 paneldecl。
|
|
func (t FieldType) Sensitive() bool { return t == FieldSecret }
|
|
|
|
// Numeric 报告该类型是否接受 min/max 数值边界。依据:闭集里只有 number 是数值控件,
|
|
// date 在声明里是日期字符串,用数值边界表达日期范围只会产生歧义。
|
|
func (t FieldType) Numeric() bool { return t == FieldNumber }
|
|
|
|
// PullsOptions 报告该类型是否需要宿主去拉下拉选项。依据:只有 select / multiSelect 会
|
|
// 渲染选项列表,其它类型上的 optionsFrom 是无效声明(会被 paneldecl 拒绝)。
|
|
func (t FieldType) PullsOptions() bool { return t == FieldSelect || t == FieldMultiSelect }
|
|
|
|
// Field 是一个字段声明(§5.2 的 fields 元素,form 与 status 共用)。
|
|
type Field struct {
|
|
// Key 是配置键 / 行字段名,形如 §5.2 示例的 provider / apiKey / endpoint。
|
|
// 它同时是表单的提交键与 status 行的数据键,因此在区块内必须唯一。
|
|
Key string `json:"key"`
|
|
// Label 是字段标签。缺省时宿主回落到 Key(与 Column.Label 同一取舍)。
|
|
Label string `json:"label,omitempty"`
|
|
// Type 决定控件,必须落在闭集内。
|
|
Type FieldType `json:"type"`
|
|
// Required 是**配置值**的必填标记(§5.2 示例的 `"required": true`),不是声明层的
|
|
// 必填 —— 声明层的必填只认 Key 与 Type。
|
|
Required bool `json:"required,omitempty"`
|
|
// Placeholder 是输入提示(示例 `https://...`)。
|
|
Placeholder string `json:"placeholder,omitempty"`
|
|
// OptionsFrom 是下拉选项来源。§5.2 只给了插件内的一种来源(示例 plugin:providers);
|
|
// **只允许 `plugin:` 前缀**,其它一律拒 —— 防「声明里塞任意 URL」。
|
|
OptionsFrom string `json:"optionsFrom,omitempty"`
|
|
// Default 是字段初始值。§5.2 的示例里没有这个键;它按任务书「若你定义了这些可选键」
|
|
// 的口径加入,且对 secret 类型被 paneldecl 硬拒(§5.4.2 读侧无明文)。
|
|
Default any `json:"default,omitempty"`
|
|
// Min 是数值下界,仅 number 类型可声明(§5.2 示例里没有这个键,同上)。
|
|
Min *float64 `json:"min,omitempty"`
|
|
// Max 是数值上界,仅 number 类型可声明,且必须 >= Min。
|
|
Max *float64 `json:"max,omitempty"`
|
|
}
|