feat(plugins): 面板动作执行器接线 —— 动作真可用,不再 501 兜底(L1)
- 插件管理器加生产动作处理器登记面(RegisterActions);未登记处理器/未声明动作仍 404 - web-search 四个动作真读写真源 + 真发 HTTP 探针:plugin.listProviders/saveProvider/ testProvider/reauthProvider(配置落 $DATA_DIR/config/plugins/web-search.json,0600) - 失败回结构化错误码(不含上游原文)+ 审计带 code 字段;501 文案改为「未登记处理器」 - 拆出 panelactions.go(动作索引推导/OptionsActionName/三闸门分发),panels.go 519→347 行 缺口(如实):面板保存后运行中的工具**不热重载**(下一片做);声明面缺 primary/fallback (按 DECISIONS-2026-10-06 #1/#2 补)。
This commit is contained in:
1 parent
a150211468
commit
2e1c3ed3fd
13 files changed
+2043
-204
No files matched your search
@@ -202,7 +202,8 @@ func TestPanels_InvalidPluginIDIsRejectedWholesale(t *testing.T) {
|
||||
}
|
||||
|
||||
// TestPanels_ActionKindsFollowDeclarationSite 锁定读写面由**声明位置**决定:
|
||||
// table/log 的 source 是读来源,form 的 submit 与 table 的 rowActions 是写面。
|
||||
// table/log 的 source 与下拉的 optionsFrom 是读来源,form 的 submit 与 table 的
|
||||
// rowActions 是写面。
|
||||
func TestPanels_ActionKindsFollowDeclarationSite(t *testing.T) {
|
||||
t.Parallel()
|
||||
hub, _ := newTestHub(t)
|
||||
@@ -216,6 +217,9 @@ func TestPanels_ActionKindsFollowDeclarationSite(t *testing.T) {
|
||||
{"plugin.listProviders", ActionRead},
|
||||
{"plugin.saveProvider", ActionWrite},
|
||||
{"plugin.testProvider", ActionWrite},
|
||||
// 下拉候选来源 `plugin:providers` 也进索引(读面):前端按它拉候选,
|
||||
// 宿主不认这个名字,控件就只能降级成文本框。
|
||||
{"plugin.providers", ActionRead},
|
||||
}
|
||||
for _, c := range cases {
|
||||
got, ok := hub.Action("web-search", c.action)
|
||||
@@ -227,11 +231,31 @@ func TestPanels_ActionKindsFollowDeclarationSite(t *testing.T) {
|
||||
t.Fatalf("未声明的动作不得被判为已声明")
|
||||
}
|
||||
if got := hub.DeclaredActions("web-search"); strings.Join(got, ",") !=
|
||||
"plugin.listProviders,plugin.saveProvider,plugin.testProvider" {
|
||||
"plugin.listProviders,plugin.providers,plugin.saveProvider,plugin.testProvider" {
|
||||
t.Fatalf("DeclaredActions = %v", got)
|
||||
}
|
||||
}
|
||||
|
||||
// TestOptionsActionNameMatchesFrontendMapping 锁定 `optionsFrom` → 动作名的映射
|
||||
// 与前端 `resolveOptionsAction` **逐字同源**(前端片 PLG-3 登记的口径):
|
||||
// 两处一旦分叉,声明的下拉就会去调一个宿主不认识的名字。
|
||||
func TestOptionsActionNameMatchesFrontendMapping(t *testing.T) {
|
||||
t.Parallel()
|
||||
cases := map[string]string{
|
||||
"plugin:providers": "plugin.providers",
|
||||
"plugin:search.regions": "plugin.search.regions",
|
||||
" plugin:providers ": "plugin.providers",
|
||||
"plugin:": "",
|
||||
"providers": "",
|
||||
"": "",
|
||||
}
|
||||
for in, want := range cases {
|
||||
if got := OptionsActionName(in); got != want {
|
||||
t.Errorf("OptionsActionName(%q) = %q, want %q", in, got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestPanels_DispatchThreeWayRefusal 锁定分发失败的三种病因各自可判类,
|
||||
// 且执行器只在「已声明 + 已启用 + 已接线」时才被调用。
|
||||
func TestPanels_DispatchThreeWayRefusal(t *testing.T) {
|
||||
@@ -246,23 +270,27 @@ func TestPanels_DispatchThreeWayRefusal(t *testing.T) {
|
||||
t.Fatalf("未声明动作 err = %v,期望 ErrActionNotDeclared", err)
|
||||
}
|
||||
if _, err := hub.Dispatch(context.Background(), req); !errors.Is(err, ErrActionUnavailable) {
|
||||
t.Fatalf("未接线执行器 err = %v,期望 ErrActionUnavailable", err)
|
||||
t.Fatalf("未登记处理器 err = %v,期望 ErrActionUnavailable", err)
|
||||
}
|
||||
|
||||
var seen ActionRequest
|
||||
hub.SetExecutor(func(_ context.Context, r ActionRequest) (any, error) {
|
||||
seen = r
|
||||
return map[string]any{"rows": 1}, nil
|
||||
})
|
||||
if err := hub.RegisterActions("web-search", map[string]ActionHandler{
|
||||
"plugin.listProviders": func(_ context.Context, r ActionRequest) (any, error) {
|
||||
seen = r
|
||||
return map[string]any{"rows": 1}, nil
|
||||
},
|
||||
}); err != nil {
|
||||
t.Fatalf("RegisterActions: %v", err)
|
||||
}
|
||||
out, err := hub.Dispatch(context.Background(), req)
|
||||
if err != nil {
|
||||
t.Fatalf("Dispatch: %v", err)
|
||||
}
|
||||
if seen.PluginID != "web-search" || seen.Action != "plugin.listProviders" {
|
||||
t.Fatalf("执行器收到 %+v", seen)
|
||||
t.Fatalf("处理器收到 %+v", seen)
|
||||
}
|
||||
if m, ok := out.(map[string]any); !ok || m["rows"] != 1 {
|
||||
t.Fatalf("Dispatch 返回 %#v,期望执行器结果原样透传", out)
|
||||
t.Fatalf("Dispatch 返回 %#v,期望处理器结果原样透传", out)
|
||||
}
|
||||
|
||||
hub.SetEnabled("web-search", false)
|
||||
|
||||
Reference in new issue
Block a user