feat: future task UI

This commit is contained in:
Soulter
2026-06-03 21:14:14 +08:00
parent df6eef052f
commit 8a1988a2c9
9 changed files with 1463 additions and 623 deletions

View File

@@ -200,9 +200,18 @@ class CronJobManager:
return None
return aps_job.next_run_time.astimezone(timezone.utc)
async def _run_job(self, job_id: str) -> None:
async def run_job_now(self, job_id: str) -> None:
await self._run_job(job_id, ignore_enabled=True, delete_run_once=False)
async def _run_job(
self,
job_id: str,
*,
ignore_enabled: bool = False,
delete_run_once: bool = True,
) -> None:
job = await self.db.get_cron_job(job_id)
if not job or not job.enabled:
if not job or (not job.enabled and not ignore_enabled):
return
start_time = datetime.now(timezone.utc)
await self.db.update_cron_job(
@@ -230,7 +239,7 @@ class CronJobManager:
last_error=last_error,
next_run_time=next_run,
)
if job.run_once:
if job.run_once and delete_run_once:
# one-shot: remove after execution regardless of success
await self.delete_job(job_id)

View File

@@ -1,3 +1,4 @@
import asyncio
import traceback
from datetime import datetime, timezone
@@ -20,6 +21,7 @@ class CronRoute(Route):
("/cron/jobs", ("POST", self.create_job)),
("/cron/jobs/<job_id>", ("PATCH", self.update_job)),
("/cron/jobs/<job_id>", ("DELETE", self.delete_job)),
("/cron/jobs/<job_id>/run", ("POST", self.run_job_now)),
]
self.register_routes()
@@ -281,3 +283,19 @@ class CronRoute(Route):
except Exception as e: # noqa: BLE001
logger.error(traceback.format_exc())
return jsonify(Response().error(f"Failed to delete job: {e!s}").__dict__)
async def run_job_now(self, job_id: str):
try:
cron_mgr = self.core_lifecycle.cron_manager
if cron_mgr is None:
return jsonify(
Response().error("Cron manager not initialized").__dict__
)
job = await cron_mgr.db.get_cron_job(job_id)
if not job:
return jsonify(Response().error("Job not found").__dict__)
asyncio.create_task(cron_mgr.run_job_now(job_id))
return jsonify(Response().ok(message="started").__dict__)
except Exception as e: # noqa: BLE001
logger.error(traceback.format_exc())
return jsonify(Response().error(f"Failed to run job: {e!s}").__dict__)

View File

@@ -1,4 +1,4 @@
/* Auto-generated MDI subset 268 icons */
/* Auto-generated MDI subset 271 icons */
/* Do not edit manually. Run: pnpm run subset-icons */
@font-face {
@@ -228,6 +228,10 @@
content: "\F0150";
}
.mdi-clock-time-four-outline::before {
content: "\F144E";
}
.mdi-close::before {
content: "\F0156";
}
@@ -820,6 +824,10 @@
content: "\F040A";
}
.mdi-play-circle-outline::before {
content: "\F040D";
}
.mdi-plus::before {
content: "\F0415";
}
@@ -892,6 +900,10 @@
content: "\F167A";
}
.mdi-send-outline::before {
content: "\F1165";
}
.mdi-server::before {
content: "\F048B";
}

View File

