fix(webui): avoid fake automation origins
This commit is contained in:
@@ -152,11 +152,11 @@ def _origin_payload(
|
||||
job: CronJob,
|
||||
session_manager: _SessionManagerLike | None,
|
||||
) -> dict[str, Any] | None:
|
||||
session_key = job.payload.session_key
|
||||
if not session_key and job.payload.origin_channel and job.payload.origin_chat_id:
|
||||
session_key = f"{job.payload.origin_channel}:{job.payload.origin_chat_id}"
|
||||
if not session_key:
|
||||
channel = job.payload.origin_channel
|
||||
chat_id = job.payload.origin_chat_id
|
||||
if not channel or not chat_id:
|
||||
return None
|
||||
session_key = f"{channel}:{chat_id}"
|
||||
|
||||
title = ""
|
||||
preview = ""
|
||||
@@ -166,7 +166,6 @@ def _origin_payload(
|
||||
title = str(data.get("title") or "")
|
||||
preview = _session_preview(data.get("messages"))
|
||||
|
||||
channel, _, chat_id = session_key.partition(":")
|
||||
return {
|
||||
"session_key": session_key,
|
||||
"channel": channel,
|
||||
|
||||
@@ -826,6 +826,12 @@ async def test_webui_automations_route_lists_all_jobs_and_allows_user_actions(
|
||||
origin_channel="websocket",
|
||||
origin_chat_id="abc",
|
||||
)
|
||||
legacy_job = cron.add_job(
|
||||
name="english-quiz",
|
||||
schedule=CronSchedule(kind="every", every_ms=3_600_000),
|
||||
message="Practice English",
|
||||
session_key="unified:default",
|
||||
)
|
||||
cron.register_system_job(
|
||||
CronJob(
|
||||
id="heartbeat",
|
||||
@@ -862,6 +868,8 @@ async def test_webui_automations_route_lists_all_jobs_and_allows_user_actions(
|
||||
assert by_id[user_job.id]["state"]["run_history"] == []
|
||||
assert by_id[user_job.id]["origin"]["session_key"] == "websocket:abc"
|
||||
assert by_id[user_job.id]["origin"]["preview"] == "hi"
|
||||
assert by_id[legacy_job.id]["payload"]["session_key"] == "unified:default"
|
||||
assert by_id[legacy_job.id]["origin"] is None
|
||||
assert by_id["heartbeat"]["protected"] is True
|
||||
|
||||
disabled = await _http_get(
|
||||
|
||||
@@ -3521,6 +3521,9 @@ function AutomationRow({
|
||||
t(key, { defaultValue: fallback, ...(values ?? {}) });
|
||||
const status = automationStatus(job, tx);
|
||||
const origin = automationOriginLabel(job, tx);
|
||||
const originHref = job.origin?.channel === "websocket"
|
||||
? `#/chat/${encodeURIComponent(job.origin.session_key)}`
|
||||
: null;
|
||||
const history = job.state.run_history ?? [];
|
||||
const canManage = !job.protected;
|
||||
const canRun = canManage && job.enabled && !job.state.pending;
|
||||
@@ -3554,11 +3557,11 @@ function AutomationRow({
|
||||
<AutomationDetail label={tx("settings.automations.labels.last", "Last")}>
|
||||
{formatAutomationLast(job, locale, tx)}
|
||||
</AutomationDetail>
|
||||
<AutomationDetail label={tx("settings.automations.labels.origin", "Origin")}>
|
||||
{job.origin?.session_key ? (
|
||||
<AutomationDetail label={tx("settings.automations.labels.origin", "Linked chat")}>
|
||||
{originHref ? (
|
||||
<a
|
||||
className="inline-flex max-w-full items-center gap-1 text-foreground/80 underline-offset-2 hover:underline"
|
||||
href={`#/chat/${encodeURIComponent(job.origin.session_key)}`}
|
||||
href={originHref}
|
||||
>
|
||||
<span className="truncate">{origin}</span>
|
||||
<ExternalLink className="h-3 w-3 shrink-0" aria-hidden />
|
||||
@@ -3751,7 +3754,10 @@ function automationOriginLabel(
|
||||
): string {
|
||||
if (job.protected) return tx("settings.automations.origin.system", "System");
|
||||
const origin = job.origin;
|
||||
if (!origin) return tx("settings.automations.origin.unknown", "Unknown session");
|
||||
if (!origin && job.payload.kind === "agent_turn") {
|
||||
return tx("settings.automations.origin.legacy", "Recreate in target chat");
|
||||
}
|
||||
if (!origin) return tx("settings.automations.origin.unknown", "No linked chat");
|
||||
return origin.title || origin.preview || origin.session_key;
|
||||
}
|
||||
|
||||
|
||||
@@ -493,7 +493,7 @@
|
||||
"schedule": "Schedule",
|
||||
"next": "Next",
|
||||
"last": "Last",
|
||||
"origin": "Origin"
|
||||
"origin": "Linked chat"
|
||||
},
|
||||
"runNow": "Run now",
|
||||
"pause": "Pause",
|
||||
@@ -512,7 +512,8 @@
|
||||
},
|
||||
"origin": {
|
||||
"system": "System",
|
||||
"unknown": "Unknown session"
|
||||
"unknown": "No linked chat",
|
||||
"legacy": "Recreate in target chat"
|
||||
},
|
||||
"schedule": {
|
||||
"at": "At {{time}}",
|
||||
|
||||
@@ -493,7 +493,7 @@
|
||||
"schedule": "Programación",
|
||||
"next": "Siguiente",
|
||||
"last": "Última",
|
||||
"origin": "Origen"
|
||||
"origin": "Chat vinculado"
|
||||
},
|
||||
"runNow": "Ejecutar ahora",
|
||||
"pause": "Pausar",
|
||||
@@ -512,7 +512,8 @@
|
||||
},
|
||||
"origin": {
|
||||
"system": "Sistema",
|
||||
"unknown": "Sesión desconocida"
|
||||
"unknown": "Sin chat vinculado",
|
||||
"legacy": "Recréala en el chat de destino"
|
||||
},
|
||||
"schedule": {
|
||||
"at": "A las {{time}}",
|
||||
|
||||
@@ -493,7 +493,7 @@
|
||||
"schedule": "Planning",
|
||||
"next": "Prochaine",
|
||||
"last": "Dernière",
|
||||
"origin": "Origine"
|
||||
"origin": "Discussion liée"
|
||||
},
|
||||
"runNow": "Exécuter maintenant",
|
||||
"pause": "Mettre en pause",
|
||||
@@ -512,7 +512,8 @@
|
||||
},
|
||||
"origin": {
|
||||
"system": "Système",
|
||||
"unknown": "Session inconnue"
|
||||
"unknown": "Aucune discussion liée",
|
||||
"legacy": "Recréez-la dans la discussion cible"
|
||||
},
|
||||
"schedule": {
|
||||
"at": "À {{time}}",
|
||||
|
||||
@@ -493,7 +493,7 @@
|
||||
"schedule": "Jadwal",
|
||||
"next": "Berikutnya",
|
||||
"last": "Terakhir",
|
||||
"origin": "Asal"
|
||||
"origin": "Chat tertaut"
|
||||
},
|
||||
"runNow": "Jalankan sekarang",
|
||||
"pause": "Jeda",
|
||||
@@ -512,7 +512,8 @@
|
||||
},
|
||||
"origin": {
|
||||
"system": "Sistem",
|
||||
"unknown": "Sesi tidak dikenal"
|
||||
"unknown": "Tidak ada chat tertaut",
|
||||
"legacy": "Buat ulang di chat tujuan"
|
||||
},
|
||||
"schedule": {
|
||||
"at": "Pada {{time}}",
|
||||
|
||||
@@ -493,7 +493,7 @@
|
||||
"schedule": "スケジュール",
|
||||
"next": "次回",
|
||||
"last": "前回",
|
||||
"origin": "発生元"
|
||||
"origin": "関連チャット"
|
||||
},
|
||||
"runNow": "今すぐ実行",
|
||||
"pause": "一時停止",
|
||||
@@ -512,7 +512,8 @@
|
||||
},
|
||||
"origin": {
|
||||
"system": "システム",
|
||||
"unknown": "不明なセッション"
|
||||
"unknown": "関連チャットなし",
|
||||
"legacy": "対象チャットで作り直してください"
|
||||
},
|
||||
"schedule": {
|
||||
"at": "{{time}}",
|
||||
|
||||
@@ -493,7 +493,7 @@
|
||||
"schedule": "일정",
|
||||
"next": "다음",
|
||||
"last": "마지막",
|
||||
"origin": "출처"
|
||||
"origin": "연결된 채팅"
|
||||
},
|
||||
"runNow": "지금 실행",
|
||||
"pause": "일시 중지",
|
||||
@@ -512,7 +512,8 @@
|
||||
},
|
||||
"origin": {
|
||||
"system": "시스템",
|
||||
"unknown": "알 수 없는 세션"
|
||||
"unknown": "연결된 채팅 없음",
|
||||
"legacy": "대상 채팅에서 다시 만드세요"
|
||||
},
|
||||
"schedule": {
|
||||
"at": "{{time}}",
|
||||
|
||||
@@ -493,7 +493,7 @@
|
||||
"schedule": "Lịch",
|
||||
"next": "Tiếp theo",
|
||||
"last": "Lần trước",
|
||||
"origin": "Nguồn"
|
||||
"origin": "Cuộc trò chuyện liên kết"
|
||||
},
|
||||
"runNow": "Chạy ngay",
|
||||
"pause": "Tạm dừng",
|
||||
@@ -512,7 +512,8 @@
|
||||
},
|
||||
"origin": {
|
||||
"system": "Hệ thống",
|
||||
"unknown": "Phiên không xác định"
|
||||
"unknown": "Chưa liên kết cuộc trò chuyện",
|
||||
"legacy": "Tạo lại trong cuộc trò chuyện đích"
|
||||
},
|
||||
"schedule": {
|
||||
"at": "Vào {{time}}",
|
||||
|
||||
@@ -493,7 +493,7 @@
|
||||
"schedule": "计划",
|
||||
"next": "下次",
|
||||
"last": "上次",
|
||||
"origin": "来源"
|
||||
"origin": "关联会话"
|
||||
},
|
||||
"runNow": "立即运行",
|
||||
"pause": "暂停",
|
||||
@@ -512,7 +512,8 @@
|
||||
},
|
||||
"origin": {
|
||||
"system": "系统",
|
||||
"unknown": "未知会话"
|
||||
"unknown": "未关联会话",
|
||||
"legacy": "请在目标会话中重新创建"
|
||||
},
|
||||
"schedule": {
|
||||
"at": "在 {{time}}",
|
||||
|
||||
@@ -493,7 +493,7 @@
|
||||
"schedule": "排程",
|
||||
"next": "下次",
|
||||
"last": "上次",
|
||||
"origin": "來源"
|
||||
"origin": "關聯會話"
|
||||
},
|
||||
"runNow": "立即執行",
|
||||
"pause": "暫停",
|
||||
@@ -512,7 +512,8 @@
|
||||
},
|
||||
"origin": {
|
||||
"system": "系統",
|
||||
"unknown": "未知會話"
|
||||
"unknown": "未關聯會話",
|
||||
"legacy": "請在目標會話中重新建立"
|
||||
},
|
||||
"schedule": {
|
||||
"at": "於 {{time}}",
|
||||
|
||||
@@ -365,6 +365,26 @@ describe("App layout", () => {
|
||||
preview: "Check release blockers",
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "legacy-quiz",
|
||||
name: "english-quiz",
|
||||
enabled: true,
|
||||
protected: false,
|
||||
delete_after_run: false,
|
||||
schedule: { kind: "cron", expr: "30 9-23 * * *", tz: "Asia/Shanghai" },
|
||||
payload: {
|
||||
message: "Practice English",
|
||||
kind: "agent_turn",
|
||||
session_key: "unified:default",
|
||||
},
|
||||
state: {
|
||||
next_run_at_ms: Date.UTC(2026, 3, 17, 11, 0, 0),
|
||||
last_status: "ok",
|
||||
pending: false,
|
||||
run_history: [],
|
||||
},
|
||||
origin: null,
|
||||
},
|
||||
{
|
||||
id: "heartbeat",
|
||||
name: "heartbeat",
|
||||
@@ -393,6 +413,9 @@ describe("App layout", () => {
|
||||
expect(screen.getByText("Daily repo check")).toBeInTheDocument();
|
||||
expect(screen.getByText("Check the repo status")).toBeInTheDocument();
|
||||
expect(screen.getByText("Release prep")).toBeInTheDocument();
|
||||
expect(screen.getByText("english-quiz")).toBeInTheDocument();
|
||||
expect(screen.getByText("Recreate in target chat")).toBeInTheDocument();
|
||||
expect(screen.queryByText("unified:default")).not.toBeInTheDocument();
|
||||
expect(screen.getByText("heartbeat")).toBeInTheDocument();
|
||||
expect(within(sidebar).getByRole("button", { name: "Automations" })).toHaveAttribute(
|
||||
"aria-current",
|
||||
|
||||
Reference in New Issue
Block a user