mirror of
https://github.com/NanmiCoder/cc-haha
synced 2026-07-17 13:13:35 +08:00
Merge Feishu IM setup guidance into local main
Bring the desktop Feishu onboarding prompt from the worktree onto local main while preserving the existing local Web UI startup commit. Constraint: Local main already had an independent commit after the worktree base, so fast-forward merge was not possible. Confidence: high Scope-risk: narrow Directive: Keep future Feishu setup help concise in the settings page and leave detailed platform instructions in docs. Tested: merge completed without conflicts Tested: cd desktop && bunx vitest run src/pages/AdapterSettings.test.tsx src/i18n/index.test.tsx Not-tested: Full post-merge check:desktop was not rerun; it had passed in the source worktree before merge.
This commit is contained in:
commit
82609f6db6
@ -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',
|
||||
|
||||
@ -378,6 +378,11 @@ export const zh: Record<TranslationKey, string> = {
|
||||
'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',
|
||||
|
||||
54
desktop/src/pages/AdapterSettings.test.tsx
Normal file
54
desktop/src/pages/AdapterSettings.test.tsx
Normal file
@ -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<ReturnType<typeof useAdapterStore.getState>>)
|
||||
|
||||
render(<AdapterSettings />)
|
||||
}
|
||||
|
||||
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()
|
||||
})
|
||||
})
|
||||
@ -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' && (
|
||||
<div className="p-4 space-y-4">
|
||||
{!hasSavedFeishuCredentials && (
|
||||
<div className="rounded-lg border border-[var(--color-border)] bg-[var(--color-surface)] p-4">
|
||||
<div className="flex flex-col gap-3 sm:flex-row sm:items-start sm:justify-between">
|
||||
<div className="flex min-w-0 gap-3">
|
||||
<span className="material-symbols-outlined mt-0.5 text-[20px] text-[var(--color-brand)]">smart_toy</span>
|
||||
<div className="min-w-0">
|
||||
<h4 className="text-sm font-semibold text-[var(--color-text-primary)]">{t('settings.adapters.feishuCreateBotTitle')}</h4>
|
||||
<p className="mt-1 text-xs leading-5 text-[var(--color-text-tertiary)]">{t('settings.adapters.feishuCreateBotDesc')}</p>
|
||||
<ol className="mt-2 space-y-1 text-xs leading-5 text-[var(--color-text-secondary)]">
|
||||
<li>1. {t('settings.adapters.feishuCreateBotStepCreate')}</li>
|
||||
<li>2. {t('settings.adapters.feishuCreateBotStepFill')}</li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
<a
|
||||
href={FEISHU_CREATE_BOT_URL}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="inline-flex h-9 shrink-0 items-center justify-center gap-1.5 rounded-[var(--radius-md)] bg-[image:var(--gradient-btn-primary)] px-3 text-xs font-medium text-[var(--color-btn-primary-fg)] shadow-[var(--shadow-button-primary)] transition-colors hover:bg-[image:var(--gradient-btn-primary-hover)] hover:brightness-105 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-brand)] focus-visible:ring-offset-2 focus-visible:ring-offset-[var(--color-surface)]"
|
||||
>
|
||||
{t('settings.adapters.feishuCreateBotAction')}
|
||||
<span className="material-symbols-outlined text-[14px]">open_in_new</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<Input
|
||||
label={t('settings.adapters.appId')}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user