feat: 渠道管理分两块(.env必要回退+删除同步+可用类型/已保存分开)
agent-120 .env只留必要回退: - .env.example KOOK移4可选业务字段(RECEIVE_MODE/WEBHOOK_PATH/VERIFY_TOKEN/ENCRYPT_KEY),只留token/base_url; channelAccountsFromEnv不读这4个; 说明业务字段走channelConfigForm.channels.json - 黑名单/限流/receive_mode等走管理面板热更新, env仅必要连接回退 agent-121 删除渠道列表同步(根因: adminListChannels枚举caps,删除不同步caps): - adminListChannels 以channels.json为准: 遍历caps时已删账号adapter跳过(s.channels注入时), 删除/保存后列表=channels.json, 删除即消失 - (capReg Remove后续可加,范围外标注) agent-122 渠道管理分两块显示(主人:不割裂): - ①可用适配器类型(顶部PLATFORM_TYPES全集grid卡片,已配置/未配置Tag,点新建配置) - ②已保存配置(下方AdminTable过滤accounts>0,账号+bot身份+掩码token提示+连接/断开/删除) - 拆 channelConfigForm.tsx(248行) 表单抽出; Channels.tsx 463→306行; token只回填hint不写值(保存留空不改secret) 全仓 build/vet/test绿+前端build绿(356KB)
This commit is contained in:
1 parent
b614633432
commit
0ed7984de3
8 files changed
+578
-290
No files matched your search
+26
-13
@@ -151,22 +151,29 @@ func TestChannelFactoryBuildFromFile(t *testing.T) {
|
||||
|
||||
// TestNamedAdapterForwardsWebhook verifies the production wrapper forwards a
|
||||
// kook webhook-mode adapter's InboundHandler/WebhookPath to the channel bridge,
|
||||
// so bridge.WebhookHandlers() mounts the KOOK callback route on the gateway.
|
||||
// so bridge.WebhookHandlers() mounts the KOOK callback route on the gateway. The
|
||||
// webhook business fields (receive_mode/webhook_path) are sourced from
|
||||
// channels.json — .env only carries the necessary connection fallback.
|
||||
func TestNamedAdapterForwardsWebhook(t *testing.T) {
|
||||
t.Setenv("CHANNEL_KOOK_TOKEN", "kook-secret")
|
||||
t.Setenv("CHANNEL_KOOK_RECEIVE_MODE", "webhook")
|
||||
t.Setenv("CHANNEL_KOOK_WEBHOOK_PATH", "/webhook/kook")
|
||||
|
||||
adapters := buildChannelAdapters(testFactory(t))
|
||||
path := filepath.Join(t.TempDir(), "channels.json")
|
||||
raw := `{"kook":[{"id":"conf0","config":{"bot_token":"kook-secret","receive_mode":"webhook","webhook_path":"/webhook/kook"}}]}`
|
||||
if err := os.WriteFile(path, []byte(raw), 0o600); err != nil {
|
||||
t.Fatalf("write channels.json: %v", err)
|
||||
}
|
||||
f := &channelFactory{path: path, fallback: channelAccountsFromEnv(), log: testLog()}
|
||||
adpts, err := f.Build("kook")
|
||||
if err != nil {
|
||||
t.Fatalf("Build: %v", err)
|
||||
}
|
||||
var found *namedAdapter
|
||||
for _, a := range adapters {
|
||||
for _, a := range adpts {
|
||||
if nwa, ok := a.(*namedAdapter); ok && barePlatform(nwa.Name()) == "kook" {
|
||||
found = nwa
|
||||
break
|
||||
}
|
||||
}
|
||||
if found == nil {
|
||||
t.Fatalf("kook named adapter not found, got %v", names(adapters))
|
||||
t.Fatalf("kook named adapter not found, got %v", names(adpts))
|
||||
}
|
||||
if p := found.WebhookPath(); p != "/webhook/kook" {
|
||||
t.Errorf("WebhookPath = %q, want /webhook/kook", p)
|
||||
@@ -179,11 +186,17 @@ func TestNamedAdapterForwardsWebhook(t *testing.T) {
|
||||
// TestNamedAdapterNoWebhookInWSMode verifies a ws-mode adapter (all non-webhook
|
||||
// platforms) does not surface a webhook handler through the wrapper.
|
||||
func TestNamedAdapterNoWebhookInWSMode(t *testing.T) {
|
||||
t.Setenv("CHANNEL_KOOK_TOKEN", "kook-secret")
|
||||
t.Setenv("CHANNEL_KOOK_RECEIVE_MODE", "ws")
|
||||
|
||||
adapters := buildChannelAdapters(testFactory(t))
|
||||
for _, a := range adapters {
|
||||
path := filepath.Join(t.TempDir(), "channels.json")
|
||||
raw := `{"kook":[{"id":"conf0","config":{"bot_token":"kook-secret","receive_mode":"ws"}}]}`
|
||||
if err := os.WriteFile(path, []byte(raw), 0o600); err != nil {
|
||||
t.Fatalf("write channels.json: %v", err)
|
||||
}
|
||||
f := &channelFactory{path: path, fallback: channelAccountsFromEnv(), log: testLog()}
|
||||
adpts, err := f.Build("kook")
|
||||
if err != nil {
|
||||
t.Fatalf("Build: %v", err)
|
||||
}
|
||||
for _, a := range adpts {
|
||||
if barePlatform(a.Name()) != "kook" {
|
||||
continue
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user