fix(webui): reduce automation dashboard copy

This commit is contained in:
chengyongru
2026-06-14 01:03:53 +08:00
parent 17e3183598
commit 5f2f694034
12 changed files with 60 additions and 94 deletions
+38 -62
View File
@@ -1264,18 +1264,6 @@ export function SettingsView({
}
};
const refreshAutomations = async () => {
setAutomationsLoading(true);
setAutomationsError(null);
try {
setAutomations(await fetchAutomations(token));
} catch (err) {
setAutomationsError((err as Error).message);
} finally {
setAutomationsLoading(false);
}
};
const handleAutomationAction = async (
action: AutomationAction,
job: SessionAutomationJob,
@@ -1585,7 +1573,6 @@ export function SettingsView({
error={automationsError}
onQueryChange={setAutomationsQuery}
onFilterChange={setAutomationsFilter}
onRefresh={refreshAutomations}
onAction={handleAutomationAction}
onRequestDelete={setAutomationPendingDelete}
/>
@@ -3350,7 +3337,6 @@ function AutomationsSettings({
error,
onQueryChange,
onFilterChange,
onRefresh,
onAction,
onRequestDelete,
}: {
@@ -3362,7 +3348,6 @@ function AutomationsSettings({
error: string | null;
onQueryChange: (value: string) => void;
onFilterChange: (value: AutomationFilter) => void;
onRefresh: () => void;
onAction: (action: AutomationAction, job: SessionAutomationJob) => void | Promise<void>;
onRequestDelete: (job: SessionAutomationJob) => void;
}) {
@@ -3389,38 +3374,16 @@ function AutomationsSettings({
return (
<div className="space-y-5">
<section className="rounded-[24px] border border-border/50 bg-card/82 px-4 py-4 shadow-[0_18px_65px_rgba(15,23,42,0.07)] backdrop-blur-xl sm:px-5">
<div className="flex flex-col gap-3 lg:flex-row lg:items-center lg:justify-between">
<p className="max-w-[38rem] text-[13px] leading-6 text-muted-foreground">
{tx(
"settings.automations.description",
"Review cron reminders, recurring agent turns, one-time jobs, and protected system jobs.",
)}
</p>
<div className="flex shrink-0 flex-wrap gap-2">
<Button
type="button"
variant="outline"
onClick={onRefresh}
disabled={loading}
className="h-9 rounded-full px-3 text-[13px]"
>
{loading ? (
<Loader2 className="mr-2 h-3.5 w-3.5 animate-spin" aria-hidden />
) : (
<RotateCcw className="mr-2 h-3.5 w-3.5" aria-hidden />
)}
{tx("settings.automations.refresh", "Refresh")}
</Button>
<Button asChild className="h-9 rounded-full px-3 text-[13px]">
<a href="#/new">
<Plus className="mr-2 h-3.5 w-3.5" aria-hidden />
{tx("settings.automations.newInChat", "New in chat")}
</a>
</Button>
</div>
<div className="flex justify-end">
<Button asChild className="h-9 rounded-full px-3 text-[13px]">
<a href="#/new">
<Plus className="mr-2 h-3.5 w-3.5" aria-hidden />
{tx("settings.automations.newInChat", "New in chat")}
</a>
</Button>
</div>
<div className="mt-5 grid gap-2 sm:grid-cols-4">
<div className="mt-4 grid gap-2 sm:grid-cols-4">
<AutomationStat label={tx("settings.automations.stats.active", "Active")} value={activeCount} />
<AutomationStat label={tx("settings.automations.stats.paused", "Paused")} value={pausedCount} />
<AutomationStat label={tx("settings.automations.stats.failed", "Failed")} value={failedCount} />
@@ -3569,23 +3532,36 @@ function AutomationRow({
) : null}
{history.length ? (
<div className="mt-3 flex flex-wrap gap-1.5">
{history.slice(-4).map((record) => (
<span
key={`${record.run_at_ms}:${record.status}`}
className={cn(
"rounded-full px-2 py-1 text-[11px]",
record.status === "error"
? "bg-destructive/10 text-destructive"
: record.status === "skipped"
? "bg-amber-500/10 text-amber-700 dark:text-amber-300"
: "bg-emerald-500/10 text-emerald-700 dark:text-emerald-300",
)}
title={record.error || fmtDateTime(record.run_at_ms, locale)}
>
{automationRunStatusLabel(record.status, tx)} · {formatAutomationRunDuration(record.duration_ms, locale, tx)}
</span>
))}
<div className="mt-3">
<div className="mb-1.5 text-[11px] font-medium uppercase tracking-normal text-muted-foreground">
{tx("settings.automations.history.recent", "Recent runs")}
</div>
<div className="flex flex-wrap gap-1.5">
{history.slice(-4).map((record) => {
const statusLabel = automationRunStatusLabel(record.status, tx);
const duration = formatAutomationRunDuration(record.duration_ms, locale, tx);
const visibleLabel = record.status === "ok" ? duration : `${statusLabel} · ${duration}`;
const detail = record.error || fmtDateTime(record.run_at_ms, locale);
const accessibleLabel = `${statusLabel} · ${duration} · ${detail}`;
return (
<span
key={`${record.run_at_ms}:${record.status}`}
className={cn(
"rounded-full px-2 py-1 text-[11px]",
record.status === "error"
? "bg-destructive/10 text-destructive"
: record.status === "skipped"
? "bg-amber-500/10 text-amber-700 dark:text-amber-300"
: "bg-emerald-500/10 text-emerald-700 dark:text-emerald-300",
)}
title={accessibleLabel}
aria-label={accessibleLabel}
>
{visibleLabel}
</span>
);
})}
</div>
</div>
) : null}
</div>
+2 -3
View File
@@ -466,8 +466,6 @@
"automations": {
"kicker": "Workspace automations",
"title": "Automations",
"description": "Review cron reminders, recurring agent turns, one-time jobs, and protected system jobs.",
"refresh": "Refresh",
"newInChat": "New in chat",
"stats": {
"active": "Active",
@@ -551,7 +549,8 @@
"history": {
"ok": "Completed",
"error": "Error",
"skipped": "Skipped"
"skipped": "Skipped",
"recent": "Recent runs"
},
"duration": {
"lessThanSecond": "< 1 second"
+2 -3
View File
@@ -466,8 +466,6 @@
"automations": {
"kicker": "Automatizaciones del espacio",
"title": "Automatizaciones",
"description": "Revisa recordatorios cron, turnos recurrentes del agente, tareas de una vez y tareas protegidas del sistema.",
"refresh": "Actualizar",
"newInChat": "Crear en chat",
"stats": {
"active": "Activas",
@@ -551,7 +549,8 @@
"history": {
"ok": "Completada",
"error": "Error",
"skipped": "Omitida"
"skipped": "Omitida",
"recent": "Ejecuciones recientes"
},
"duration": {
"lessThanSecond": "menos de 1 segundo"
+2 -3
View File
@@ -466,8 +466,6 @@
"automations": {
"kicker": "Automatisations de lespace",
"title": "Automatisations",
"description": "Passez en revue les rappels cron, tours récurrents de lagent, tâches ponctuelles et tâches système protégées.",
"refresh": "Actualiser",
"newInChat": "Créer dans le chat",
"stats": {
"active": "Actives",
@@ -551,7 +549,8 @@
"history": {
"ok": "Terminée",
"error": "Erreur",
"skipped": "Ignorée"
"skipped": "Ignorée",
"recent": "Exécutions récentes"
},
"duration": {
"lessThanSecond": "moins de 1 seconde"
+2 -3
View File
@@ -466,8 +466,6 @@
"automations": {
"kicker": "Otomasi ruang kerja",
"title": "Otomasi",
"description": "Tinjau pengingat cron, giliran agen berulang, tugas sekali jalan, dan tugas sistem terlindungi.",
"refresh": "Segarkan",
"newInChat": "Buat di chat",
"stats": {
"active": "Aktif",
@@ -551,7 +549,8 @@
"history": {
"ok": "Selesai",
"error": "Error",
"skipped": "Dilewati"
"skipped": "Dilewati",
"recent": "Eksekusi terbaru"
},
"duration": {
"lessThanSecond": "kurang dari 1 detik"
+2 -3
View File
@@ -466,8 +466,6 @@
"automations": {
"kicker": "ワークスペースの自動タスク",
"title": "自動タスク",
"description": "cron リマインダー、定期的な agent ターン、一回限りのタスク、保護されたシステムタスクを確認できます。",
"refresh": "更新",
"newInChat": "チャットで作成",
"stats": {
"active": "実行中",
@@ -551,7 +549,8 @@
"history": {
"ok": "完了",
"error": "エラー",
"skipped": "スキップ"
"skipped": "スキップ",
"recent": "最近の実行"
},
"duration": {
"lessThanSecond": "1 秒未満"
+2 -3
View File
@@ -466,8 +466,6 @@
"automations": {
"kicker": "작업 공간 자동화",
"title": "자동화",
"description": "cron 알림, 반복 agent 작업, 일회성 작업, 보호된 시스템 작업을 확인합니다.",
"refresh": "새로 고침",
"newInChat": "채팅에서 만들기",
"stats": {
"active": "활성",
@@ -551,7 +549,8 @@
"history": {
"ok": "완료",
"error": "오류",
"skipped": "건너뜀"
"skipped": "건너뜀",
"recent": "최근 실행"
},
"duration": {
"lessThanSecond": "1초 미만"
+2 -3
View File
@@ -466,8 +466,6 @@
"automations": {
"kicker": "Tự động hóa không gian làm việc",
"title": "Tự động hóa",
"description": "Xem nhắc nhở cron, lượt agent định kỳ, tác vụ một lần và tác vụ hệ thống được bảo vệ.",
"refresh": "Làm mới",
"newInChat": "Tạo trong chat",
"stats": {
"active": "Đang chạy",
@@ -551,7 +549,8 @@
"history": {
"ok": "Hoàn tất",
"error": "Lỗi",
"skipped": "Đã bỏ qua"
"skipped": "Đã bỏ qua",
"recent": "Lượt chạy gần đây"
},
"duration": {
"lessThanSecond": "dưới 1 giây"
+2 -3
View File
@@ -466,8 +466,6 @@
"automations": {
"kicker": "工作区自动任务",
"title": "自动任务",
"description": "统一查看 cron 提醒、周期性 agent 任务、一次性任务和系统任务。",
"refresh": "刷新",
"newInChat": "在聊天中创建",
"stats": {
"active": "运行中",
@@ -551,7 +549,8 @@
"history": {
"ok": "完成",
"error": "错误",
"skipped": "已跳过"
"skipped": "已跳过",
"recent": "最近运行"
},
"duration": {
"lessThanSecond": "不到 1 秒"
+2 -3
View File
@@ -466,8 +466,6 @@
"automations": {
"kicker": "工作區自動任務",
"title": "自動任務",
"description": "集中查看 cron 提醒、週期性 agent 任務、一次性任務和系統任務。",
"refresh": "重新整理",
"newInChat": "在聊天中建立",
"stats": {
"active": "執行中",
@@ -551,7 +549,8 @@
"history": {
"ok": "完成",
"error": "錯誤",
"skipped": "已略過"
"skipped": "已略過",
"recent": "最近執行"
},
"duration": {
"lessThanSecond": "不到 1 秒"
+3 -3
View File
@@ -506,14 +506,14 @@ describe("App layout", () => {
fireEvent.click(within(sidebar).getByRole("button", { name: "自动任务" }));
expect(await screen.findByRole("heading", { name: "自动任务" })).toBeInTheDocument();
expect(screen.getByText("统一查看 cron 提醒、周期性 agent 任务、一次性任务和系统任务。")).toBeInTheDocument();
expect(screen.getByRole("button", { name: "刷新" })).toBeInTheDocument();
expect(screen.getByText("任务队列")).toBeInTheDocument();
expect(screen.getByText("每日检查")).toBeInTheDocument();
expect(screen.getByText("检查仓库状态")).toBeInTheDocument();
expect(screen.getByText("每 1天")).toBeInTheDocument();
expect(screen.getByText("完成 · 不到 1 秒")).toBeInTheDocument();
expect(screen.getByText("最近运行")).toBeInTheDocument();
expect(screen.getByText("不到 1 秒")).toBeInTheDocument();
expect(screen.queryByText("Workspace automations")).not.toBeInTheDocument();
expect(screen.queryByRole("button", { name: "刷新" })).not.toBeInTheDocument();
expect(document.title).toBe("自动任务 · nanobot");
});
+1 -2
View File
@@ -49,8 +49,6 @@ const LOCALIZED_SETTINGS_COPY_KEYS = [
"settings.nav.advanced",
"sidebar.automations",
"settings.automations.title",
"settings.automations.description",
"settings.automations.refresh",
"settings.automations.newInChat",
"settings.automations.filters.active",
"settings.automations.queue",
@@ -59,6 +57,7 @@ const LOCALIZED_SETTINGS_COPY_KEYS = [
"settings.automations.labels.schedule",
"settings.automations.status.active",
"settings.automations.history.ok",
"settings.automations.history.recent",
"settings.automations.duration.lessThanSecond",
"settings.automations.deleteTitle",
"settings.sections.interface",