mirror of
https://github.com/NanmiCoder/cc-haha
synced 2026-07-17 13:13:35 +08:00
- Add 7 frequency modes (every N min/hours, daily, weekdays, specific days, monthly, custom cron) with progressive disclosure UI - Add "Run Now" button with confirmation popover and fire-and-forget API - Add execution logs panel (TaskRunsPanel) with auto-polling and accordion behavior - Add task edit mode with cron reverse-parsing (parseCron) to populate form - Add server-side extractAssistantText to store meaningful AI responses instead of raw NDJSON - Fix session linking: pass --session-id to CLI subprocess so "View conversation" navigates to actual content - Fix MACRO undefined error by adding --preload to Bun.spawn - Add confirmation popovers for all destructive actions (run/disable/delete) - Add DayOfWeekPicker component for specific-days scheduling - Add cronDescribe utility with i18n support and unit tests - Display task creation time and last run time - Add ~50 i18n keys (en/zh) for all new UI elements Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
47 lines
1.5 KiB
TypeScript
47 lines
1.5 KiB
TypeScript
import { useState } from 'react'
|
|
import type { CronTask } from '../../types/task'
|
|
import { TaskRow } from './TaskRow'
|
|
import { useTranslation } from '../../i18n'
|
|
|
|
type Props = {
|
|
tasks: CronTask[]
|
|
}
|
|
|
|
export function TaskList({ tasks }: Props) {
|
|
const t = useTranslation()
|
|
const enabledCount = tasks.filter((task) => task.enabled).length
|
|
const [expandedLogsId, setExpandedLogsId] = useState<string | null>(null)
|
|
|
|
return (
|
|
<div>
|
|
{/* Stats */}
|
|
<div className="grid grid-cols-3 gap-4 mb-6">
|
|
<StatCard label={t('tasks.totalTasks')} value={String(tasks.length)} />
|
|
<StatCard label={t('tasks.active')} value={String(enabledCount)} />
|
|
<StatCard label={t('tasks.disabled')} value={String(tasks.length - enabledCount)} />
|
|
</div>
|
|
|
|
{/* Task rows — accordion: only one logs panel open at a time */}
|
|
<div className="flex flex-col">
|
|
{tasks.map((task) => (
|
|
<TaskRow
|
|
key={task.id}
|
|
task={task}
|
|
showLogs={expandedLogsId === task.id}
|
|
onToggleLogs={() => setExpandedLogsId(expandedLogsId === task.id ? null : task.id)}
|
|
/>
|
|
))}
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
function StatCard({ label, value }: { label: string; value: string }) {
|
|
return (
|
|
<div className="px-4 py-3 rounded-[var(--radius-lg)] bg-[var(--color-surface-info)]">
|
|
<div className="text-2xl font-bold text-[var(--color-text-primary)]">{value}</div>
|
|
<div className="text-xs text-[var(--color-text-secondary)]">{label}</div>
|
|
</div>
|
|
)
|
|
}
|