diff --git a/desktop/src/i18n/locales/en.ts b/desktop/src/i18n/locales/en.ts index cfb95502..a59b5d94 100644 --- a/desktop/src/i18n/locales/en.ts +++ b/desktop/src/i18n/locales/en.ts @@ -376,6 +376,11 @@ export const en = { 'settings.adapters.appIdPlaceholder': 'e.g. cli_xxx', 'settings.adapters.appSecret': 'App Secret', 'settings.adapters.appSecretPlaceholder': 'From Feishu Open Platform', + 'settings.adapters.feishuCreateBotTitle': 'Need a Feishu bot?', + 'settings.adapters.feishuCreateBotDesc': 'Use the documented OpenClaw template to create a Feishu bot with the required permissions already configured. Then paste the App ID and App Secret below.', + 'settings.adapters.feishuCreateBotAction': 'Create Feishu bot', + 'settings.adapters.feishuCreateBotStepCreate': 'Create the bot from the template.', + 'settings.adapters.feishuCreateBotStepFill': 'Copy its App ID and App Secret, then fill them in here.', 'settings.adapters.encryptKey': 'Encrypt Key', 'settings.adapters.encryptKeyPlaceholder': 'Optional', 'settings.adapters.verificationToken': 'Verification Token', diff --git a/desktop/src/i18n/locales/zh.ts b/desktop/src/i18n/locales/zh.ts index 354959d4..61fed16f 100644 --- a/desktop/src/i18n/locales/zh.ts +++ b/desktop/src/i18n/locales/zh.ts @@ -378,6 +378,11 @@ export const zh: Record = { 'settings.adapters.appIdPlaceholder': '如 cli_xxx', 'settings.adapters.appSecret': 'App Secret', 'settings.adapters.appSecretPlaceholder': '从飞书开放平台获取', + 'settings.adapters.feishuCreateBotTitle': '还没有飞书机器人?', + 'settings.adapters.feishuCreateBotDesc': '使用文档中的官方 OpenClaw 模板,一键创建已预配权限的飞书机器人。创建后把 App ID 和 App Secret 填到下方。', + 'settings.adapters.feishuCreateBotAction': '一键创建飞书机器人', + 'settings.adapters.feishuCreateBotStepCreate': '点击模板创建机器人。', + 'settings.adapters.feishuCreateBotStepFill': '复制 App ID 和 App Secret,回到这里填写。', 'settings.adapters.encryptKey': 'Encrypt Key', 'settings.adapters.encryptKeyPlaceholder': '可选', 'settings.adapters.verificationToken': 'Verification Token', diff --git a/desktop/src/pages/AdapterSettings.test.tsx b/desktop/src/pages/AdapterSettings.test.tsx new file mode 100644 index 00000000..7185a093 --- /dev/null +++ b/desktop/src/pages/AdapterSettings.test.tsx @@ -0,0 +1,54 @@ +import { afterEach, describe, expect, it, vi } from 'vitest' +import { cleanup, render, screen } from '@testing-library/react' +import '@testing-library/jest-dom' + +import { AdapterSettings } from './AdapterSettings' +import { useAdapterStore } from '../stores/adapterStore' +import { useSettingsStore } from '../stores/settingsStore' +import type { AdapterFileConfig } from '../types/adapter' + +const FEISHU_CREATE_BOT_URL = 'https://open.feishu.cn/page/openclaw?form=multiAgent' + +function renderAdapterSettings(config: AdapterFileConfig) { + useSettingsStore.setState({ locale: 'en' }) + useAdapterStore.setState({ + config, + isLoading: false, + fetchConfig: vi.fn(async () => {}), + } as Partial>) + + render() +} + +afterEach(() => { + cleanup() + useAdapterStore.setState(useAdapterStore.getInitialState(), true) + useSettingsStore.setState(useSettingsStore.getInitialState(), true) +}) + +describe('AdapterSettings Feishu onboarding', () => { + it('shows the documented one-click Feishu bot link before credentials are configured', () => { + renderAdapterSettings({}) + + expect(screen.getByText('Need a Feishu bot?')).toBeInTheDocument() + expect(screen.getByText(/OpenClaw template/)).toBeInTheDocument() + expect(screen.getByText('1. Create the bot from the template.')).toBeInTheDocument() + expect(screen.getByText('2. Copy its App ID and App Secret, then fill them in here.')).toBeInTheDocument() + expect(screen.getByRole('link', { name: /create feishu bot/i })).toHaveAttribute( + 'href', + FEISHU_CREATE_BOT_URL, + ) + }) + + it('hides the one-click Feishu bot prompt once saved credentials exist', () => { + renderAdapterSettings({ + feishu: { + appId: 'cli_existing', + appSecret: '****cret', + }, + }) + + expect(screen.queryByRole('link', { name: /create feishu bot/i })).not.toBeInTheDocument() + expect(screen.queryByText('Need a Feishu bot?')).not.toBeInTheDocument() + }) +}) diff --git a/desktop/src/pages/AdapterSettings.tsx b/desktop/src/pages/AdapterSettings.tsx index 0738f83b..5578336b 100644 --- a/desktop/src/pages/AdapterSettings.tsx +++ b/desktop/src/pages/AdapterSettings.tsx @@ -10,6 +10,8 @@ import QRCode from 'qrcode' type ImTab = 'feishu' | 'wechat' | 'dingtalk' | 'telegram' type ImPlatform = 'telegram' | 'feishu' | 'wechat' | 'dingtalk' +const FEISHU_CREATE_BOT_URL = 'https://open.feishu.cn/page/openclaw?form=multiAgent' + export function AdapterSettings() { const t = useTranslation() const { @@ -375,6 +377,7 @@ export function AdapterSettings() { const pairingExpiry = config.pairing?.expiresAt const isPairingActive = pairingExpiry ? Date.now() < pairingExpiry : false const minutesLeft = pairingExpiry ? Math.max(0, Math.ceil((pairingExpiry - Date.now()) / 60000)) : 0 + const hasSavedFeishuCredentials = Boolean(config.feishu?.appId && config.feishu?.appSecret) if (isLoading) { return ( @@ -505,6 +508,32 @@ export function AdapterSettings() { {activeIm === 'feishu' && (
+ {!hasSavedFeishuCredentials && ( +
+
+
+ smart_toy +
+

{t('settings.adapters.feishuCreateBotTitle')}

+

{t('settings.adapters.feishuCreateBotDesc')}

+
    +
  1. 1. {t('settings.adapters.feishuCreateBotStepCreate')}
  2. +
  3. 2. {t('settings.adapters.feishuCreateBotStepFill')}
  4. +
+
+
+ + {t('settings.adapters.feishuCreateBotAction')} + open_in_new + +
+
+ )}