agent-relay-server 0.4.30 → 0.4.32
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/public/dashboard.js +44 -13
- package/public/index.html +6 -6
- package/src/db.ts +1 -0
package/package.json
CHANGED
package/public/dashboard.js
CHANGED
|
@@ -123,8 +123,9 @@
|
|
|
123
123
|
vm.$watch("pairStatusFilter", (value) => vm.save("pairStatusFilter", value));
|
|
124
124
|
vm.$watch("inboxShowArchived", (value) => vm.save("inboxShowArchived", value));
|
|
125
125
|
vm.$watch("activityFilter", (value) => vm.save("activityFilter", value));
|
|
126
|
-
vm.$watch("view", (value) => {
|
|
126
|
+
vm.$watch("view", (value, oldValue) => {
|
|
127
127
|
vm.save("view", value);
|
|
128
|
+
if (oldValue === "analytics") vm.destroyAllCharts();
|
|
128
129
|
if (value === "analytics") vm.$nextTick(() => vm.renderCharts());
|
|
129
130
|
});
|
|
130
131
|
}
|
|
@@ -1095,6 +1096,7 @@
|
|
|
1095
1096
|
|
|
1096
1097
|
function isAgentStale(vm, agent) {
|
|
1097
1098
|
if (!agent?.lastSeen || agent.status === "offline") return false;
|
|
1099
|
+
if (agent.id === "user" || agent.id === "system") return false;
|
|
1098
1100
|
const lastSeenMs = new Date(agent.lastSeen).getTime();
|
|
1099
1101
|
if (!Number.isFinite(lastSeenMs)) return false;
|
|
1100
1102
|
return (vm.now || Date.now()) - lastSeenMs > 60_000;
|
|
@@ -2424,6 +2426,7 @@
|
|
|
2424
2426
|
renderVolumeChart,
|
|
2425
2427
|
renderStatusChart,
|
|
2426
2428
|
renderAgentChart,
|
|
2429
|
+
destroyAllCharts,
|
|
2427
2430
|
};
|
|
2428
2431
|
}
|
|
2429
2432
|
|
|
@@ -2434,15 +2437,20 @@
|
|
|
2434
2437
|
}
|
|
2435
2438
|
|
|
2436
2439
|
function renderVolumeChart() {
|
|
2437
|
-
|
|
2440
|
+
const data = buildVolumeSeries(this.messages);
|
|
2441
|
+
|
|
2442
|
+
if (this.chartInstances.volume) {
|
|
2443
|
+
this.chartInstances.volume.updateSeries([{ name: "Messages", data }]);
|
|
2444
|
+
return;
|
|
2445
|
+
}
|
|
2438
2446
|
|
|
2439
2447
|
const el = document.querySelector("#chart-volume");
|
|
2440
2448
|
if (!el) return;
|
|
2441
2449
|
|
|
2442
2450
|
this.chartInstances.volume = new ApexCharts(el, {
|
|
2443
|
-
chart: { type: "area", height: 280, background: "transparent", toolbar: { show: false } },
|
|
2451
|
+
chart: { type: "area", height: 280, background: "transparent", toolbar: { show: false }, animations: { dynamicAnimation: { speed: 350 } } },
|
|
2444
2452
|
theme: { mode: "dark" },
|
|
2445
|
-
series: [{ name: "Messages", data
|
|
2453
|
+
series: [{ name: "Messages", data }],
|
|
2446
2454
|
xaxis: { type: "datetime" },
|
|
2447
2455
|
stroke: { curve: "smooth", width: 2 },
|
|
2448
2456
|
fill: { type: "gradient", gradient: { opacityFrom: 0.4, opacityTo: 0 } },
|
|
@@ -2465,16 +2473,23 @@
|
|
|
2465
2473
|
}
|
|
2466
2474
|
|
|
2467
2475
|
function renderStatusChart() {
|
|
2468
|
-
|
|
2476
|
+
const { labels, series } = countAgentStatuses(this.agents);
|
|
2477
|
+
const colorMap = { online: "#48bb78", idle: "#48bb78", busy: "#ecc94b", offline: "#718096" };
|
|
2478
|
+
|
|
2479
|
+
if (this.chartInstances.status) {
|
|
2480
|
+
this.chartInstances.status.updateOptions({
|
|
2481
|
+
series,
|
|
2482
|
+
labels,
|
|
2483
|
+
colors: labels.map((label) => colorMap[label] || "#718096"),
|
|
2484
|
+
});
|
|
2485
|
+
return;
|
|
2486
|
+
}
|
|
2469
2487
|
|
|
2470
2488
|
const el = document.querySelector("#chart-status");
|
|
2471
2489
|
if (!el) return;
|
|
2472
2490
|
|
|
2473
|
-
const { labels, series } = countAgentStatuses(this.agents);
|
|
2474
|
-
const colorMap = { online: "#48bb78", idle: "#48bb78", busy: "#ecc94b", offline: "#718096" };
|
|
2475
|
-
|
|
2476
2491
|
this.chartInstances.status = new ApexCharts(el, {
|
|
2477
|
-
chart: { type: "donut", height: 280, background: "transparent" },
|
|
2492
|
+
chart: { type: "donut", height: 280, background: "transparent", animations: { dynamicAnimation: { speed: 350 } } },
|
|
2478
2493
|
theme: { mode: "dark" },
|
|
2479
2494
|
series,
|
|
2480
2495
|
labels,
|
|
@@ -2494,14 +2509,21 @@
|
|
|
2494
2509
|
}
|
|
2495
2510
|
|
|
2496
2511
|
function renderAgentChart() {
|
|
2497
|
-
|
|
2512
|
+
const sorted = countMessagesByAgent(this);
|
|
2513
|
+
|
|
2514
|
+
if (this.chartInstances.agents) {
|
|
2515
|
+
this.chartInstances.agents.updateOptions({
|
|
2516
|
+
series: [{ name: "Messages", data: sorted.map(([, count]) => count) }],
|
|
2517
|
+
xaxis: { categories: sorted.map(([name]) => name) },
|
|
2518
|
+
});
|
|
2519
|
+
return;
|
|
2520
|
+
}
|
|
2498
2521
|
|
|
2499
2522
|
const el = document.querySelector("#chart-agents");
|
|
2500
2523
|
if (!el) return;
|
|
2501
2524
|
|
|
2502
|
-
const sorted = countMessagesByAgent(this);
|
|
2503
2525
|
this.chartInstances.agents = new ApexCharts(el, {
|
|
2504
|
-
chart: { type: "bar", height: 280, background: "transparent", toolbar: { show: false } },
|
|
2526
|
+
chart: { type: "bar", height: 280, background: "transparent", toolbar: { show: false }, animations: { dynamicAnimation: { speed: 350 } } },
|
|
2505
2527
|
theme: { mode: "dark" },
|
|
2506
2528
|
series: [{ name: "Messages", data: sorted.map(([, count]) => count) }],
|
|
2507
2529
|
xaxis: { categories: sorted.map(([name]) => name) },
|
|
@@ -2523,7 +2545,16 @@
|
|
|
2523
2545
|
}
|
|
2524
2546
|
|
|
2525
2547
|
function destroyChart(vm, name) {
|
|
2526
|
-
if (vm.chartInstances[name])
|
|
2548
|
+
if (vm.chartInstances[name]) {
|
|
2549
|
+
vm.chartInstances[name].destroy();
|
|
2550
|
+
vm.chartInstances[name] = null;
|
|
2551
|
+
}
|
|
2552
|
+
}
|
|
2553
|
+
|
|
2554
|
+
function destroyAllCharts() {
|
|
2555
|
+
destroyChart(this, "volume");
|
|
2556
|
+
destroyChart(this, "status");
|
|
2557
|
+
destroyChart(this, "agents");
|
|
2527
2558
|
}
|
|
2528
2559
|
|
|
2529
2560
|
function createRelayDashboard() {
|
package/public/index.html
CHANGED
|
@@ -433,7 +433,7 @@
|
|
|
433
433
|
</div>
|
|
434
434
|
<div class="list-group list-group-flush" style="max-height: 60vh; overflow-y: auto">
|
|
435
435
|
<template x-for="a in sortedAgents.slice(0, 20)" :key="a.id">
|
|
436
|
-
<div class="list-group-item d-flex align-items-center gap-2" style="cursor:pointer" @click="openAgentDetail(a)">
|
|
436
|
+
<div class="list-group-item d-flex align-items-center gap-2" style="cursor:pointer" @click="if (!window.getSelection().toString()) openAgentDetail(a)">
|
|
437
437
|
<span class="status-dot" :class="agentStatusClass(a)"></span>
|
|
438
438
|
<span class="agent-type-icon" :class="agentType(a)" :title="agentTypeTitle(a)" :aria-label="agentTypeTitle(a)">
|
|
439
439
|
<i class="ti" :class="agentTypeIcon(a)"></i>
|
|
@@ -483,7 +483,7 @@
|
|
|
483
483
|
</div>
|
|
484
484
|
<div class="card-body p-0" style="max-height: 60vh; overflow-y: auto">
|
|
485
485
|
<template x-for="item in activityItems.slice(0, 15)" :key="item.id">
|
|
486
|
-
<
|
|
486
|
+
<div role="button" class="list-group-item list-group-item-action activity-item text-start w-100 border-0 border-bottom rounded-0" style="cursor:pointer" @click="if (!window.getSelection().toString()) openActivityItem(item)">
|
|
487
487
|
<div class="d-flex align-items-start gap-3">
|
|
488
488
|
<span class="activity-icon" :class="activityKindClass(item.kind)">
|
|
489
489
|
<i class="ti" :class="item.icon"></i>
|
|
@@ -498,7 +498,7 @@
|
|
|
498
498
|
<div class="text-secondary small text-truncate" x-show="item.meta" x-text="item.meta"></div>
|
|
499
499
|
</div>
|
|
500
500
|
</div>
|
|
501
|
-
</
|
|
501
|
+
</div>
|
|
502
502
|
</template>
|
|
503
503
|
<template x-if="activityItems.length === 0">
|
|
504
504
|
<div class="p-3 text-secondary text-center">No activity</div>
|
|
@@ -568,7 +568,7 @@
|
|
|
568
568
|
<div class="row g-3">
|
|
569
569
|
<template x-for="a in sortedAgents" :key="a.id">
|
|
570
570
|
<div class="col-md-6 col-xl-4">
|
|
571
|
-
<div class="card agent-card" :class="{ selected: selectedAgent === a.id }" @click="openAgentDetail(a)">
|
|
571
|
+
<div class="card agent-card" :class="{ selected: selectedAgent === a.id }" @click="if (!window.getSelection().toString()) openAgentDetail(a)">
|
|
572
572
|
<div class="card-body">
|
|
573
573
|
<div class="d-flex align-items-start gap-2">
|
|
574
574
|
<span class="status-dot mt-1" :class="agentStatusClass(a)" :title="agentStatusTitle(a)"></span>
|
|
@@ -1028,7 +1028,7 @@
|
|
|
1028
1028
|
<div class="card">
|
|
1029
1029
|
<div class="list-group list-group-flush">
|
|
1030
1030
|
<template x-for="item in activityItems" :key="item.id">
|
|
1031
|
-
<
|
|
1031
|
+
<div role="button" class="list-group-item list-group-item-action activity-item text-start" style="cursor:pointer" @click="if (!window.getSelection().toString()) openActivityItem(item)">
|
|
1032
1032
|
<div class="d-flex align-items-start gap-3">
|
|
1033
1033
|
<span class="activity-icon" :class="activityKindClass(item.kind)">
|
|
1034
1034
|
<i class="ti" :class="item.icon"></i>
|
|
@@ -1043,7 +1043,7 @@
|
|
|
1043
1043
|
<div class="text-secondary small mt-1 text-truncate" x-show="item.meta" x-text="item.meta"></div>
|
|
1044
1044
|
</div>
|
|
1045
1045
|
</div>
|
|
1046
|
-
</
|
|
1046
|
+
</div>
|
|
1047
1047
|
</template>
|
|
1048
1048
|
<template x-if="activityItems.length === 0">
|
|
1049
1049
|
<div class="list-group-item text-secondary text-center py-5">
|
package/src/db.ts
CHANGED
|
@@ -629,6 +629,7 @@ export function heartbeat(id: string, guard?: AgentSessionGuard): boolean {
|
|
|
629
629
|
export function reapStaleAgents(ttlMs: number = STALE_TTL_MS): string[] {
|
|
630
630
|
const now = Date.now();
|
|
631
631
|
const cutoff = now - ttlMs;
|
|
632
|
+
db.prepare("UPDATE agents SET last_seen = ? WHERE id IN ('user', 'system')").run(now);
|
|
632
633
|
const rows = db
|
|
633
634
|
.prepare(
|
|
634
635
|
"UPDATE agents SET status = 'offline', ready = 0 WHERE status != 'offline' AND last_seen < ? AND id NOT IN ('user', 'system') RETURNING id"
|