From 51e67f20ff941cd1bb557326d4c5bf02b60cf1f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A8=8B=E5=BA=8F=E5=91=98=E9=98=BF=E6=B1=9F=28Relakkes?= =?UTF-8?q?=29?= Date: Tue, 19 May 2026 00:08:17 +0800 Subject: [PATCH] fix: reduce Feishu IM setup dead ends Feishu onboarding previously expected users to find the template bot flow in docs before the desktop form made sense. Surface the documented OpenClaw creation link and the two required setup steps directly in the unconfigured Feishu settings state, while hiding the prompt once saved credentials exist. Constraint: The documented one-click template URL is the source of truth for bot creation. Rejected: Add a full wizard | this flow only needs a short external creation link plus credential fields. Confidence: high Scope-risk: narrow Directive: Keep this prompt short; detailed Feishu menu setup belongs in docs, not the settings form. Tested: cd desktop && bunx vitest run src/pages/AdapterSettings.test.tsx src/i18n/index.test.tsx Tested: cd desktop && bun run lint Tested: git diff --check Tested: bun run check:desktop Not-tested: Live Feishu developer console account flow. --- desktop/src/i18n/locales/en.ts | 5 ++ desktop/src/i18n/locales/zh.ts | 5 ++ desktop/src/pages/AdapterSettings.test.tsx | 54 ++++++++++++++++++++++ desktop/src/pages/AdapterSettings.tsx | 29 ++++++++++++ 4 files changed, 93 insertions(+) create mode 100644 desktop/src/pages/AdapterSettings.test.tsx 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 + +
+
+ )}