feat(plugins): 插件「管理面板声明」库——声明模型 + 闭集校验 + catalog(design/09 §5.2/§5.2.1)
纯库、零接线:不碰 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」打不红,正是因为全序与算法无关;这不是测试虚护。)
This commit is contained in:
1 parent
6e28b38b08
commit
c9144c1096
19 files changed
+3053
No files matched your search
@@ -0,0 +1,80 @@
|
||||
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"`
|
||||
}
|
||||
Reference in new issue
Block a user