From 3321d36bd78a7d2864ce710d1f8e34a7de37a85a Mon Sep 17 00:00:00 2001 From: konard Date: Tue, 14 Jul 2026 07:41:32 +0000 Subject: [PATCH 1/3] Initial commit with task details Adding .gitkeep for PR creation (default mode). This file will be removed when the task is complete. Issue: https://github.com/xlabtg/teleton-agent/issues/709 --- .gitkeep | 1 + 1 file changed, 1 insertion(+) create mode 100644 .gitkeep diff --git a/.gitkeep b/.gitkeep new file mode 100644 index 00000000..7b1acc65 --- /dev/null +++ b/.gitkeep @@ -0,0 +1 @@ +# .gitkeep file auto-generated at 2026-07-14T07:41:32.473Z for PR creation at branch issue-709-a86119ebe7ec for issue https://github.com/xlabtg/teleton-agent/issues/709 \ No newline at end of file From ea318062d78a4c4ea15500078fcf06b1e6fb8783 Mon Sep 17 00:00:00 2001 From: konard Date: Tue, 14 Jul 2026 07:57:46 +0000 Subject: [PATCH 2/3] =?UTF-8?q?test(web):=20=D0=BF=D1=80=D0=BE=D0=B2=D0=B5?= =?UTF-8?q?=D1=80=D0=B8=D1=82=D1=8C=20=D0=BE=D0=B1=D1=80=D0=B0=D0=B1=D0=BE?= =?UTF-8?q?=D1=82=D0=BA=D1=83=20=D0=BE=D1=88=D0=B8=D0=B1=D0=BE=D0=BA=20UI-?= =?UTF-8?q?=D0=B4=D0=B5=D0=B9=D1=81=D1=82=D0=B2=D0=B8=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- web/src/lib/__tests__/handleUiAction.test.ts | 23 ++++++++++++++++++++ web/src/lib/handleUiAction.ts | 10 +++++++++ 2 files changed, 33 insertions(+) create mode 100644 web/src/lib/__tests__/handleUiAction.test.ts create mode 100644 web/src/lib/handleUiAction.ts diff --git a/web/src/lib/__tests__/handleUiAction.test.ts b/web/src/lib/__tests__/handleUiAction.test.ts new file mode 100644 index 00000000..fafd83b6 --- /dev/null +++ b/web/src/lib/__tests__/handleUiAction.test.ts @@ -0,0 +1,23 @@ +import { describe, expect, it, vi } from "vitest"; +import { handleUiAction } from "../handleUiAction"; + +describe("handleUiAction", () => { + it("surfaces a rejected action without rethrowing it", async () => { + const setError = vi.fn(); + + await expect( + handleUiAction(() => Promise.reject(new Error("boom")), setError) + ).resolves.toBeUndefined(); + + expect(setError).toHaveBeenCalledOnce(); + expect(setError).toHaveBeenCalledWith("boom"); + }); + + it("converts non-Error rejections to a readable message", async () => { + const setError = vi.fn(); + + await handleUiAction(() => Promise.reject("offline"), setError); + + expect(setError).toHaveBeenCalledWith("offline"); + }); +}); diff --git a/web/src/lib/handleUiAction.ts b/web/src/lib/handleUiAction.ts new file mode 100644 index 00000000..95086650 --- /dev/null +++ b/web/src/lib/handleUiAction.ts @@ -0,0 +1,10 @@ +export async function handleUiAction( + action: () => Promise, + setError: (message: string) => void +): Promise { + try { + await action(); + } catch (error) { + setError(error instanceof Error ? error.message : String(error)); + } +} From c14e26ff61dbe4eec6a2279c93db698f639a1824 Mon Sep 17 00:00:00 2001 From: konard Date: Tue, 14 Jul 2026 07:58:28 +0000 Subject: [PATCH 3/3] =?UTF-8?q?fix(web):=20=D0=BF=D0=BE=D0=BA=D0=B0=D0=B7?= =?UTF-8?q?=D1=8B=D0=B2=D0=B0=D1=82=D1=8C=20=D0=BE=D1=88=D0=B8=D0=B1=D0=BA?= =?UTF-8?q?=D0=B8=20=D1=81=D0=B5=D1=82=D0=B5=D0=B2=D1=8B=D1=85=20UI-=D0=B4?= =?UTF-8?q?=D0=B5=D0=B9=D1=81=D1=82=D0=B2=D0=B8=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitkeep | 1 - web/src/pages/Events.tsx | 6 +++++- web/src/pages/Network.tsx | 19 +++++++++++++------ 3 files changed, 18 insertions(+), 8 deletions(-) delete mode 100644 .gitkeep diff --git a/.gitkeep b/.gitkeep deleted file mode 100644 index 7b1acc65..00000000 --- a/.gitkeep +++ /dev/null @@ -1 +0,0 @@ -# .gitkeep file auto-generated at 2026-07-14T07:41:32.473Z for PR creation at branch issue-709-a86119ebe7ec for issue https://github.com/xlabtg/teleton-agent/issues/709 \ No newline at end of file diff --git a/web/src/pages/Events.tsx b/web/src/pages/Events.tsx index 762becc2..2a490b00 100644 --- a/web/src/pages/Events.tsx +++ b/web/src/pages/Events.tsx @@ -6,6 +6,7 @@ import { WebhookRegistrationData, } from "../lib/api"; import { useTranslation } from "react-i18next"; +import { handleUiAction } from "../lib/handleUiAction"; function fmtTime(value: string | number | null): string { if (value === null) return "-"; @@ -419,7 +420,10 @@ export function Events() { className="btn-ghost btn-sm" onClick={() => { setFilterType(type); - api.eventsList({ type, limit: 100 }).then((result) => setEvents(result.data.events)); + void handleUiAction(async () => { + const result = await api.eventsList({ type, limit: 100 }); + setEvents(result.data.events); + }, setError); }} > {type} diff --git a/web/src/pages/Network.tsx b/web/src/pages/Network.tsx index 5ccbb02e..ef167ceb 100644 --- a/web/src/pages/Network.tsx +++ b/web/src/pages/Network.tsx @@ -10,6 +10,7 @@ import { } from "../lib/api"; import { toast } from "../lib/toast-store"; import { useTranslation } from "react-i18next"; +import { handleUiAction } from "../lib/handleUiAction"; const TRUST_LEVELS: NetworkTrustLevel[] = ["trusted", "verified", "untrusted"]; const AGENT_STATUSES: NetworkAgentStatus[] = ["available", "busy", "offline", "degraded"]; @@ -327,18 +328,24 @@ export function Network() { }; const updateTrust = async (agent: NetworkAgentData, trustLevel: NetworkTrustLevel) => { - await api.updateNetworkAgentTrust(agent.id, { trustLevel }); - await load(); + await handleUiAction(async () => { + await api.updateNetworkAgentTrust(agent.id, { trustLevel }); + await load(); + }, setLastError); }; const toggleBlocked = async (agent: NetworkAgentData) => { - await api.updateNetworkAgentTrust(agent.id, { blocked: !agent.blocked }); - await load(); + await handleUiAction(async () => { + await api.updateNetworkAgentTrust(agent.id, { blocked: !agent.blocked }); + await load(); + }, setLastError); }; const removeAgent = async (agent: NetworkAgentData) => { - await api.removeNetworkAgent(agent.id); - await load(); + await handleUiAction(async () => { + await api.removeNetworkAgent(agent.id); + await load(); + }, setLastError); }; const delegateTask = async () => {