mirror of
https://github.com/nexu-io/open-design.git
synced 2026-05-31 19:04:39 +07:00
Merge 0ea3895b16 into 53fb175855
This commit is contained in:
commit
593f79ca2c
7 changed files with 65 additions and 9 deletions
|
|
@ -12,6 +12,7 @@ import type {
|
|||
import { Icon } from './Icon';
|
||||
import { navigate } from '../router';
|
||||
import { useT } from '../i18n';
|
||||
import { localizeRunFailureReason } from '../i18n/runErrors';
|
||||
import type { Dict } from '../i18n/types';
|
||||
import { useAnalytics } from '../analytics/provider';
|
||||
import { trackAutomationsClick } from '../analytics/events';
|
||||
|
|
@ -174,14 +175,16 @@ function formatRunTimestamp(ts: number): string {
|
|||
});
|
||||
}
|
||||
|
||||
function runFailureReason(run: {
|
||||
status: RoutineRun['status'];
|
||||
error?: string | null;
|
||||
summary?: string | null;
|
||||
} | null | undefined): string | null {
|
||||
function runFailureReason(
|
||||
run: {
|
||||
status: RoutineRun['status'];
|
||||
error?: string | null;
|
||||
summary?: string | null;
|
||||
} | null | undefined,
|
||||
t: TranslateFn,
|
||||
): string | null {
|
||||
if (!run || run.status !== 'failed') return null;
|
||||
const reason = (run.error || run.summary || '').trim();
|
||||
return reason || null;
|
||||
return localizeRunFailureReason(run.error || run.summary || '', t);
|
||||
}
|
||||
|
||||
type FormState = {
|
||||
|
|
@ -414,7 +417,7 @@ function RunHistory({
|
|||
return (
|
||||
<ul className="routines-history">
|
||||
{runs.map((r) => {
|
||||
const failureReason = runFailureReason(r);
|
||||
const failureReason = runFailureReason(r, t);
|
||||
return (
|
||||
<li key={r.id} className="routines-history-row">
|
||||
<StatusPill status={r.status} t={t} />
|
||||
|
|
@ -763,7 +766,7 @@ export function RoutinesSection({ onClose }: RoutinesSectionProps) {
|
|||
: t('routines.targetCreate');
|
||||
const isBusy = busyId === r.id;
|
||||
const isExpanded = expandedId === r.id;
|
||||
const failureReason = runFailureReason(r.lastRun);
|
||||
const failureReason = runFailureReason(r.lastRun, t);
|
||||
return (
|
||||
<li key={r.id} className={`routines-card routines-item${r.enabled ? '' : ' is-disabled'}`}>
|
||||
<div className="routines-item-head">
|
||||
|
|
|
|||
|
|
@ -967,6 +967,8 @@ export const en: Dict = {
|
|||
'Delete this automation? Past runs and their projects are kept.',
|
||||
'routines.errorPickProject':
|
||||
'Pick a project to reuse, or switch to “Create new each run”',
|
||||
'routines.errorAgentEmptyOutput':
|
||||
'Agent completed without producing any output. The model or provider may have returned an empty response — check the agent logs for upstream errors.',
|
||||
'entry.helpAria': 'Help',
|
||||
'entry.helpMenuAria': 'Help menu',
|
||||
'entry.helpGetHelp': 'Get help on GitHub',
|
||||
|
|
|
|||
|
|
@ -964,6 +964,8 @@ export const zhCN: Dict = {
|
|||
'routines.status.canceled': '已取消',
|
||||
'routines.confirmDelete': '删除此自动化?过往运行记录及其项目将予以保留。',
|
||||
'routines.errorPickProject': '请选择要复用的项目,或切换为“每次运行新建项目”。',
|
||||
'routines.errorAgentEmptyOutput':
|
||||
'代理已完成运行但未产生任何输出。模型或提供商可能返回了空响应,请检查代理日志中的上游错误。',
|
||||
'entry.helpAria': '帮助',
|
||||
'entry.helpMenuAria': '帮助菜单',
|
||||
'entry.helpGetHelp': '在 GitHub 上获取帮助',
|
||||
|
|
|
|||
|
|
@ -698,6 +698,8 @@ export const zhTW: Dict = {
|
|||
'routines.status.canceled': '已取消',
|
||||
'routines.confirmDelete': '刪除此自動化?過往執行記錄及其專案將予以保留。',
|
||||
'routines.errorPickProject': '請選擇要重複使用的專案,或切換為「每次執行建立新專案」。',
|
||||
'routines.errorAgentEmptyOutput':
|
||||
'代理已完成執行但未產生任何輸出。模型或提供商可能返回了空回應,請檢查代理日誌中的上游錯誤。',
|
||||
|
||||
'newproj.tabPrototype': '原型',
|
||||
'newproj.tabLiveArtifact': '即時成品',
|
||||
|
|
|
|||
20
apps/web/src/i18n/runErrors.ts
Normal file
20
apps/web/src/i18n/runErrors.ts
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
import type { Dict } from './types';
|
||||
|
||||
type TranslateFn = (key: keyof Dict, vars?: Record<string, string | number>) => string;
|
||||
|
||||
const AGENT_EMPTY_OUTPUT_EN =
|
||||
'Agent completed without producing any output. The model or provider may have returned an empty response — check the agent logs for upstream errors.';
|
||||
|
||||
const KNOWN_RUN_FAILURE_KEYS: Record<string, keyof Dict> = {
|
||||
[AGENT_EMPTY_OUTPUT_EN]: 'routines.errorAgentEmptyOutput',
|
||||
};
|
||||
|
||||
export function localizeRunFailureReason(
|
||||
reason: string | null | undefined,
|
||||
t: TranslateFn,
|
||||
): string | null {
|
||||
if (!reason?.trim()) return null;
|
||||
const trimmed = reason.trim();
|
||||
const key = KNOWN_RUN_FAILURE_KEYS[trimmed];
|
||||
return key ? t(key) : trimmed;
|
||||
}
|
||||
|
|
@ -1279,6 +1279,7 @@ export interface Dict {
|
|||
'routines.status.canceled': string;
|
||||
'routines.confirmDelete': string;
|
||||
'routines.errorPickProject': string;
|
||||
'routines.errorAgentEmptyOutput': string;
|
||||
// Bottom-of-rail help menu
|
||||
'entry.helpAria': string;
|
||||
'entry.helpMenuAria': string;
|
||||
|
|
|
|||
26
apps/web/tests/i18n/runErrors.test.ts
Normal file
26
apps/web/tests/i18n/runErrors.test.ts
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
import { describe, expect, it } from 'vitest';
|
||||
|
||||
import { localizeRunFailureReason } from '../../src/i18n/runErrors';
|
||||
import type { Dict } from '../../src/i18n/types';
|
||||
|
||||
const t = ((key: keyof Dict) => {
|
||||
if (key === 'routines.errorAgentEmptyOutput') {
|
||||
return '代理已完成运行但未产生任何输出。';
|
||||
}
|
||||
return key;
|
||||
}) as (key: keyof Dict) => string;
|
||||
|
||||
describe('localizeRunFailureReason', () => {
|
||||
it('maps known daemon empty-output errors to i18n', () => {
|
||||
const reason =
|
||||
'Agent completed without producing any output. The model or provider may have returned an empty response — check the agent logs for upstream errors.';
|
||||
|
||||
expect(localizeRunFailureReason(reason, t)).toBe(
|
||||
'代理已完成运行但未产生任何输出。',
|
||||
);
|
||||
});
|
||||
|
||||
it('passes through unknown errors unchanged', () => {
|
||||
expect(localizeRunFailureReason('Network timeout', t)).toBe('Network timeout');
|
||||
});
|
||||
});
|
||||
Loading…
Reference in a new issue