@@ -6,8 +6,9 @@
"page": {
"title": "Future Task Management",
"beta": "Experimental",
"subtitle": "See scheduled tasks for AstrBot. AstrBot will wake up, run them, and deliver the results.",
"subtitle": "AstrBot wakes up at the scheduled time, completes the task, and sends the result back to the target conversation.",
"proactive": {
"link": "Supported platforms",
"supported": "Proactive delivery is available only on the configured platforms below",
"unsupported": "No proactive messaging platforms enabled. Turn them on in Platform settings."
}
@@ -18,9 +19,34 @@
"refresh": "Refresh",
"delete": "Delete",
"cancel": "Cancel",
"close": "Close",
"more": "More actions",
"runNow": "Run now",
"save": "Save",
"submit": "Create"
},
"platformDialog": {
"title": "Supported Platforms",
"description": "Only the following platforms support proactive message delivery. AstrBot can send future task results back only to target conversations on these platforms."
},
"card": {
"onceAt": "One-off · {time}",
"runAt": "Run at: {time}",
"nextRun": "Next run: {time}",
"dailyAt": "Daily at {time}",
"weeklyAt": "Every {day} at {time}",
"monthlyAt": "Monthly on day {day} at {time}",
"everyMinutes": "Every {count} minutes",
"everyHours": "Every {count} hours",
"everyDays": "Every {count} days",
"customCron": "Custom · {cron}"
},
"filters": {
"search": "Search title and content",
"umo": "Filter by UMO",
"noUmos": "No UMOs",
"noMatches": "No matching future tasks."
},
"overview": {
"totalTasks": "Total Tasks",
"totalTasksNote": "Registered future tasks",
@@ -83,11 +109,42 @@
"chatHint": "You can ask AstrBot in chat to create future tasks instead of adding them here.",
"runOnce": "One-off task",
"name": "Task name",
"note": "Task description",
"note": "Task requirements",
"scheduleMode": "Execution time",
"scheduleModes": {
"once": "One-off",
"interval": "Interval",
"daily": "Daily",
"weekly": "Weekly",
"monthly": "Monthly",
"cron": "Custom Cron"
},
"intervalEvery": "Every",
"intervalUnit": "Unit",
"intervalUnits": {
"minutes": "Minutes",
"hours": "Hours",
"days": "Days"
},
"dailyTime": "Time",
"weeklyDay": "Weekday",
"weeklyTime": "Time",
"monthlyDay": "Day",
"monthlyTime": "Time",
"weekdays": {
"sunday": "Sunday",
"monday": "Monday",
"tuesday": "Tuesday",
"wednesday": "Wednesday",
"thursday": "Thursday",
"friday": "Friday",
"saturday": "Saturday"
},
"cron": "Cron expression",
"cronPlaceholder": "0 9 * * *",
"runAt": "Run at",
"session": "Target session (platform_id:message_type:session_id)",
"session": "Deliver to",
"noUmos": "No sessions available",
"timezone": "Timezone (optional, e.g. Asia/Shanghai)",
"enabled": "Enabled"
},
@@ -97,11 +154,14 @@
"updateFailed": "Failed to update",
"deleteSuccess": "Deleted",
"deleteFailed": "Failed to delete",
"sessionRequired": "Session is required",
"noteRequired": "Description is required",
"nameRequired": "Task name is required",
"sessionRequired": "Delivery target is required",
"noteRequired": "Task requirements are required",
"cronRequired": "Cron expression is required",
"runAtRequired": "Please select run time",
"createSuccess": "Created successfully",
"createFailed": "Failed to create"
"createFailed": "Failed to create",
"runStarted": "Started",
"runFailed": "Failed to run"
}
}

View File

