agent-relay-server 0.4.29 → 0.4.31
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 +49 -13
- package/public/index.html +57 -66
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
|
}
|
|
@@ -1217,6 +1218,7 @@
|
|
|
1217
1218
|
agentStatusClass,
|
|
1218
1219
|
severityClass,
|
|
1219
1220
|
agentStatusTitle,
|
|
1221
|
+
agentChannels,
|
|
1220
1222
|
channelPresence,
|
|
1221
1223
|
integrationPresence,
|
|
1222
1224
|
timeAgo,
|
|
@@ -1440,6 +1442,11 @@
|
|
|
1440
1442
|
return { label: "configured", tone: "primary", icon: "ti-plug-connected" };
|
|
1441
1443
|
}
|
|
1442
1444
|
|
|
1445
|
+
function agentChannels(agent) {
|
|
1446
|
+
if (!agent) return [];
|
|
1447
|
+
return (this.channels || []).filter((ch) => ch.agentId === agent.id);
|
|
1448
|
+
}
|
|
1449
|
+
|
|
1443
1450
|
function channelPresence(channel) {
|
|
1444
1451
|
if (!channel) return { label: "unknown", tone: "secondary", icon: "ti-plug-off" };
|
|
1445
1452
|
if (channel.status === "offline") return { label: "offline", tone: "secondary", icon: "ti-plug-off" };
|
|
@@ -2418,6 +2425,7 @@
|
|
|
2418
2425
|
renderVolumeChart,
|
|
2419
2426
|
renderStatusChart,
|
|
2420
2427
|
renderAgentChart,
|
|
2428
|
+
destroyAllCharts,
|
|
2421
2429
|
};
|
|
2422
2430
|
}
|
|
2423
2431
|
|
|
@@ -2428,15 +2436,20 @@
|
|
|
2428
2436
|
}
|
|
2429
2437
|
|
|
2430
2438
|
function renderVolumeChart() {
|
|
2431
|
-
|
|
2439
|
+
const data = buildVolumeSeries(this.messages);
|
|
2440
|
+
|
|
2441
|
+
if (this.chartInstances.volume) {
|
|
2442
|
+
this.chartInstances.volume.updateSeries([{ name: "Messages", data }]);
|
|
2443
|
+
return;
|
|
2444
|
+
}
|
|
2432
2445
|
|
|
2433
2446
|
const el = document.querySelector("#chart-volume");
|
|
2434
2447
|
if (!el) return;
|
|
2435
2448
|
|
|
2436
2449
|
this.chartInstances.volume = new ApexCharts(el, {
|
|
2437
|
-
chart: { type: "area", height: 280, background: "transparent", toolbar: { show: false } },
|
|
2450
|
+
chart: { type: "area", height: 280, background: "transparent", toolbar: { show: false }, animations: { dynamicAnimation: { speed: 350 } } },
|
|
2438
2451
|
theme: { mode: "dark" },
|
|
2439
|
-
series: [{ name: "Messages", data
|
|
2452
|
+
series: [{ name: "Messages", data }],
|
|
2440
2453
|
xaxis: { type: "datetime" },
|
|
2441
2454
|
stroke: { curve: "smooth", width: 2 },
|
|
2442
2455
|
fill: { type: "gradient", gradient: { opacityFrom: 0.4, opacityTo: 0 } },
|
|
@@ -2459,16 +2472,23 @@
|
|
|
2459
2472
|
}
|
|
2460
2473
|
|
|
2461
2474
|
function renderStatusChart() {
|
|
2462
|
-
|
|
2475
|
+
const { labels, series } = countAgentStatuses(this.agents);
|
|
2476
|
+
const colorMap = { online: "#48bb78", idle: "#48bb78", busy: "#ecc94b", offline: "#718096" };
|
|
2477
|
+
|
|
2478
|
+
if (this.chartInstances.status) {
|
|
2479
|
+
this.chartInstances.status.updateOptions({
|
|
2480
|
+
series,
|
|
2481
|
+
labels,
|
|
2482
|
+
colors: labels.map((label) => colorMap[label] || "#718096"),
|
|
2483
|
+
});
|
|
2484
|
+
return;
|
|
2485
|
+
}
|
|
2463
2486
|
|
|
2464
2487
|
const el = document.querySelector("#chart-status");
|
|
2465
2488
|
if (!el) return;
|
|
2466
2489
|
|
|
2467
|
-
const { labels, series } = countAgentStatuses(this.agents);
|
|
2468
|
-
const colorMap = { online: "#48bb78", idle: "#48bb78", busy: "#ecc94b", offline: "#718096" };
|
|
2469
|
-
|
|
2470
2490
|
this.chartInstances.status = new ApexCharts(el, {
|
|
2471
|
-
chart: { type: "donut", height: 280, background: "transparent" },
|
|
2491
|
+
chart: { type: "donut", height: 280, background: "transparent", animations: { dynamicAnimation: { speed: 350 } } },
|
|
2472
2492
|
theme: { mode: "dark" },
|
|
2473
2493
|
series,
|
|
2474
2494
|
labels,
|
|
@@ -2488,14 +2508,21 @@
|
|
|
2488
2508
|
}
|
|
2489
2509
|
|
|
2490
2510
|
function renderAgentChart() {
|
|
2491
|
-
|
|
2511
|
+
const sorted = countMessagesByAgent(this);
|
|
2512
|
+
|
|
2513
|
+
if (this.chartInstances.agents) {
|
|
2514
|
+
this.chartInstances.agents.updateOptions({
|
|
2515
|
+
series: [{ name: "Messages", data: sorted.map(([, count]) => count) }],
|
|
2516
|
+
xaxis: { categories: sorted.map(([name]) => name) },
|
|
2517
|
+
});
|
|
2518
|
+
return;
|
|
2519
|
+
}
|
|
2492
2520
|
|
|
2493
2521
|
const el = document.querySelector("#chart-agents");
|
|
2494
2522
|
if (!el) return;
|
|
2495
2523
|
|
|
2496
|
-
const sorted = countMessagesByAgent(this);
|
|
2497
2524
|
this.chartInstances.agents = new ApexCharts(el, {
|
|
2498
|
-
chart: { type: "bar", height: 280, background: "transparent", toolbar: { show: false } },
|
|
2525
|
+
chart: { type: "bar", height: 280, background: "transparent", toolbar: { show: false }, animations: { dynamicAnimation: { speed: 350 } } },
|
|
2499
2526
|
theme: { mode: "dark" },
|
|
2500
2527
|
series: [{ name: "Messages", data: sorted.map(([, count]) => count) }],
|
|
2501
2528
|
xaxis: { categories: sorted.map(([name]) => name) },
|
|
@@ -2517,7 +2544,16 @@
|
|
|
2517
2544
|
}
|
|
2518
2545
|
|
|
2519
2546
|
function destroyChart(vm, name) {
|
|
2520
|
-
if (vm.chartInstances[name])
|
|
2547
|
+
if (vm.chartInstances[name]) {
|
|
2548
|
+
vm.chartInstances[name].destroy();
|
|
2549
|
+
vm.chartInstances[name] = null;
|
|
2550
|
+
}
|
|
2551
|
+
}
|
|
2552
|
+
|
|
2553
|
+
function destroyAllCharts() {
|
|
2554
|
+
destroyChart(this, "volume");
|
|
2555
|
+
destroyChart(this, "status");
|
|
2556
|
+
destroyChart(this, "agents");
|
|
2521
2557
|
}
|
|
2522
2558
|
|
|
2523
2559
|
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>
|
|
@@ -447,23 +447,20 @@
|
|
|
447
447
|
<span x-text="a.name || a.id.slice(-12)"></span>
|
|
448
448
|
</template>
|
|
449
449
|
</div>
|
|
450
|
-
<div class="
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
<span class="badge" :class="badge.className" x-text="badge.label"></span>
|
|
454
|
-
</template>
|
|
455
|
-
</div>
|
|
456
|
-
<template x-if="agentPair(a)">
|
|
457
|
-
<span class="badge pair-badge mt-1" :class="pairBadgeClass(agentPair(a))" :title="pairTitle(agentPair(a), a.id)">
|
|
458
|
-
<i class="ti ti-link me-1"></i><span x-text="pairBadgeLabel(agentPair(a), a.id)"></span>
|
|
450
|
+
<div class="d-flex gap-1 mt-1 flex-wrap align-items-center">
|
|
451
|
+
<span class="badge" :class="'bg-' + agentPresence(a).tone + '-lt'" style="font-size: 0.7rem">
|
|
452
|
+
<i class="ti me-1" :class="agentPresence(a).icon"></i><span x-text="agentPresence(a).label"></span>
|
|
459
453
|
</span>
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
<
|
|
466
|
-
|
|
454
|
+
<template x-if="agentAttention(a).total > 0">
|
|
455
|
+
<span class="badge bg-warning text-white" style="font-size: 0.7rem" :title="agentAttentionTitle(a)">
|
|
456
|
+
<i class="ti ti-bell me-1"></i><span x-text="agentAttention(a).total"></span>
|
|
457
|
+
</span>
|
|
458
|
+
</template>
|
|
459
|
+
<template x-if="agentPair(a)">
|
|
460
|
+
<span class="badge pair-badge" :class="pairBadgeClass(agentPair(a))" style="font-size: 0.7rem" :title="pairTitle(agentPair(a), a.id)">
|
|
461
|
+
<i class="ti ti-link me-1"></i><span x-text="pairBadgeLabel(agentPair(a), a.id)"></span>
|
|
462
|
+
</span>
|
|
463
|
+
</template>
|
|
467
464
|
</div>
|
|
468
465
|
</div>
|
|
469
466
|
<span class="text-secondary small" x-text="timeAgo(a.lastSeen)"></span>
|
|
@@ -486,7 +483,7 @@
|
|
|
486
483
|
</div>
|
|
487
484
|
<div class="card-body p-0" style="max-height: 60vh; overflow-y: auto">
|
|
488
485
|
<template x-for="item in activityItems.slice(0, 15)" :key="item.id">
|
|
489
|
-
<
|
|
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)">
|
|
490
487
|
<div class="d-flex align-items-start gap-3">
|
|
491
488
|
<span class="activity-icon" :class="activityKindClass(item.kind)">
|
|
492
489
|
<i class="ti" :class="item.icon"></i>
|
|
@@ -501,7 +498,7 @@
|
|
|
501
498
|
<div class="text-secondary small text-truncate" x-show="item.meta" x-text="item.meta"></div>
|
|
502
499
|
</div>
|
|
503
500
|
</div>
|
|
504
|
-
</
|
|
501
|
+
</div>
|
|
505
502
|
</template>
|
|
506
503
|
<template x-if="activityItems.length === 0">
|
|
507
504
|
<div class="p-3 text-secondary text-center">No activity</div>
|
|
@@ -571,7 +568,7 @@
|
|
|
571
568
|
<div class="row g-3">
|
|
572
569
|
<template x-for="a in sortedAgents" :key="a.id">
|
|
573
570
|
<div class="col-md-6 col-xl-4">
|
|
574
|
-
<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)">
|
|
575
572
|
<div class="card-body">
|
|
576
573
|
<div class="d-flex align-items-start gap-2">
|
|
577
574
|
<span class="status-dot mt-1" :class="agentStatusClass(a)" :title="agentStatusTitle(a)"></span>
|
|
@@ -585,16 +582,10 @@
|
|
|
585
582
|
</template>
|
|
586
583
|
<span class="text-truncate" :class="a.label ? 'text-secondary small' : 'fw-bold'" x-text="a.name || a.id.slice(-12)"></span>
|
|
587
584
|
</div>
|
|
588
|
-
<div class="
|
|
589
|
-
<div class="presence-badges d-flex gap-1 mt-1 flex-wrap">
|
|
585
|
+
<div class="d-flex gap-1 mt-1 flex-wrap align-items-center">
|
|
590
586
|
<span class="badge" :class="'bg-' + agentPresence(a).tone + '-lt'">
|
|
591
587
|
<i class="ti me-1" :class="agentPresence(a).icon"></i><span x-text="agentPresence(a).label"></span>
|
|
592
588
|
</span>
|
|
593
|
-
<template x-for="badge in agentPresenceBadges(a)" :key="badge.label">
|
|
594
|
-
<span class="badge" :class="badge.className" x-text="badge.label"></span>
|
|
595
|
-
</template>
|
|
596
|
-
</div>
|
|
597
|
-
<div class="d-flex gap-1 mt-1 flex-wrap">
|
|
598
589
|
<template x-if="agentAttention(a).total > 0">
|
|
599
590
|
<span class="badge bg-warning text-white" :title="agentAttentionTitle(a)">
|
|
600
591
|
<i class="ti ti-bell me-1"></i><span x-text="agentAttention(a).total"></span>
|
|
@@ -605,31 +596,8 @@
|
|
|
605
596
|
<i class="ti ti-link me-1"></i><span x-text="pairBadgeLabel(agentPair(a), a.id)"></span>
|
|
606
597
|
</span>
|
|
607
598
|
</template>
|
|
608
|
-
<span class="badge bg-danger-lt" x-show="agentAttention(a).unread" x-text="agentAttention(a).unread + ' unread'"></span>
|
|
609
|
-
<span class="badge bg-warning-lt" x-show="agentAttention(a).needsHumanResponse">needs response</span>
|
|
610
|
-
<span class="badge bg-info-lt" x-show="agentAttention(a).agentQuestion">question</span>
|
|
611
|
-
<span class="badge bg-orange-lt" x-show="agentAttention(a).claimableTasks" x-text="agentAttention(a).claimableTasks + ' claimable'"></span>
|
|
612
|
-
<template x-if="a.machine">
|
|
613
|
-
<span class="badge bg-secondary-lt" x-text="a.machine"></span>
|
|
614
|
-
</template>
|
|
615
|
-
<template x-if="a.rig">
|
|
616
|
-
<span class="badge bg-primary-lt" x-text="a.rig"></span>
|
|
617
|
-
</template>
|
|
618
|
-
<template x-for="tag in (a.tags || [])" :key="tag">
|
|
619
|
-
<span class="badge bg-cyan-lt" x-text="tag"></span>
|
|
620
|
-
</template>
|
|
621
|
-
</div>
|
|
622
|
-
<template x-if="a.capabilities && a.capabilities.length">
|
|
623
|
-
<div class="d-flex gap-1 mt-1 flex-wrap">
|
|
624
|
-
<template x-for="cap in a.capabilities" :key="cap">
|
|
625
|
-
<span class="badge bg-purple-lt" x-text="'⚡' + cap"></span>
|
|
626
|
-
</template>
|
|
627
|
-
</div>
|
|
628
|
-
</template>
|
|
629
|
-
<div class="text-secondary small mt-2">
|
|
630
|
-
<span x-text="'Last seen: ' + timeAgo(a.lastSeen)"></span>
|
|
631
|
-
<span class="ms-2" x-text="'Created: ' + fmtTime(a.createdAt)"></span>
|
|
632
599
|
</div>
|
|
600
|
+
<div class="text-secondary small mt-1" x-text="'Last seen: ' + timeAgo(a.lastSeen)"></div>
|
|
633
601
|
</div>
|
|
634
602
|
<div class="agent-actions d-flex gap-1">
|
|
635
603
|
<button class="btn btn-sm btn-ghost-secondary p-1" title="Send message" @click.stop="openComposeToAgent(a)">
|
|
@@ -1060,7 +1028,7 @@
|
|
|
1060
1028
|
<div class="card">
|
|
1061
1029
|
<div class="list-group list-group-flush">
|
|
1062
1030
|
<template x-for="item in activityItems" :key="item.id">
|
|
1063
|
-
<
|
|
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)">
|
|
1064
1032
|
<div class="d-flex align-items-start gap-3">
|
|
1065
1033
|
<span class="activity-icon" :class="activityKindClass(item.kind)">
|
|
1066
1034
|
<i class="ti" :class="item.icon"></i>
|
|
@@ -1075,7 +1043,7 @@
|
|
|
1075
1043
|
<div class="text-secondary small mt-1 text-truncate" x-show="item.meta" x-text="item.meta"></div>
|
|
1076
1044
|
</div>
|
|
1077
1045
|
</div>
|
|
1078
|
-
</
|
|
1046
|
+
</div>
|
|
1079
1047
|
</template>
|
|
1080
1048
|
<template x-if="activityItems.length === 0">
|
|
1081
1049
|
<div class="list-group-item text-secondary text-center py-5">
|
|
@@ -1604,7 +1572,6 @@
|
|
|
1604
1572
|
</template>
|
|
1605
1573
|
<span class="fw-bold text-truncate" x-text="selectedAgentDetail.name || selectedAgentDetail.id.slice(-12)"></span>
|
|
1606
1574
|
</div>
|
|
1607
|
-
<div class="text-secondary small text-truncate" x-text="selectedAgentDetail.id"></div>
|
|
1608
1575
|
</div>
|
|
1609
1576
|
<button class="btn btn-sm btn-ghost-secondary p-1" @click="closeAgentDetail()" title="Close">
|
|
1610
1577
|
<i class="ti ti-x"></i>
|
|
@@ -1718,21 +1685,45 @@
|
|
|
1718
1685
|
</template>
|
|
1719
1686
|
|
|
1720
1687
|
<div class="p-3 border-bottom">
|
|
1721
|
-
<
|
|
1722
|
-
|
|
1723
|
-
<
|
|
1724
|
-
<span class="badge bg-cyan-lt" x-text="tag"></span>
|
|
1725
|
-
</template>
|
|
1726
|
-
<template x-if="!(selectedAgentDetail.tags || []).length">
|
|
1727
|
-
<span class="text-secondary small">No tags</span>
|
|
1728
|
-
</template>
|
|
1688
|
+
<div class="detail-row mb-2">
|
|
1689
|
+
<div class="text-secondary small">ID</div>
|
|
1690
|
+
<div class="small text-break user-select-all" style="font-family: var(--tblr-font-monospace); font-size: 0.75rem; opacity: 0.7" x-text="selectedAgentDetail.id"></div>
|
|
1729
1691
|
</div>
|
|
1730
|
-
<
|
|
1731
|
-
<div class="
|
|
1732
|
-
|
|
1733
|
-
|
|
1692
|
+
<div class="detail-row mb-2">
|
|
1693
|
+
<div class="text-secondary small">Tags</div>
|
|
1694
|
+
<div class="d-flex gap-1 flex-wrap">
|
|
1695
|
+
<template x-for="tag in (selectedAgentDetail.tags || [])" :key="tag">
|
|
1696
|
+
<span class="badge bg-cyan-lt" x-text="tag"></span>
|
|
1697
|
+
</template>
|
|
1698
|
+
<template x-if="!(selectedAgentDetail.tags || []).length">
|
|
1699
|
+
<span class="text-secondary small">—</span>
|
|
1734
1700
|
</template>
|
|
1735
1701
|
</div>
|
|
1702
|
+
</div>
|
|
1703
|
+
<div class="detail-row mb-2">
|
|
1704
|
+
<div class="text-secondary small">Capabilities</div>
|
|
1705
|
+
<div class="d-flex gap-1 flex-wrap">
|
|
1706
|
+
<template x-if="selectedAgentDetail.capabilities && selectedAgentDetail.capabilities.length">
|
|
1707
|
+
<template x-for="cap in selectedAgentDetail.capabilities" :key="cap">
|
|
1708
|
+
<span class="badge bg-purple-lt" x-text="cap"></span>
|
|
1709
|
+
</template>
|
|
1710
|
+
</template>
|
|
1711
|
+
<template x-if="!(selectedAgentDetail.capabilities || []).length">
|
|
1712
|
+
<span class="text-secondary small">—</span>
|
|
1713
|
+
</template>
|
|
1714
|
+
</div>
|
|
1715
|
+
</div>
|
|
1716
|
+
<template x-if="agentChannels(selectedAgentDetail).length">
|
|
1717
|
+
<div class="detail-row mb-2">
|
|
1718
|
+
<div class="text-secondary small">Channels</div>
|
|
1719
|
+
<div class="d-flex gap-1 flex-wrap">
|
|
1720
|
+
<template x-for="ch in agentChannels(selectedAgentDetail)" :key="ch.id">
|
|
1721
|
+
<span class="badge" :class="'bg-' + channelPresence(ch).tone + '-lt'" :title="ch.type + ' · ' + ch.direction">
|
|
1722
|
+
<i class="ti me-1" :class="channelPresence(ch).icon"></i><span x-text="ch.name"></span>
|
|
1723
|
+
</span>
|
|
1724
|
+
</template>
|
|
1725
|
+
</div>
|
|
1726
|
+
</div>
|
|
1736
1727
|
</template>
|
|
1737
1728
|
</div>
|
|
1738
1729
|
|