feat: add i18n, platform channels page, and WeChat QR login

- Add vue-i18n with auto-detect browser language and manual toggle (EN/中文)
- Move platform channels to separate page with credential management
- Support Telegram, Discord, Slack, WhatsApp, Matrix, Feishu, Weixin, WeCom
- Add WeChat QR code login (opens in browser, polls status, auto-saves)
- Write platform credentials to ~/.hermes/.env matching hermes gateway setup
- Auto restart gateway after platform config changes
- Add settings store with per-section save for all config categories
- Persist session group collapse state across navigation
- Fix pre-existing TypeScript build errors

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
ekko
2026-04-13 15:15:14 +08:00
parent 9e069a20a1
commit e89a240f1d
42 changed files with 2627 additions and 378 deletions
+87
View File
@@ -0,0 +1,87 @@
import { defineStore } from 'pinia'
import { ref } from 'vue'
import * as configApi from '@/api/config'
import type { DisplayConfig, AgentConfig, MemoryConfig, SessionResetConfig, PrivacyConfig } from '@/api/config'
export const useSettingsStore = defineStore('settings', () => {
const loading = ref(false)
const display = ref<DisplayConfig>({})
const agent = ref<AgentConfig>({})
const memory = ref<MemoryConfig>({})
const sessionReset = ref<SessionResetConfig>({})
const privacy = ref<PrivacyConfig>({})
const telegram = ref<Record<string, any>>({})
const discord = ref<Record<string, any>>({})
const slack = ref<Record<string, any>>({})
const whatsapp = ref<Record<string, any>>({})
const matrix = ref<Record<string, any>>({})
const wecom = ref<Record<string, any>>({})
const feishu = ref<Record<string, any>>({})
const dingtalk = ref<Record<string, any>>({})
const weixin = ref<Record<string, any>>({})
const platforms = ref<Record<string, any>>({})
async function fetchSettings() {
loading.value = true
try {
const data = await configApi.fetchConfig()
display.value = data.display || {}
agent.value = data.agent || {}
memory.value = data.memory || {}
sessionReset.value = data.session_reset || {}
privacy.value = data.privacy || {}
telegram.value = data.telegram || {}
discord.value = data.discord || {}
slack.value = data.slack || {}
whatsapp.value = data.whatsapp || {}
matrix.value = data.matrix || {}
wecom.value = data.wecom || {}
feishu.value = data.feishu || {}
dingtalk.value = data.dingtalk || {}
weixin.value = data.weixin || {}
platforms.value = data.platforms || {}
} catch (err) {
console.error('Failed to fetch settings:', err)
} finally {
loading.value = false
}
}
async function saveSection(section: string, values: Record<string, any>) {
await configApi.updateConfigSection(section, values)
switch (section) {
case 'display': display.value = { ...display.value, ...values }; break
case 'agent': agent.value = { ...agent.value, ...values }; break
case 'memory': memory.value = { ...memory.value, ...values }; break
case 'session_reset': sessionReset.value = { ...sessionReset.value, ...values }; break
case 'privacy': privacy.value = { ...privacy.value, ...values }; break
case 'telegram': telegram.value = { ...telegram.value, ...values }; break
case 'discord': discord.value = { ...discord.value, ...values }; break
case 'slack': slack.value = { ...slack.value, ...values }; break
case 'whatsapp': whatsapp.value = { ...whatsapp.value, ...values }; break
case 'matrix': matrix.value = { ...matrix.value, ...values }; break
case 'wechat': case 'wecom': wecom.value = { ...wecom.value, ...values }; break
case 'feishu': feishu.value = { ...feishu.value, ...values }; break
case 'dingtalk': dingtalk.value = { ...dingtalk.value, ...values }; break
case 'weixin': weixin.value = { ...weixin.value, ...values }; break
case 'platforms': {
// Deep-merge each platform's credentials
for (const [key, val] of Object.entries(values)) {
platforms.value = {
...platforms.value,
[key]: { ...(platforms.value[key] || {}), ...(val as Record<string, any>) },
}
}
break
}
}
}
return {
loading,
display, agent, memory, sessionReset, privacy,
telegram, discord, slack, whatsapp, matrix, wecom, feishu, dingtalk, weixin, platforms,
fetchSettings, saveSection,
}
})