fix(web): simplify route test dialog

This commit is contained in:
RockChinQ
2026-08-25 21:27:33 +08:00
parent ad6b8b3209
commit e62f8a957a
5 changed files with 109 additions and 102 deletions
@@ -1013,15 +1013,16 @@ function RouteDryRunDialog({
{t('bots.testRoute')} {t('bots.testRoute')}
</Button> </Button>
<Dialog open={open} onOpenChange={setOpen}> <Dialog open={open} onOpenChange={setOpen}>
<DialogContent className="max-w-2xl"> <DialogContent className="sm:max-w-lg">
<DialogHeader> <DialogHeader>
<DialogTitle>{t('bots.dryRunTitle')}</DialogTitle> <DialogTitle>{t('bots.dryRunTitle')}</DialogTitle>
<DialogDescription>{t('bots.dryRunDescription')}</DialogDescription> <DialogDescription>{t('bots.dryRunDescription')}</DialogDescription>
</DialogHeader> </DialogHeader>
<div className="space-y-4"> <div className="space-y-4">
<div className="space-y-3"> <div className="space-y-2">
<div className="space-y-1.5"> <div className="flex flex-col gap-2 sm:flex-row sm:items-end">
<div className="min-w-0 flex-1 space-y-1.5">
<label className="text-sm font-medium"> <label className="text-sm font-medium">
{t('bots.dryRunEventType')} {t('bots.dryRunEventType')}
</label> </label>
@@ -1038,23 +1039,11 @@ function RouteDryRunDialog({
</SelectContent> </SelectContent>
</Select> </Select>
</div> </div>
<div className="rounded-md border bg-muted/20 px-3 py-2.5">
<div className="flex items-start justify-between gap-3">
<div className="min-w-0">
<p className="text-sm font-medium">
{t('bots.dryRunSampleReady')}
</p>
<p className="mt-0.5 text-xs leading-relaxed text-muted-foreground">
{t('bots.dryRunSampleDescription', {
event: eventLabel(eventType, t),
})}
</p>
</div>
<Button <Button
type="button" type="button"
variant="ghost" variant="ghost"
size="sm" size="sm"
className="h-8 shrink-0 px-2 text-xs" className="h-9 shrink-0 self-start px-2 text-xs text-muted-foreground sm:self-auto"
onClick={() => setAdvancedPayloadOpen((value) => !value)} onClick={() => setAdvancedPayloadOpen((value) => !value)}
> >
{advancedPayloadOpen ? ( {advancedPayloadOpen ? (
@@ -1068,14 +1057,14 @@ function RouteDryRunDialog({
</Button> </Button>
</div> </div>
{advancedPayloadOpen && ( {advancedPayloadOpen && (
<div className="mt-3 space-y-1.5 border-t pt-3"> <div className="space-y-1.5 rounded-md border bg-muted/20 p-3">
<label className="text-xs font-medium"> <label className="text-xs font-medium">
{t('bots.dryRunPayload')} {t('bots.dryRunPayload')}
</label> </label>
<Textarea <Textarea
value={payloadText} value={payloadText}
onChange={(e) => setPayloadText(e.target.value)} onChange={(e) => setPayloadText(e.target.value)}
className="min-h-[118px] font-mono text-xs" className="min-h-[110px] font-mono text-xs"
spellCheck={false} spellCheck={false}
placeholder='{"message_text": "hello"}' placeholder='{"message_text": "hello"}'
/> />
@@ -1089,7 +1078,6 @@ function RouteDryRunDialog({
</div> </div>
)} )}
</div> </div>
</div>
{runError && ( {runError && (
<Alert variant="destructive"> <Alert variant="destructive">
@@ -1188,9 +1176,9 @@ function RouteDryRunDialog({
</Alert> </Alert>
)} )}
<Alert className="border-amber-200 bg-amber-50/60 text-amber-900 dark:border-amber-900/50 dark:bg-amber-950/20 dark:text-amber-200"> <Alert className="border-amber-200 bg-amber-50/60 px-3 py-2 text-amber-900 dark:border-amber-900/50 dark:bg-amber-950/20 dark:text-amber-200">
<AlertCircle className="h-4 w-4" /> <AlertCircle className="h-4 w-4" />
<AlertDescription> <AlertDescription className="text-xs">
{t('bots.routeTestSideEffectWarning')} {t('bots.routeTestSideEffectWarning')}
</AlertDescription> </AlertDescription>
</Alert> </Alert>
+9 -10
View File
@@ -469,30 +469,29 @@ const enUS = {
runner_failed: 'The Agent runner failed while processing the event.', runner_failed: 'The Agent runner failed while processing the event.',
delivery_failed: 'The processor finished, but delivery failed.', delivery_failed: 'The processor finished, but delivery failed.',
}, },
routeTestAction: 'Run saved route', routeTestAction: 'Run saved configuration',
routeTestRunning: 'Running…', routeTestRunning: 'Running…',
routeTestFailed: 'Failed to run the saved route. Try again later.', routeTestFailed: 'Failed to run the saved route. Try again later.',
routeTestDispatched: routeTestDispatched:
'The saved route ran successfully. {{count}} platform actions were blocked.', 'The saved route ran successfully. {{count}} platform actions were blocked.',
routeTestSideEffectWarning: routeTestSideEffectWarning:
'Running the saved route executes its processor. Platform messaging actions are blocked, but tools and external services may still have side effects.', 'Platform messaging is blocked, but the processor and tools still run.',
dryRunTitle: 'Test event route', dryRunTitle: 'Test route',
dryRunDescription: dryRunDescription:
'Preview the current form without running a processor, or run the saved route to validate the live configuration.', 'Preview the match first. Run the saved configuration only when you need to test the processor.',
dryRunEventType: 'Event type', dryRunEventType: 'Event type',
dryRunSampleReady: 'Sample event is ready', dryRunSampleReady: 'Sample event is ready',
dryRunSampleDescription: dryRunSampleDescription:
'LangBot prepared example data for {{event}}. Most route tests can use it as-is.', 'LangBot prepared example data for {{event}}. Most route tests can use it as-is.',
dryRunEditPayload: 'Edit advanced data', dryRunEditPayload: 'Test data',
dryRunHidePayload: 'Hide advanced data', dryRunHidePayload: 'Hide data',
dryRunPayload: 'Advanced event data (JSON)', dryRunPayload: 'Test data (JSON)',
dryRunPayloadHint: dryRunPayloadHint: 'Use this to test message and conversation conditions.',
'Use simple fields such as message_text, chat_type, and chat_id to test conditions.',
dryRunPayloadJsonError: 'Enter valid JSON.', dryRunPayloadJsonError: 'Enter valid JSON.',
dryRunPayloadObjectError: 'Payload must be a JSON object.', dryRunPayloadObjectError: 'Payload must be a JSON object.',
dryRunNeedsSavedBot: 'Save the bot before testing routes.', dryRunNeedsSavedBot: 'Save the bot before testing routes.',
dryRunFailed: 'Route test failed. Try again later.', dryRunFailed: 'Route test failed. Try again later.',
dryRunAction: 'Preview route', dryRunAction: 'Preview match',
dryRunRunning: 'Testing…', dryRunRunning: 'Testing…',
dryRunMatched: 'Route matched', dryRunMatched: 'Route matched',
dryRunNotMatched: 'No route matched', dryRunNotMatched: 'No route matched',
+9 -10
View File
@@ -476,32 +476,31 @@ const jaJP = {
runner_failed: 'Agent Runner がイベント処理中に失敗しました。', runner_failed: 'Agent Runner がイベント処理中に失敗しました。',
delivery_failed: '処理は完了しましたが、結果の配信に失敗しました。', delivery_failed: '処理は完了しましたが、結果の配信に失敗しました。',
}, },
routeTestAction: '保存済みルートを実行', routeTestAction: '保存済み設定を実行',
routeTestRunning: '実行中…', routeTestRunning: '実行中…',
routeTestFailed: routeTestFailed:
'保存済みルートの実行に失敗しました。後でもう一度お試しください。', '保存済みルートの実行に失敗しました。後でもう一度お試しください。',
routeTestDispatched: routeTestDispatched:
'保存済みルートを実行しました。{{count}} 件のプラットフォーム操作を抑制しました。', '保存済みルートを実行しました。{{count}} 件のプラットフォーム操作を抑制しました。',
routeTestSideEffectWarning: routeTestSideEffectWarning:
'保存済みルートを実行するとプロセッサーが動作します。プラットフォームのメッセージ操作は抑制されますが、ツールや外部サービスには副作用が生じる場合があります。', 'プラットフォームへの送信は抑制されますが、プロセッサーとツールは実行されます。',
dryRunTitle: 'イベントルートをテスト', dryRunTitle: 'ルートをテスト',
dryRunDescription: dryRunDescription:
'プロセッサーを実行せずに現在のフォームをプレビューするか、保存済みルートを実行して設定を検証します。', 'まず一致結果を確認し、必要な場合のみ保存済み設定を実行します。',
dryRunEventType: 'イベントタイプ', dryRunEventType: 'イベントタイプ',
dryRunSampleReady: 'サンプルイベントを準備しました', dryRunSampleReady: 'サンプルイベントを準備しました',
dryRunSampleDescription: dryRunSampleDescription:
'LangBot が「{{event}}」用のサンプルデータを準備しました。通常はそのままテストできます。', 'LangBot が「{{event}}」用のサンプルデータを準備しました。通常はそのままテストできます。',
dryRunEditPayload: '詳細データを編集', dryRunEditPayload: 'テストデータ',
dryRunHidePayload: '詳細データを閉じる', dryRunHidePayload: 'データを閉じる',
dryRunPayload: '詳細イベントデータ(JSON', dryRunPayload: 'テストデータ(JSON',
dryRunPayloadHint: dryRunPayloadHint: 'メッセージや会話の条件テストに使用します。',
'message_text、chat_type、chat_id などの簡単なフィールドで条件をテストできます。',
dryRunPayloadJsonError: '有効な JSON を入力してください。', dryRunPayloadJsonError: '有効な JSON を入力してください。',
dryRunPayloadObjectError: dryRunPayloadObjectError:
'ペイロードは JSON オブジェクトである必要があります。', 'ペイロードは JSON オブジェクトである必要があります。',
dryRunNeedsSavedBot: 'ルートをテストする前にボットを保存してください。', dryRunNeedsSavedBot: 'ルートをテストする前にボットを保存してください。',
dryRunFailed: 'ルートテストに失敗しました。後でもう一度お試しください。', dryRunFailed: 'ルートテストに失敗しました。後でもう一度お試しください。',
dryRunAction: 'ルートをプレビュー', dryRunAction: '一致を確認',
dryRunRunning: 'テスト中…', dryRunRunning: 'テスト中…',
dryRunMatched: 'ルートに一致しました', dryRunMatched: 'ルートに一致しました',
dryRunNotMatched: '一致するルートはありません', dryRunNotMatched: '一致するルートはありません',
+9 -12
View File
@@ -447,29 +447,26 @@ const zhHans = {
runner_failed: 'Agent Runner 处理事件时失败。', runner_failed: 'Agent Runner 处理事件时失败。',
delivery_failed: '处理器已完成,但结果投递失败。', delivery_failed: '处理器已完成,但结果投递失败。',
}, },
routeTestAction: '运行已保存路由', routeTestAction: '运行已保存配置',
routeTestRunning: '运行中…', routeTestRunning: '运行中…',
routeTestFailed: '运行已保存路由失败,请稍后重试。', routeTestFailed: '运行已保存路由失败,请稍后重试。',
routeTestDispatched: '已保存路由运行成功,{{count}} 个平台操作已被阻止。', routeTestDispatched: '已保存路由运行成功,{{count}} 个平台操作已被阻止。',
routeTestSideEffectWarning: routeTestSideEffectWarning: '平台消息会被拦截,但处理器和工具仍会运行。',
'运行已保存路由会执行处理器。平台消息操作会被阻止,但工具和外部服务仍可能产生副作用。', dryRunTitle: '测试路由',
dryRunTitle: '测试事件路由', dryRunDescription: '先预览匹配结果;需要验证处理器时,再运行已保存配置。',
dryRunDescription:
'可以先预览当前表单而不运行处理器,也可以运行已保存路由来验证线上配置。',
dryRunEventType: '事件类型', dryRunEventType: '事件类型',
dryRunSampleReady: '示例事件已准备好', dryRunSampleReady: '示例事件已准备好',
dryRunSampleDescription: dryRunSampleDescription:
'LangBot 已为“{{event}}”准备示例数据,大多数路由测试可直接使用。', 'LangBot 已为“{{event}}”准备示例数据,大多数路由测试可直接使用。',
dryRunEditPayload: '编辑高级数据', dryRunEditPayload: '测试数据',
dryRunHidePayload: '收起高级数据', dryRunHidePayload: '收起数据',
dryRunPayload: '高级事件数据(JSON', dryRunPayload: '测试数据(JSON',
dryRunPayloadHint: dryRunPayloadHint: '用于测试消息内容、会话类型等条件。',
'可填写 message_text、chat_type、chat_id 等简单字段,用于匹配触发条件。',
dryRunPayloadJsonError: '请输入合法 JSON。', dryRunPayloadJsonError: '请输入合法 JSON。',
dryRunPayloadObjectError: '载荷必须是 JSON 对象。', dryRunPayloadObjectError: '载荷必须是 JSON 对象。',
dryRunNeedsSavedBot: '请先保存机器人后再测试路由。', dryRunNeedsSavedBot: '请先保存机器人后再测试路由。',
dryRunFailed: '路由测试失败,请稍后重试。', dryRunFailed: '路由测试失败,请稍后重试。',
dryRunAction: '预览路由', dryRunAction: '预览匹配',
dryRunRunning: '测试中…', dryRunRunning: '测试中…',
dryRunMatched: '已命中路由', dryRunMatched: '已命中路由',
dryRunNotMatched: '未命中路由', dryRunNotMatched: '未命中路由',
+24
View File
@@ -378,6 +378,30 @@ test.describe('bot advanced flows', () => {
await expect( await expect(
page.getByText('Failed to refresh route status.'), page.getByText('Failed to refresh route status.'),
).toBeVisible(); ).toBeVisible();
await page.getByRole('button', { name: 'Test route' }).click();
const routeDialog = page.getByRole('dialog');
await expect(
routeDialog.getByText('Test route', { exact: true }),
).toBeVisible();
await expect(
routeDialog.getByText(
'Preview the match first. Run the saved configuration only when you need to test the processor.',
),
).toBeVisible();
await expect(routeDialog.getByText('Sample event is ready')).toHaveCount(0);
await expect(
routeDialog.getByRole('button', { name: 'Test data' }),
).toBeVisible();
await expect(
routeDialog.getByRole('button', { name: 'Preview match' }),
).toBeVisible();
await expect(
routeDialog.getByRole('button', { name: 'Run saved configuration' }),
).toBeVisible();
const dialogBox = await routeDialog.boundingBox();
expect(dialogBox).not.toBeNull();
expect(dialogBox!.height).toBeLessThan(500);
}); });
test('toggles bot enable/disable state', async ({ page }) => { test('toggles bot enable/disable state', async ({ page }) => {