From 960e322c7988cd6aaccd2cac5723d1b56665b97a Mon Sep 17 00:00:00 2001 From: fdc310 <2213070223@qq.com> Date: Fri, 18 Sep 2026 19:08:30 +0800 Subject: [PATCH] feat(web): add contextual setup guides --- .../app/home/agents/AgentDetailContent.tsx | 2 + .../agents/components/AgentCreateContent.tsx | 37 +- .../agents/components/AgentFormComponent.tsx | 70 +- web/src/app/home/bots/BotDetailContent.tsx | 3 +- .../home/bots/components/bot-form/BotForm.tsx | 686 +++++++++++++----- .../components/guided-tour/GuidedTour.tsx | 359 +++++++++ .../guided-tour/dynamic-form-progress.ts | 46 ++ .../app/home/knowledge/KBDetailContent.tsx | 3 +- .../knowledge/components/kb-form/KBForm.tsx | 99 ++- web/src/i18n/locales/en-US.ts | 125 ++++ web/src/i18n/locales/ja-JP.ts | 124 ++++ web/src/i18n/locales/zh-Hans.ts | 116 +++ web/src/i18n/locales/zh-Hant.ts | 110 +++ web/tests/e2e/contextual-guides.spec.ts | 248 +++++++ web/tests/e2e/fixtures/langbot-api.ts | 11 + 15 files changed, 1832 insertions(+), 207 deletions(-) create mode 100644 web/src/app/home/components/guided-tour/GuidedTour.tsx create mode 100644 web/src/app/home/components/guided-tour/dynamic-form-progress.ts create mode 100644 web/tests/e2e/contextual-guides.spec.ts diff --git a/web/src/app/home/agents/AgentDetailContent.tsx b/web/src/app/home/agents/AgentDetailContent.tsx index abe7cbe2d..4532532c9 100644 --- a/web/src/app/home/agents/AgentDetailContent.tsx +++ b/web/src/app/home/agents/AgentDetailContent.tsx @@ -115,6 +115,7 @@ export default function AgentDetailContent({ id }: { id: string }) { if (isCreateMode) { return ( { refreshPipelines(); navigate(`/home/agents?id=${encodeURIComponent(newAgentId)}`); @@ -248,6 +249,7 @@ export default function AgentDetailContent({ id }: { id: string }) { onRunnerStatusChange={setRunnerStatus} onSupportedEventPatternsChange={setSupportedEventPatterns} onPlatformToolsChange={setPlatformTools} + guideEnabled={canManage} /> } diff --git a/web/src/app/home/agents/components/AgentCreateContent.tsx b/web/src/app/home/agents/components/AgentCreateContent.tsx index 4860d52e3..d18a41ead 100644 --- a/web/src/app/home/agents/components/AgentCreateContent.tsx +++ b/web/src/app/home/agents/components/AgentCreateContent.tsx @@ -27,11 +27,16 @@ import { import { Input } from '@/components/ui/input'; import EmojiPicker from '@/components/ui/emoji-picker'; import ProcessorTypeDiagram from './ProcessorTypeDiagram'; +import GuidedTour, { + GuidedTourStep, +} from '@/app/home/components/guided-tour/GuidedTour'; export default function AgentCreateContent({ onCreated, + guideEnabled = true, }: { onCreated: (agentId: string) => void; + guideEnabled?: boolean; }) { const { t } = useTranslation(); const [kind, setKind] = useState('agent'); @@ -109,6 +114,28 @@ export default function AgentCreateContent({ description: t('agents.eventProcessor.description'), }, ]; + const guideSteps: GuidedTourStep[] = [ + { + id: 'type', + target: '[data-guide="processor-type"]', + title: t('guidedTour.processorCreate.type.title'), + description: t('guidedTour.processorCreate.type.description'), + }, + { + id: 'basic', + target: '[data-guide="processor-basic"]', + title: t('guidedTour.processorCreate.basic.title'), + description: t('guidedTour.processorCreate.basic.description'), + complete: Boolean(form.watch('name')?.trim()), + requirement: t('guidedTour.processorCreate.basic.requirement'), + }, + { + id: 'submit', + target: '[data-guide="processor-submit"]', + title: t('guidedTour.processorCreate.submit.title'), + description: t('guidedTour.processorCreate.submit.description'), + }, + ]; return (
@@ -120,6 +147,7 @@ export default function AgentCreateContent({ type="submit" form="agent-create-form" disabled={form.formState.isSubmitting} + data-guide="processor-submit" > {t('common.submit')} @@ -132,6 +160,7 @@ export default function AgentCreateContent({

- + {t('agents.basicInfo')} @@ -258,6 +287,12 @@ export default function AgentCreateContent({
+ ); } diff --git a/web/src/app/home/agents/components/AgentFormComponent.tsx b/web/src/app/home/agents/components/AgentFormComponent.tsx index 8584662ea..28ef93d61 100644 --- a/web/src/app/home/agents/components/AgentFormComponent.tsx +++ b/web/src/app/home/agents/components/AgentFormComponent.tsx @@ -45,6 +45,10 @@ import { import { Form, FormField, FormItem, FormMessage } from '@/components/ui/form'; import AgentEventPatternPicker from './AgentEventPatternPicker'; import RunnerSelect from './RunnerSelect'; +import GuidedTour, { + GuidedTourStep, +} from '@/app/home/components/guided-tour/GuidedTour'; +import { areRequiredDynamicFieldsComplete } from '@/app/home/components/guided-tour/dynamic-form-progress'; import AgentApiToolPicker from './AgentApiToolPicker'; const OTHER_TOOL_SCOPES = [ @@ -70,6 +74,7 @@ interface AgentFormComponentProps { onRunnerStatusChange?: (status: RunnerStatus) => void; onSupportedEventPatternsChange?: (patterns: string[]) => void; onPlatformToolsChange?: (tools: AgentPlatformTool[]) => void; + guideEnabled?: boolean; } export type AgentConfigSection = 'runner' | 'events_and_tools'; @@ -124,6 +129,7 @@ function AgentFormComponent( onRunnerStatusChange, onSupportedEventPatternsChange, onPlatformToolsChange, + guideEnabled = true, }: AgentFormComponentProps, ref: ForwardedRef, ) { @@ -469,6 +475,54 @@ function AgentFormComponent( t, ]); + const runnerGuideSteps = useMemo(() => { + const steps: GuidedTourStep[] = [ + { + id: 'runner', + target: '[data-guide="runner-selector"]', + title: t('guidedTour.runner.select.title'), + description: t('guidedTour.runner.select.description'), + complete: Boolean(currentRunner && selectedRunnerOption), + requirement: t('guidedTour.runner.select.requirement'), + action: { + href: 'https://space.langbot.app/market?type=plugin&component=Runner&runner_usage=agent', + label: t('guidedTour.runner.select.action'), + }, + }, + ]; + + if (activeRunnerStage) { + steps.push({ + id: 'parameters', + target: '[data-guide="runner-parameters"]', + title: t('guidedTour.runner.parameters.title'), + description: t('guidedTour.runner.parameters.description'), + complete: areRequiredDynamicFieldsComplete( + activeRunnerStage.config, + activeRunnerValues, + ), + requirement: t('guidedTour.runner.parameters.requirement'), + }); + } + + steps.push({ + id: 'events', + target: '[data-guide="agent-sections"]', + title: t('guidedTour.runner.events.title'), + description: t('guidedTour.runner.events.description'), + complete: activeSection === 'events_and_tools', + requirement: t('guidedTour.runner.events.requirement'), + }); + return steps; + }, [ + activeRunnerStage, + activeRunnerValues, + activeSection, + currentRunner, + selectedRunnerOption, + t, + ]); + useEffect(() => { onRunnerStatusChange?.(runnerStatus); }, [onRunnerStatusChange, runnerStatus]); @@ -517,7 +571,10 @@ function AgentFormComponent( ] || {}; return ( - + {extractI18nObject(stage.label)} {stage.description && ( @@ -660,7 +717,10 @@ function AgentFormComponent( onSubmit={form.handleSubmit(handleSubmit)} className="mb-2 flex h-full min-h-0 min-w-0 flex-1 flex-col" > -