From 594897c9bb1da527ac507707f57ad667b0cb3877 Mon Sep 17 00:00:00 2001 From: lpf Date: Tue, 10 Mar 2026 14:46:34 +0800 Subject: [PATCH] hide unavailable channels in webui --- .github/workflows/release.yml | 14 +++++++------- pkg/api/server.go | 12 +++++++----- pkg/channels/compiled_channels.go | 30 +++++++++++++++++++++++++++++ pkg/channels/dingtalk.go | 2 ++ pkg/channels/dingtalk_stub.go | 2 ++ pkg/channels/discord.go | 2 ++ pkg/channels/discord_stub.go | 2 ++ pkg/channels/feishu.go | 2 ++ pkg/channels/feishu_stub.go | 2 ++ pkg/channels/maixcam.go | 2 ++ pkg/channels/maixcam_stub.go | 2 ++ pkg/channels/qq.go | 2 ++ pkg/channels/qq_stub.go | 2 ++ pkg/channels/telegram.go | 2 ++ pkg/channels/telegram_stub.go | 2 ++ pkg/channels/whatsapp.go | 2 ++ pkg/channels/whatsapp_stub.go | 2 ++ webui/src/components/Sidebar.tsx | 28 ++++++++++++++++----------- webui/src/context/AppContext.tsx | 7 ++++++- webui/src/pages/ChannelSettings.tsx | 21 ++++++++++++++------ 20 files changed, 110 insertions(+), 30 deletions(-) create mode 100644 pkg/channels/compiled_channels.go diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 79a57ac..9333fb7 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -83,10 +83,7 @@ jobs: uses: actions/upload-artifact@v4 with: name: release-artifacts - path: | - build/*.tar.gz - build/*.zip - build/checksums.txt + path: build if-no-files-found: error publish-release: @@ -100,6 +97,9 @@ jobs: name: release-artifacts path: build + - name: List downloaded artifacts + run: find build -maxdepth 4 -type f | sort + - name: Resolve tag id: tag run: | @@ -116,6 +116,6 @@ jobs: name: ${{ steps.tag.outputs.name }} generate_release_notes: true files: | - build/*.tar.gz - build/*.zip - build/checksums.txt + build/**/*.tar.gz + build/**/*.zip + build/**/checksums.txt diff --git a/pkg/api/server.go b/pkg/api/server.go index ffbc5b0..ea47f5d 100644 --- a/pkg/api/server.go +++ b/pkg/api/server.go @@ -1188,9 +1188,10 @@ func (s *Server) handleWebUIVersion(w http.ResponseWriter, r *http.Request) { return } _ = json.NewEncoder(w).Encode(map[string]interface{}{ - "ok": true, - "gateway_version": firstNonEmptyString(s.gatewayVersion, gatewayBuildVersion()), - "webui_version": firstNonEmptyString(s.webuiVersion, detectWebUIVersion(strings.TrimSpace(s.webUIDir))), + "ok": true, + "gateway_version": firstNonEmptyString(s.gatewayVersion, gatewayBuildVersion()), + "webui_version": firstNonEmptyString(s.webuiVersion, detectWebUIVersion(strings.TrimSpace(s.webUIDir))), + "compiled_channels": channels.CompiledChannelKeys(), }) } @@ -1523,8 +1524,9 @@ func (s *Server) webUISubagentsRuntimePayload(ctx context.Context) map[string]in func (s *Server) webUIVersionPayload() map[string]interface{} { return map[string]interface{}{ - "gateway_version": firstNonEmptyString(s.gatewayVersion, gatewayBuildVersion()), - "webui_version": firstNonEmptyString(s.webuiVersion, detectWebUIVersion(strings.TrimSpace(s.webUIDir))), + "gateway_version": firstNonEmptyString(s.gatewayVersion, gatewayBuildVersion()), + "webui_version": firstNonEmptyString(s.webuiVersion, detectWebUIVersion(strings.TrimSpace(s.webUIDir))), + "compiled_channels": channels.CompiledChannelKeys(), } } diff --git a/pkg/channels/compiled_channels.go b/pkg/channels/compiled_channels.go new file mode 100644 index 0000000..47b26e4 --- /dev/null +++ b/pkg/channels/compiled_channels.go @@ -0,0 +1,30 @@ +package channels + +import "sort" + +func CompiledChannelKeys() []string { + out := make([]string, 0, 7) + if telegramCompiled { + out = append(out, "telegram") + } + if whatsappCompiled { + out = append(out, "whatsapp") + } + if discordCompiled { + out = append(out, "discord") + } + if feishuCompiled { + out = append(out, "feishu") + } + if qqCompiled { + out = append(out, "qq") + } + if dingtalkCompiled { + out = append(out, "dingtalk") + } + if maixcamCompiled { + out = append(out, "maixcam") + } + sort.Strings(out) + return out +} diff --git a/pkg/channels/dingtalk.go b/pkg/channels/dingtalk.go index b8e7e84..9241670 100644 --- a/pkg/channels/dingtalk.go +++ b/pkg/channels/dingtalk.go @@ -30,6 +30,8 @@ type DingTalkChannel struct { sessionWebhooks sync.Map // chatID -> sessionWebhook } +const dingtalkCompiled = true + // NewDingTalkChannel creates a new DingTalk channel instance func NewDingTalkChannel(cfg config.DingTalkConfig, messageBus *bus.MessageBus) (*DingTalkChannel, error) { if cfg.ClientID == "" || cfg.ClientSecret == "" { diff --git a/pkg/channels/dingtalk_stub.go b/pkg/channels/dingtalk_stub.go index e6bda0a..f11b518 100644 --- a/pkg/channels/dingtalk_stub.go +++ b/pkg/channels/dingtalk_stub.go @@ -9,6 +9,8 @@ import ( type DingTalkChannel struct{ disabledChannel } +const dingtalkCompiled = false + func NewDingTalkChannel(cfg config.DingTalkConfig, bus *bus.MessageBus) (*DingTalkChannel, error) { return nil, errChannelDisabled("dingtalk") } diff --git a/pkg/channels/discord.go b/pkg/channels/discord.go index 886b3ba..d22e537 100644 --- a/pkg/channels/discord.go +++ b/pkg/channels/discord.go @@ -23,6 +23,8 @@ type DiscordChannel struct { config config.DiscordConfig } +const discordCompiled = true + func NewDiscordChannel(cfg config.DiscordConfig, bus *bus.MessageBus) (*DiscordChannel, error) { session, err := discordgo.New("Bot " + cfg.Token) if err != nil { diff --git a/pkg/channels/discord_stub.go b/pkg/channels/discord_stub.go index f6c0474..b0f1d3a 100644 --- a/pkg/channels/discord_stub.go +++ b/pkg/channels/discord_stub.go @@ -9,6 +9,8 @@ import ( type DiscordChannel struct{ disabledChannel } +const discordCompiled = false + func NewDiscordChannel(cfg config.DiscordConfig, bus *bus.MessageBus) (*DiscordChannel, error) { return nil, errChannelDisabled("discord") } diff --git a/pkg/channels/feishu.go b/pkg/channels/feishu.go index a7324f8..9e7351a 100644 --- a/pkg/channels/feishu.go +++ b/pkg/channels/feishu.go @@ -45,6 +45,8 @@ type FeishuChannel struct { tenantTokenErr error } +const feishuCompiled = true + func (c *FeishuChannel) SupportsAction(action string) bool { switch strings.ToLower(strings.TrimSpace(action)) { case "", "send": diff --git a/pkg/channels/feishu_stub.go b/pkg/channels/feishu_stub.go index 74a3ee1..29e7c0f 100644 --- a/pkg/channels/feishu_stub.go +++ b/pkg/channels/feishu_stub.go @@ -9,6 +9,8 @@ import ( type FeishuChannel struct{ disabledChannel } +const feishuCompiled = false + func NewFeishuChannel(cfg config.FeishuConfig, bus *bus.MessageBus) (*FeishuChannel, error) { return nil, errChannelDisabled("feishu") } diff --git a/pkg/channels/maixcam.go b/pkg/channels/maixcam.go index ac7487d..0692b10 100644 --- a/pkg/channels/maixcam.go +++ b/pkg/channels/maixcam.go @@ -22,6 +22,8 @@ type MaixCamChannel struct { clientsMux sync.RWMutex } +const maixcamCompiled = true + type MaixCamMessage struct { Type string `json:"type"` Tips string `json:"tips"` diff --git a/pkg/channels/maixcam_stub.go b/pkg/channels/maixcam_stub.go index fabd4fd..97794d4 100644 --- a/pkg/channels/maixcam_stub.go +++ b/pkg/channels/maixcam_stub.go @@ -9,6 +9,8 @@ import ( type MaixCamChannel struct{ disabledChannel } +const maixcamCompiled = false + func NewMaixCamChannel(cfg config.MaixCamConfig, bus *bus.MessageBus) (*MaixCamChannel, error) { return nil, errChannelDisabled("maixcam") } diff --git a/pkg/channels/qq.go b/pkg/channels/qq.go index bde2d49..5bdc931 100644 --- a/pkg/channels/qq.go +++ b/pkg/channels/qq.go @@ -31,6 +31,8 @@ type QQChannel struct { mu sync.RWMutex } +const qqCompiled = true + func NewQQChannel(cfg config.QQConfig, messageBus *bus.MessageBus) (*QQChannel, error) { base := NewBaseChannel("qq", cfg, messageBus, cfg.AllowFrom) diff --git a/pkg/channels/qq_stub.go b/pkg/channels/qq_stub.go index 646e041..1543b8e 100644 --- a/pkg/channels/qq_stub.go +++ b/pkg/channels/qq_stub.go @@ -9,6 +9,8 @@ import ( type QQChannel struct{ disabledChannel } +const qqCompiled = false + func NewQQChannel(cfg config.QQConfig, bus *bus.MessageBus) (*QQChannel, error) { return nil, errChannelDisabled("qq") } diff --git a/pkg/channels/telegram.go b/pkg/channels/telegram.go index 8103fd5..8568384 100644 --- a/pkg/channels/telegram.go +++ b/pkg/channels/telegram.go @@ -38,6 +38,8 @@ const ( telegramStreamMaxRetries = 4 ) +const telegramCompiled = true + type TelegramChannel struct { *BaseChannel bot *telego.Bot diff --git a/pkg/channels/telegram_stub.go b/pkg/channels/telegram_stub.go index 0632340..6730242 100644 --- a/pkg/channels/telegram_stub.go +++ b/pkg/channels/telegram_stub.go @@ -9,6 +9,8 @@ import ( type TelegramChannel struct{ disabledChannel } +const telegramCompiled = false + func NewTelegramChannel(cfg config.TelegramConfig, bus *bus.MessageBus) (*TelegramChannel, error) { return nil, errChannelDisabled("telegram") } diff --git a/pkg/channels/whatsapp.go b/pkg/channels/whatsapp.go index ceae381..88884be 100644 --- a/pkg/channels/whatsapp.go +++ b/pkg/channels/whatsapp.go @@ -30,6 +30,8 @@ type WhatsAppChannel struct { connected bool } +const whatsappCompiled = true + func NewWhatsAppChannel(cfg config.WhatsAppConfig, bus *bus.MessageBus) (*WhatsAppChannel, error) { base := NewBaseChannel("whatsapp", cfg, bus, cfg.AllowFrom) diff --git a/pkg/channels/whatsapp_stub.go b/pkg/channels/whatsapp_stub.go index d0c5614..c3c53f3 100644 --- a/pkg/channels/whatsapp_stub.go +++ b/pkg/channels/whatsapp_stub.go @@ -9,6 +9,8 @@ import ( type WhatsAppChannel struct{ disabledChannel } +const whatsappCompiled = false + func NewWhatsAppChannel(cfg config.WhatsAppConfig, bus *bus.MessageBus) (*WhatsAppChannel, error) { return nil, errChannelDisabled("whatsapp") } diff --git a/webui/src/components/Sidebar.tsx b/webui/src/components/Sidebar.tsx index f56c575..5842b72 100644 --- a/webui/src/components/Sidebar.tsx +++ b/webui/src/components/Sidebar.tsx @@ -7,7 +7,7 @@ import NavItem from './NavItem'; const Sidebar: React.FC = () => { const { t } = useTranslation(); - const { token, setToken, sidebarOpen, sidebarCollapsed, setSidebarCollapsed } = useAppContext(); + const { token, setToken, sidebarOpen, sidebarCollapsed, setSidebarCollapsed, compiledChannels } = useAppContext(); const location = useLocation(); const [expandedSections, setExpandedSections] = React.useState>({ main: true, @@ -19,6 +19,16 @@ const Sidebar: React.FC = () => { channels: false, }); + const channelChildren = [ + { id: 'whatsapp', icon: , label: t('whatsappBridge'), to: '/channels/whatsapp' }, + { id: 'telegram', icon: , label: t('telegram'), to: '/channels/telegram' }, + { id: 'discord', icon: , label: t('discord'), to: '/channels/discord' }, + { id: 'feishu', icon: , label: t('feishu'), to: '/channels/feishu' }, + { id: 'qq', icon: , label: t('qq'), to: '/channels/qq' }, + { id: 'dingtalk', icon: , label: t('dingtalk'), to: '/channels/dingtalk' }, + { id: 'maixcam', icon: , label: t('maixcam'), to: '/channels/maixcam' }, + ].filter((item) => compiledChannels.includes(item.id)); + const sections = [ { id: 'main', @@ -54,15 +64,7 @@ const Sidebar: React.FC = () => { icon: , label: t('channelsGroup'), childrenId: 'channels', - children: [ - { icon: , label: t('whatsappBridge'), to: '/channels/whatsapp' }, - { icon: , label: t('telegram'), to: '/channels/telegram' }, - { icon: , label: t('discord'), to: '/channels/discord' }, - { icon: , label: t('feishu'), to: '/channels/feishu' }, - { icon: , label: t('qq'), to: '/channels/qq' }, - { icon: , label: t('dingtalk'), to: '/channels/dingtalk' }, - { icon: , label: t('maixcam'), to: '/channels/maixcam' }, - ], + children: channelChildren, }, { icon: , label: t('mcpServices'), to: '/mcp' }, { icon: , label: t('cronJobs'), to: '/cron' }, @@ -86,6 +88,10 @@ const Sidebar: React.FC = () => { ], }, ]; + const normalizedSections = sections.map((sec) => ({ + ...sec, + items: sec.items.filter((item: any) => !item.children || item.children.length > 0), + })); const toggle = (id: string) => setExpandedSections((prev) => ({ ...prev, [id]: !prev[id] })); const isSubmenuActive = (items: Array<{ to: string }>) => items.some((item) => location.pathname === item.to); @@ -93,7 +99,7 @@ const Sidebar: React.FC = () => { return (