@@ -1,107 +1,167 @@
{
"header": {
"eyebrow": "Automation",
"live": "Живая синхронизация"
},
"page": {
"title": "Запланированные задачи",
"beta": "Экспериментальные функции",
"subtitle": "Управление будущими задачами AstrBot. Бот автоматически проснется, выполнит задачу и отправит результат. Требуется включить «Проактивные способности» в конфигурации.",
"proactive": {
"supported": "Отправка результатов поддерживается только на указанных ниже настроенных платформах",
"unsupported": "Нет платформ, поддерживающих проактивные сообщения. Включите их в настройках платформ."
}
},
"actions": {
"create": "Новая задача",
"edit": "Изменить",
"refresh": "Обновить",
"delete": "Удалить",
"cancel": "Отмена",
"save": "Сохранить",
"submit": "Создать"
},
"overview": {
"totalTasks": "Всего задач",
"totalTasksNote": "Все зарегистрированные будущие задачи",
"enabledTasks": "Активные задачи",
"enabledTasksNote": "Задачи, которые будут автоматически выполнены",
"oneOffTasks": "Разовые задачи",
"recurringTasksNote": "Повторяющихся задач: {count}",
"proactivePlatforms": "Проактивные платформы",
"proactivePlatformsNote": "Платформы, способные отправлять результат сами"
},
"section": {
"registered": {
"title": "Список задач",
"subtitle": "Просматривайте зарегистрированные задачи, время запуска и состояние"
},
"delivery": {
"title": "Статус доставки",
"subtitle": "После выполнения задачи результат будет отправлен обратно через поддерживаемые платформы",
"support": "Проактивная доставка",
"available": "Доступна",
"unavailable": "Недоступна",
"enabledPlatforms": "Включенные платформы"
},
"quickCreate": {
"title": "Быстрое создание",
"runMode": "Режим задачи",
"target": "Целевой контекст"
},
"platforms": {
"title": "Поддерживаемые платформы"
}
},
"table": {
"title": "Список задач",
"subtitle": "Отслеживайте cron, целевую сессию, историю запусков и состояние",
"empty": "Задач пока нет.",
"headers": {
"name": "Имя",
"type": "Тип",
"cron": "Cron",
"session": "ID сессии",
"nextRun": "Следующий запуск",
"lastRun": "Последний запуск",
"note": "Описание",
"actions": "Действия"
},
"type": {
"once": "Разовая",
"recurring": "Повторяющаяся",
"activeAgent": "Активный агент",
"workflow": "Рабочий процесс",
"unknown": "{type}"
},
"timezoneLocal": "Местное время",
"notAvailable": "—"
},
"form": {
"title": "Создать задачу",
"editTitle": "Редактировать задачу",
"chatHint": "Вы можете ставить задачи прямо в чате, AstrBot создаст их автоматически без заполнения этой формы.",
"runOnce": "Разовая задача",
"name": "Имя задачи",
"note": "Описание",
"cron": "Cron-выражения",
"cronPlaceholder": "0 9 * * *",
"runAt": "Время запуска",
"session": "Целевая сессия (platform_id:message_type:session_id)",
"timezone": "Часовой пояс (опционально, напр. Europe/Moscow)",
"enabled": "Включено"
},
"messages": {
"loadFailed": "Ошибка загрузки задач",
"updateSuccess": "Задача обновлена",
"updateFailed": "Ошибка обновления",
"deleteSuccess": "Удалено",
"deleteFailed": "Ошибка удаления",
"sessionRequired": "Укажите сессию",
"noteRequired": "Заполните описание",
"cronRequired": "Укажите Cron-выражение",
"runAtRequired": "Выберите время запуска",
"createSuccess": "Задача создана",
"createFailed": "Ошибка создания"
"header": {
"eyebrow": "Automation",
"live": "Живая синхронизация"
},
"page": {
"title": "Запланированные задачи",
"beta": "Экспериментальные функции",
"subtitle": "AstrBot проснется в заданное время, выполнит задачу и отправит результат в целевую беседу.",
"proactive": {
"link": "Поддерживаемые платформы",
"supported": "Отправка результатов поддерживается только на указанных ниже настроенных платформах",
"unsupported": "Нет платформ, поддерживающих проактивные сообщения. Включите их в настройках платформ."
}
},
"actions": {
"create": "Новая задача",
"edit": "Изменить",
"refresh": "Обновить",
"delete": "Удалить",
"cancel": "Отмена",
"close": "Закрыть",
"more": "Другие действия",
"runNow": "Запустить сейчас",
"save": "Сохранить",
"submit": "Создать"
},
"platformDialog": {
"title": "Поддерживаемые платформы",
"description": "Только следующие платформы поддерживают проактивную отправку сообщений. AstrBot сможет отправить результат будущей задачи только в целевые беседы на этих платформах."
},
"card": {
"onceAt": "Один раз · {time}",
"runAt": "Время запуска: {time}",
"nextRun": "Следующий запуск: {time}",
"dailyAt": "Каждый день в {time}",
"weeklyAt": "Каждый {day} в {time}",
"monthlyAt": "Каждый месяц, день {day}, {time}",
"everyMinutes": "Каждые {count} мин.",
"everyHours": "Каждые {count} ч.",
"everyDays": "Каждые {count} дн.",
"customCron": "Вручную · {cron}"
},
"filters": {
"search": "Поиск по названию и содержанию",
"umo": "Фильтр по UMO",
"noUmos": "Нет UMO",
"noMatches": "Нет подходящих будущих задач."
},
"overview": {
"totalTasks": "Всего задач",
"totalTasksNote": "Все зарегистрированные будущие задачи",
"enabledTasks": "Активные задачи",
"enabledTasksNote": "Задачи, которые будут автоматически выполнены",
"oneOffTasks": "Разовые задачи",
"recurringTasksNote": "Повторяющихся задач: {count}",
"proactivePlatforms": "Проактивные платформы",
"proactivePlatformsNote": "Платформы, способные отправлять результат сами"
},
"section": {
"registered": {
"title": "Список задач",
"subtitle": "Просматривайте зарегистрированные задачи, время запуска и состояние"
},
"delivery": {
"title": "Статус доставки",
"subtitle": "После выполнения задачи результат будет отправлен обратно через поддерживаемые платформы",
"support": "Проактивная доставка",
"available": "Доступна",
"unavailable": "Недоступна",
"enabledPlatforms": "Включенные платформы"
},
"quickCreate": {
"title": "Быстрое создание",
"runMode": "Режим задачи",
"target": "Целевой контекст"
},
"platforms": {
"title": "Поддерживаемые платформы"
}
},
"table": {
"title": "Список задач",
"subtitle": "Отслеживайте cron, целевую сессию, историю запусков и состояние",
"empty": "Задач пока нет.",
"headers": {
"name": "Имя",
"type": "Тип",
"cron": "Cron",
"session": "ID сессии",
"nextRun": "Следующий запуск",
"lastRun": "Последний запуск",
"note": "Описание",
"actions": "Действия"
},
"type": {
"once": "Разовая",
"recurring": "Повторяющаяся",
"activeAgent": "Активный агент",
"workflow": "Рабочий процесс",
"unknown": "{type}"
},
"timezoneLocal": "Местное время",
"notAvailable": "—"
},
"form": {
"title": "Создать задачу",
"editTitle": "Редактировать задачу",
"chatHint": "Вы можете ставить задачи прямо в чате, AstrBot создаст их автоматически без заполнения этой формы.",
"runOnce": "Разовая задача",
"name": "Имя задачи",
"note": "Требования задачи",
"scheduleMode": "Время выполнения",
"scheduleModes": {
"once": "Один раз",
"interval": "Интервал",
"daily": "Каждый день",
"weekly": "Каждую неделю",
"monthly": "Каждый месяц",
"cron": "Cron вручную"
},
"intervalEvery": "Каждые",
"intervalUnit": "Единица",
"intervalUnits": {
"minutes": "Минуты",
"hours": "Часы",
"days": "Дни"
},
"dailyTime": "Время",
"weeklyDay": "День недели",
"weeklyTime": "Время",
"monthlyDay": "День",
"monthlyTime": "Время",
"weekdays": {
"sunday": "Воскресенье",
"monday": "Понедельник",
"tuesday": "Вторник",
"wednesday": "Среда",
"thursday": "Четверг",
"friday": "Пятница",
"saturday": "Суббота"
},
"cron": "Cron-выражения",
"cronPlaceholder": "0 9 * * *",
"runAt": "Время запуска",
"session": "Доставить в",
"noUmos": "Нет доступных сессий",
"timezone": "Часовой пояс (опционально, напр. Europe/Moscow)",
"enabled": "Включено"
},
"messages": {
"loadFailed": "Ошибка загрузки задач",
"updateSuccess": "Задача обновлена",
"updateFailed": "Ошибка обновления",
"deleteSuccess": "Удалено",
"deleteFailed": "Ошибка удаления",
"nameRequired": "Укажите имя задачи",
"sessionRequired": "Укажите цель доставки",
"noteRequired": "Заполните требования задачи",
"cronRequired": "Укажите Cron-выражение",
"runAtRequired": "Выберите время запуска",
"createSuccess": "Задача создана",
"createFailed": "Ошибка создания",
"runStarted": "Запущено",
"runFailed": "Ошибка запуска"
}
}

View File

@@ -4,10 +4,11 @@
"live": "实时同步"
},
"page": {
"title": "未来任务管理",
"title": "未来任务",
"beta": "实验性",
"subtitle": "AstrBot 可以被自动唤醒然后执行任务,并将结果告知任务布置方。需要先在配置文件中启用“主动型能力”。",
"subtitle": "AstrBot 会在设定时间自动唤醒,完成任务后把结果投递回目标会话。",
"proactive": {
"link": "支持的消息平台",
"supported": "主动发送结果仅支持以下您已配置的平台",
"unsupported": "暂无支持主动消息的平台,请在平台设置中开启。"
}
@@ -18,9 +19,34 @@
"refresh": "刷新",
"delete": "删除",
"cancel": "取消",
"close": "关闭",
"more": "更多操作",
"runNow": "立即执行",
"save": "保存",
"submit": "创建"
},
"platformDialog": {
"title": "支持的消息平台",
"description": "只有以下平台支持主动推送消息。未来任务完成后AstrBot 才能把结果投递回这些平台的目标会话。"
},
"card": {
"onceAt": "一次性 · {time}",
"runAt": "执行时间:{time}",
"nextRun": "下次执行:{time}",
"dailyAt": "每天 {time}",
"weeklyAt": "每周{day} {time}",
"monthlyAt": "每月 {day} 日 {time}",
"everyMinutes": "每隔 {count} 分钟",
"everyHours": "每隔 {count} 小时",
"everyDays": "每隔 {count} 天",
"customCron": "自定义 · {cron}"
},
"filters": {
"search": "搜索任务名称和内容",
"umo": "按 UMO 筛选",
"noUmos": "暂无 UMO",
"noMatches": "没有匹配的未来任务。"
},
"overview": {
"totalTasks": "任务总数",
"totalTasksNote": "当前已注册的未来任务",
@@ -83,11 +109,42 @@
"chatHint": "你可以直接通过聊天的方式来让 AstrBot 创建未来任务,而不必在此添加。",
"runOnce": "一次性任务",
"name": "任务名称",
"note": "任务说明",
"note": "任务需求",
"scheduleMode": "执行时间",
"scheduleModes": {
"once": "一次性",
"interval": "间隔",
"daily": "每天",
"weekly": "每周",
"monthly": "每个月",
"cron": "自定义"
},
"intervalEvery": "每隔",
"intervalUnit": "单位",
"intervalUnits": {
"minutes": "分钟",
"hours": "小时",
"days": "天"
},
"dailyTime": "时间",
"weeklyDay": "星期",
"weeklyTime": "时间",
"monthlyDay": "日期",
"monthlyTime": "时间",
"weekdays": {
"sunday": "周日",
"monday": "周一",
"tuesday": "周二",
"wednesday": "周三",
"thursday": "周四",
"friday": "周五",
"saturday": "周六"
},
"cron": "Cron 表达式",
"cronPlaceholder": "0 9 * * *",
"runAt": "执行时间",
"session": "目标 session (platform_id:message_type:session_id)",
"session": "投递到",
"noUmos": "暂无可用会话",
"timezone": "时区(可选,如 Asia/Shanghai",
"enabled": "启用"
},
@@ -97,11 +154,14 @@
"updateFailed": "更新失败",
"deleteSuccess": "已删除",
"deleteFailed": "删除失败",
"sessionRequired": "请填写 session",
"noteRequired": "请填写说明",
"nameRequired": "请填写任务名称",
"sessionRequired": "请选择投递目标",
"noteRequired": "请填写任务需求",
"cronRequired": "请填写 Cron 表达式",
"runAtRequired": "请选择执行时间",
"createSuccess": "创建成功",
"createFailed": "创建失败"
"createFailed": "创建失败",
"runStarted": "已开始执行",
"runFailed": "执行失败"
}
}

File diff suppressed because it is too large Load Diff