fix(webui): reduce automation dashboard copy
This commit is contained in:
@@ -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>
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -466,8 +466,6 @@
|
||||
"automations": {
|
||||
"kicker": "Automatisations de l’espace",
|
||||
"title": "Automatisations",
|
||||
"description": "Passez en revue les rappels cron, tours récurrents de l’agent, 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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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 秒未満"
|
||||
|
||||
@@ -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초 미만"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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 秒"
|
||||
|
||||
@@ -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 秒"
|
||||
|
||||
@@ -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");
|
||||
});
|
||||
|
||||
|
||||
@@ -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",
|
||||
|
||||
Reference in New Issue
Block a user