@sleep2agi/agent-network-dashboard 0.4.4-preview.0 → 0.4.5-preview.1
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/.next/BUILD_ID +1 -1
- package/.next/build-manifest.json +6 -6
- package/.next/diagnostics/route-bundle-stats.json +106 -92
- package/.next/fallback-build-manifest.json +3 -3
- package/.next/prerender-manifest.json +3 -3
- package/.next/server/app/_global-error/page/build-manifest.json +3 -3
- package/.next/server/app/_global-error.html +1 -1
- package/.next/server/app/_global-error.rsc +1 -1
- package/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/.next/server/app/_not-found/page/build-manifest.json +3 -3
- package/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next/server/app/_not-found.html +2 -2
- package/.next/server/app/_not-found.rsc +12 -12
- package/.next/server/app/_not-found.segments/_full.segment.rsc +12 -12
- package/.next/server/app/_not-found.segments/_head.segment.rsc +4 -4
- package/.next/server/app/_not-found.segments/_index.segment.rsc +7 -7
- package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
- package/.next/server/app/_not-found.segments/_not-found.segment.rsc +3 -3
- package/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/admin/page/build-manifest.json +3 -3
- package/.next/server/app/admin/page.js.nft.json +1 -1
- package/.next/server/app/admin/page_client-reference-manifest.js +1 -1
- package/.next/server/app/admin.html +2 -2
- package/.next/server/app/admin.rsc +14 -14
- package/.next/server/app/admin.segments/_full.segment.rsc +14 -14
- package/.next/server/app/admin.segments/_head.segment.rsc +4 -4
- package/.next/server/app/admin.segments/_index.segment.rsc +7 -7
- package/.next/server/app/admin.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/admin.segments/admin/__PAGE__.segment.rsc +4 -4
- package/.next/server/app/admin.segments/admin.segment.rsc +3 -3
- package/.next/server/app/index.html +2 -2
- package/.next/server/app/index.rsc +14 -14
- package/.next/server/app/index.segments/__PAGE__.segment.rsc +4 -4
- package/.next/server/app/index.segments/_full.segment.rsc +14 -14
- package/.next/server/app/index.segments/_head.segment.rsc +4 -4
- package/.next/server/app/index.segments/_index.segment.rsc +7 -7
- package/.next/server/app/index.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/login/page/build-manifest.json +3 -3
- package/.next/server/app/login/page.js.nft.json +1 -1
- package/.next/server/app/login/page_client-reference-manifest.js +1 -1
- package/.next/server/app/login.html +2 -2
- package/.next/server/app/login.rsc +14 -14
- package/.next/server/app/login.segments/_full.segment.rsc +14 -14
- package/.next/server/app/login.segments/_head.segment.rsc +4 -4
- package/.next/server/app/login.segments/_index.segment.rsc +7 -7
- package/.next/server/app/login.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/login.segments/login/__PAGE__.segment.rsc +4 -4
- package/.next/server/app/login.segments/login.segment.rsc +3 -3
- package/.next/server/app/logs/page/build-manifest.json +3 -3
- package/.next/server/app/logs/page.js.nft.json +1 -1
- package/.next/server/app/logs/page_client-reference-manifest.js +1 -1
- package/.next/server/app/logs.html +2 -2
- package/.next/server/app/logs.rsc +14 -14
- package/.next/server/app/logs.segments/_full.segment.rsc +14 -14
- package/.next/server/app/logs.segments/_head.segment.rsc +4 -4
- package/.next/server/app/logs.segments/_index.segment.rsc +7 -7
- package/.next/server/app/logs.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/logs.segments/logs/__PAGE__.segment.rsc +4 -4
- package/.next/server/app/logs.segments/logs.segment.rsc +3 -3
- package/.next/server/app/messages/page/build-manifest.json +3 -3
- package/.next/server/app/messages/page.js.nft.json +1 -1
- package/.next/server/app/messages/page_client-reference-manifest.js +1 -1
- package/.next/server/app/messages.html +2 -2
- package/.next/server/app/messages.rsc +14 -14
- package/.next/server/app/messages.segments/_full.segment.rsc +14 -14
- package/.next/server/app/messages.segments/_head.segment.rsc +4 -4
- package/.next/server/app/messages.segments/_index.segment.rsc +7 -7
- package/.next/server/app/messages.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/messages.segments/messages/__PAGE__.segment.rsc +4 -4
- package/.next/server/app/messages.segments/messages.segment.rsc +3 -3
- package/.next/server/app/node/page/build-manifest.json +3 -3
- package/.next/server/app/node/page.js.nft.json +1 -1
- package/.next/server/app/node/page_client-reference-manifest.js +1 -1
- package/.next/server/app/node.html +2 -2
- package/.next/server/app/node.rsc +14 -14
- package/.next/server/app/node.segments/_full.segment.rsc +14 -14
- package/.next/server/app/node.segments/_head.segment.rsc +4 -4
- package/.next/server/app/node.segments/_index.segment.rsc +7 -7
- package/.next/server/app/node.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/node.segments/node/__PAGE__.segment.rsc +4 -4
- package/.next/server/app/node.segments/node.segment.rsc +3 -3
- package/.next/server/app/nodes/page/build-manifest.json +3 -3
- package/.next/server/app/nodes/page.js.nft.json +1 -1
- package/.next/server/app/nodes/page_client-reference-manifest.js +1 -1
- package/.next/server/app/nodes.html +2 -2
- package/.next/server/app/nodes.rsc +14 -14
- package/.next/server/app/nodes.segments/_full.segment.rsc +14 -14
- package/.next/server/app/nodes.segments/_head.segment.rsc +4 -4
- package/.next/server/app/nodes.segments/_index.segment.rsc +7 -7
- package/.next/server/app/nodes.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/nodes.segments/nodes/__PAGE__.segment.rsc +4 -4
- package/.next/server/app/nodes.segments/nodes.segment.rsc +3 -3
- package/.next/server/app/page/build-manifest.json +3 -3
- package/.next/server/app/page.js.nft.json +1 -1
- package/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/server/app/server-logs/page/build-manifest.json +3 -3
- package/.next/server/app/server-logs/page.js.nft.json +1 -1
- package/.next/server/app/server-logs/page_client-reference-manifest.js +1 -1
- package/.next/server/app/server-logs.html +2 -2
- package/.next/server/app/server-logs.rsc +14 -14
- package/.next/server/app/server-logs.segments/_full.segment.rsc +14 -14
- package/.next/server/app/server-logs.segments/_head.segment.rsc +4 -4
- package/.next/server/app/server-logs.segments/_index.segment.rsc +7 -7
- package/.next/server/app/server-logs.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/server-logs.segments/server-logs/__PAGE__.segment.rsc +4 -4
- package/.next/server/app/server-logs.segments/server-logs.segment.rsc +3 -3
- package/.next/server/app/settings/networks/page/build-manifest.json +3 -3
- package/.next/server/app/settings/networks/page.js.nft.json +1 -1
- package/.next/server/app/settings/networks/page_client-reference-manifest.js +1 -1
- package/.next/server/app/settings/networks.html +2 -2
- package/.next/server/app/settings/networks.rsc +14 -14
- package/.next/server/app/settings/networks.segments/_full.segment.rsc +14 -14
- package/.next/server/app/settings/networks.segments/_head.segment.rsc +4 -4
- package/.next/server/app/settings/networks.segments/_index.segment.rsc +7 -7
- package/.next/server/app/settings/networks.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/settings/networks.segments/settings/networks/__PAGE__.segment.rsc +4 -4
- package/.next/server/app/settings/networks.segments/settings/networks.segment.rsc +3 -3
- package/.next/server/app/settings/networks.segments/settings.segment.rsc +3 -3
- package/.next/server/app/settings/page/build-manifest.json +3 -3
- package/.next/server/app/settings/page.js.nft.json +1 -1
- package/.next/server/app/settings/page_client-reference-manifest.js +1 -1
- package/.next/server/app/settings/tokens/page/build-manifest.json +3 -3
- package/.next/server/app/settings/tokens/page.js.nft.json +1 -1
- package/.next/server/app/settings/tokens/page_client-reference-manifest.js +1 -1
- package/.next/server/app/settings/tokens.html +2 -2
- package/.next/server/app/settings/tokens.rsc +14 -14
- package/.next/server/app/settings/tokens.segments/_full.segment.rsc +14 -14
- package/.next/server/app/settings/tokens.segments/_head.segment.rsc +4 -4
- package/.next/server/app/settings/tokens.segments/_index.segment.rsc +7 -7
- package/.next/server/app/settings/tokens.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/settings/tokens.segments/settings/tokens/__PAGE__.segment.rsc +4 -4
- package/.next/server/app/settings/tokens.segments/settings/tokens.segment.rsc +3 -3
- package/.next/server/app/settings/tokens.segments/settings.segment.rsc +3 -3
- package/.next/server/app/settings.html +2 -2
- package/.next/server/app/settings.rsc +14 -14
- package/.next/server/app/settings.segments/_full.segment.rsc +14 -14
- package/.next/server/app/settings.segments/_head.segment.rsc +4 -4
- package/.next/server/app/settings.segments/_index.segment.rsc +7 -7
- package/.next/server/app/settings.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/settings.segments/settings/__PAGE__.segment.rsc +4 -4
- package/.next/server/app/settings.segments/settings.segment.rsc +3 -3
- package/.next/server/app/tasks/[id]/page/build-manifest.json +3 -3
- package/.next/server/app/tasks/[id]/page.js.nft.json +1 -1
- package/.next/server/app/tasks/[id]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/tasks/page/build-manifest.json +3 -3
- package/.next/server/app/tasks/page.js.nft.json +1 -1
- package/.next/server/app/tasks/page_client-reference-manifest.js +1 -1
- package/.next/server/app/tasks.html +2 -2
- package/.next/server/app/tasks.rsc +14 -14
- package/.next/server/app/tasks.segments/_full.segment.rsc +14 -14
- package/.next/server/app/tasks.segments/_head.segment.rsc +4 -4
- package/.next/server/app/tasks.segments/_index.segment.rsc +7 -7
- package/.next/server/app/tasks.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/tasks.segments/tasks/__PAGE__.segment.rsc +4 -4
- package/.next/server/app/tasks.segments/tasks.segment.rsc +3 -3
- package/.next/server/chunks/ssr/[root-of-the-server]__0_jnflc._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0_jnflc._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0a0ffmv._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0a0ffmv._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__12mpoig._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__12mpoig._.js.map +1 -0
- package/.next/server/chunks/ssr/_0d-fuox._.js +3 -0
- package/.next/server/chunks/ssr/_0d-fuox._.js.map +1 -0
- package/.next/server/chunks/ssr/app_0.0wpa~._.js +3 -0
- package/.next/server/chunks/ssr/app_0.0wpa~._.js.map +1 -0
- package/.next/server/chunks/ssr/app_0dk5wao._.js +1 -1
- package/.next/server/chunks/ssr/app_0dk5wao._.js.map +1 -1
- package/.next/server/chunks/ssr/app_0et5yua._.js +3 -0
- package/.next/server/chunks/ssr/app_0et5yua._.js.map +1 -0
- package/.next/server/chunks/ssr/app_0ff~kjj._.js +9 -0
- package/.next/server/chunks/ssr/app_0ff~kjj._.js.map +1 -0
- package/.next/server/chunks/ssr/app_0izi28j._.js +3 -0
- package/.next/server/chunks/ssr/app_0izi28j._.js.map +1 -0
- package/.next/server/chunks/ssr/app_components_08ys5y3._.js +9 -0
- package/.next/server/chunks/ssr/app_components_08ys5y3._.js.map +1 -0
- package/.next/server/chunks/ssr/app_login_page_tsx_0z71ad3._.js +1 -1
- package/.next/server/chunks/ssr/app_login_page_tsx_0z71ad3._.js.map +1 -1
- package/.next/server/chunks/ssr/app_page_tsx_0es_sk2._.js +1 -1
- package/.next/server/chunks/ssr/app_page_tsx_0es_sk2._.js.map +1 -1
- package/.next/server/chunks/ssr/app_tasks_page_tsx_0z-d6mp._.js +1 -1
- package/.next/server/chunks/ssr/app_tasks_page_tsx_0z-d6mp._.js.map +1 -1
- package/.next/server/chunks/ssr/node_modules_0ck2~9g._.js +3 -0
- package/.next/server/chunks/ssr/node_modules_0ck2~9g._.js.map +1 -0
- package/.next/server/middleware-build-manifest.js +6 -6
- package/.next/server/pages/404.html +2 -2
- package/.next/server/pages/500.html +1 -1
- package/.next/server/server-reference-manifest.js +1 -1
- package/.next/server/server-reference-manifest.json +1 -1
- package/.next/static/chunks/0257pdz1-imal.js +2 -0
- package/.next/static/chunks/02flrewxlf_m_.js +1 -0
- package/.next/static/chunks/051gslfjka1kj.js +1 -0
- package/.next/static/chunks/06t_vzei8s9_h.js +1 -0
- package/.next/static/chunks/0a1wbl-spby3_.css +2 -0
- package/.next/static/chunks/0e-.zgw81gela.js +31 -0
- package/.next/static/chunks/0e7c40p~wq665.js +1 -0
- package/.next/static/chunks/0g7m7zk.v7g6h.js +1 -0
- package/.next/static/chunks/0gs9-~h7-pkuu.js +7 -0
- package/.next/static/chunks/0j3s_1ee66awv.js +1 -0
- package/.next/static/chunks/0khpyxpdrp~ty.js +1 -0
- package/.next/static/chunks/0lo_g.q1fm-hr.js +7 -0
- package/.next/static/chunks/0w1zwt8kq_7nb.js +1 -0
- package/.next/static/chunks/1031v6nw33ud3.js +1 -0
- package/.next/static/chunks/13.dst7liziwo.js +1 -0
- package/.next/static/chunks/{turbopack-0vsvjs02l449s.js → turbopack-01f1xs~cq_~si.js} +1 -1
- package/.next/trace +2 -2
- package/.next/trace-build +1 -1
- package/app/components/AppShell.tsx +9 -1
- package/app/components/CommandPalette.tsx +316 -0
- package/app/components/EmptyState.tsx +189 -0
- package/app/components/HealthBanner.tsx +132 -0
- package/app/components/HelpOverlay.tsx +121 -0
- package/app/components/LoadingSkeleton.tsx +81 -40
- package/app/components/Sidebar.tsx +90 -11
- package/app/components/TopoGraph.tsx +151 -62
- package/app/components/UserBar.tsx +16 -2
- package/app/globals.css +175 -0
- package/app/login/page.tsx +26 -13
- package/app/logs/page.tsx +2 -5
- package/app/messages/page.tsx +2 -5
- package/app/nodes/page.tsx +6 -1
- package/app/page.tsx +109 -12
- package/app/settings/networks/page.tsx +6 -1
- package/app/settings/page.tsx +56 -29
- package/app/settings/tokens/page.tsx +6 -1
- package/app/tasks/page.tsx +39 -14
- package/docs/loop-design-rounds.md +797 -0
- package/docs/oss-readiness-report.md +189 -0
- package/docs/screenshots/0.4.5-preview.1/cyber-admin.png +0 -0
- package/docs/screenshots/0.4.5-preview.1/cyber-cmdk-search.png +0 -0
- package/docs/screenshots/0.4.5-preview.1/cyber-cmdk.png +0 -0
- package/docs/screenshots/0.4.5-preview.1/cyber-login.png +0 -0
- package/docs/screenshots/0.4.5-preview.1/cyber-overview.png +0 -0
- package/docs/screenshots/0.4.5-preview.1/cyber-settings.png +0 -0
- package/docs/screenshots/0.4.5-preview.1/cyber-tasks.png +0 -0
- package/docs/screenshots/0.4.5-preview.1/light-admin.png +0 -0
- package/docs/screenshots/0.4.5-preview.1/light-cmdk-search.png +0 -0
- package/docs/screenshots/0.4.5-preview.1/light-cmdk.png +0 -0
- package/docs/screenshots/0.4.5-preview.1/light-login.png +0 -0
- package/docs/screenshots/0.4.5-preview.1/light-overview.png +0 -0
- package/docs/screenshots/0.4.5-preview.1/light-settings.png +0 -0
- package/docs/screenshots/0.4.5-preview.1/light-tasks.png +0 -0
- package/package.json +1 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__093ymui._.js +0 -3
- package/.next/server/chunks/ssr/[root-of-the-server]__093ymui._.js.map +0 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__0i1gizm._.js +0 -9
- package/.next/server/chunks/ssr/[root-of-the-server]__0i1gizm._.js.map +0 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__0~yad5w._.js +0 -3
- package/.next/server/chunks/ssr/[root-of-the-server]__0~yad5w._.js.map +0 -1
- package/.next/server/chunks/ssr/_06_xh1~._.js +0 -3
- package/.next/server/chunks/ssr/_06_xh1~._.js.map +0 -1
- package/.next/server/chunks/ssr/app_01vhyfx._.js +0 -9
- package/.next/server/chunks/ssr/app_01vhyfx._.js.map +0 -1
- package/.next/server/chunks/ssr/app_023a94i._.js +0 -3
- package/.next/server/chunks/ssr/app_023a94i._.js.map +0 -1
- package/.next/server/chunks/ssr/app_0basiqb._.js +0 -3
- package/.next/server/chunks/ssr/app_0basiqb._.js.map +0 -1
- package/.next/server/chunks/ssr/app_0pljk5o._.js +0 -3
- package/.next/server/chunks/ssr/app_0pljk5o._.js.map +0 -1
- package/.next/server/chunks/ssr/node_modules_next_dist_0t-hj0x._.js +0 -3
- package/.next/server/chunks/ssr/node_modules_next_dist_0t-hj0x._.js.map +0 -1
- package/.next/static/chunks/0.z~9klrgd.t-.js +0 -1
- package/.next/static/chunks/08aj9~75raaah.js +0 -7
- package/.next/static/chunks/08iom_z8w-wmz.js +0 -7
- package/.next/static/chunks/08v0-ki6vwpxf.js +0 -1
- package/.next/static/chunks/0dkkv90do9a4r.js +0 -1
- package/.next/static/chunks/0e-wrhqh4h3r5.js +0 -2
- package/.next/static/chunks/0ejz4zwhu3a3y.js +0 -1
- package/.next/static/chunks/0o5zj~5vjeks3.js +0 -1
- package/.next/static/chunks/0uqfv6rc-xdru.js +0 -1
- package/.next/static/chunks/0u~_.32f.midj.css +0 -2
- package/.next/static/chunks/0xrnwfefpke-g.js +0 -31
- package/.next/static/chunks/0y_po~f~fk~ap.js +0 -1
- package/.next/static/chunks/14sm.ta0zylsj.js +0 -1
- package/.next/static/chunks/18ac93ii3mjlj.js +0 -1
- /package/.next/static/{jTh5m77FIfQccc0gftvik → wcTnZXyx_R19_Ur1_cGMP}/_buildManifest.js +0 -0
- /package/.next/static/{jTh5m77FIfQccc0gftvik → wcTnZXyx_R19_Ur1_cGMP}/_clientMiddlewareManifest.js +0 -0
- /package/.next/static/{jTh5m77FIfQccc0gftvik → wcTnZXyx_R19_Ur1_cGMP}/_ssgManifest.js +0 -0
package/app/messages/page.tsx
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import { useMemo, useState } from 'react';
|
|
4
4
|
import { useMessages } from '../lib/hooks';
|
|
5
5
|
import { timeAgo } from '../components/utils';
|
|
6
|
+
import { EmptyState } from '../components/EmptyState';
|
|
6
7
|
|
|
7
8
|
interface MessageItem {
|
|
8
9
|
id: string;
|
|
@@ -186,11 +187,7 @@ export default function MessagesPage() {
|
|
|
186
187
|
{[1, 2, 3, 4, 5].map(i => <div key={i} className="h-20 rounded-2xl bg-gray-800/20" />)}
|
|
187
188
|
</div>
|
|
188
189
|
) : filtered.length === 0 ? (
|
|
189
|
-
<
|
|
190
|
-
<div className="text-gray-600 text-4xl mb-4">--</div>
|
|
191
|
-
<h3 className="text-gray-400 text-lg font-medium mb-2">No messages</h3>
|
|
192
|
-
<p className="text-gray-600 text-sm">Messages between agents will appear here.</p>
|
|
193
|
-
</div>
|
|
190
|
+
<EmptyState variant="messages" />
|
|
194
191
|
) : viewMode === 'grouped' ? (
|
|
195
192
|
<div className="space-y-4">
|
|
196
193
|
{conversations.map((conv, ci) => (
|
package/app/nodes/page.tsx
CHANGED
|
@@ -5,6 +5,7 @@ import Link from 'next/link';
|
|
|
5
5
|
import { timeAgo } from '../components/utils';
|
|
6
6
|
import { useSessions, useHealth } from '../lib/hooks';
|
|
7
7
|
import { TaskChatPanel } from '../components/TaskChatPanel';
|
|
8
|
+
import { EmptyState } from '../components/EmptyState';
|
|
8
9
|
import type { Session } from '../components/types';
|
|
9
10
|
|
|
10
11
|
const STATUS_COLORS: Record<string, string> = {
|
|
@@ -163,7 +164,11 @@ export default function NodesPage() {
|
|
|
163
164
|
{[1,2,3,4].map(i => <div key={i} className="h-16 bg-gray-800/20 rounded-lg" />)}
|
|
164
165
|
</div>
|
|
165
166
|
) : filtered.length === 0 ? (
|
|
166
|
-
<
|
|
167
|
+
<EmptyState
|
|
168
|
+
variant="nodes"
|
|
169
|
+
title="No nodes match your filters"
|
|
170
|
+
sub="Try clearing search or status filters, or wait for an agent to register."
|
|
171
|
+
/>
|
|
167
172
|
) : viewMode === 'grid' ? (
|
|
168
173
|
<div className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-4">
|
|
169
174
|
{filtered.map(s => {
|
package/app/page.tsx
CHANGED
|
@@ -8,7 +8,8 @@ import { BroadcastBar } from './components/BroadcastBar';
|
|
|
8
8
|
import { TopoGraph } from './components/TopoGraph';
|
|
9
9
|
import { AgentCard } from './components/AgentCard';
|
|
10
10
|
import { InboxPanel } from './components/InboxPanel';
|
|
11
|
-
import { LoadingSkeleton
|
|
11
|
+
import { LoadingSkeleton } from './components/LoadingSkeleton';
|
|
12
|
+
import { NodesEmptyState as EmptyState } from './components/EmptyState';
|
|
12
13
|
import { UserBar } from './components/UserBar';
|
|
13
14
|
import { CommandCenter, useCommandCenter } from './components/CommandCenter';
|
|
14
15
|
import { DispatchPanel } from './components/DispatchPanel';
|
|
@@ -185,19 +186,115 @@ export default function Dashboard() {
|
|
|
185
186
|
</section>
|
|
186
187
|
)}
|
|
187
188
|
|
|
188
|
-
{/* Quick Actions
|
|
189
|
-
|
|
189
|
+
{/* Quick Actions — split into two distinct intents:
|
|
190
|
+
(1) Top: live stat cards (carry data, drill-in on click)
|
|
191
|
+
(2) Bottom: pure nav rail (no number, icon + label)
|
|
192
|
+
Previously these were mixed in one row of 6, mixing data cells
|
|
193
|
+
("0/0", "--", "0") with placeholder arrows ("→ Messages").
|
|
194
|
+
Users couldn't tell which were stats vs which were navigation. */}
|
|
195
|
+
<section className="mb-3 grid grid-cols-3 gap-2 sm:gap-3">
|
|
196
|
+
{(() => {
|
|
197
|
+
// Build breakdown popover content per card. Pure data — pure CSS
|
|
198
|
+
// popover (no JS state) wires the hover-show transition below.
|
|
199
|
+
const idleCount = sessions.filter(s => isOnline(s) && s.status !== 'working').length;
|
|
200
|
+
const offlineCount = total - online;
|
|
201
|
+
const orderedStatuses = ['running', 'replied', 'failed', 'cancelled', 'expired', 'closed', 'created', 'delivered', 'acked'];
|
|
202
|
+
const failedRecent = tasks.filter((t: { status: string }) => t.status === 'failed').length;
|
|
203
|
+
|
|
204
|
+
const cards = [
|
|
205
|
+
{
|
|
206
|
+
href: '/nodes', label: 'Nodes',
|
|
207
|
+
value: `${online}/${total}`,
|
|
208
|
+
sub: `${total > 0 ? Math.round((online / total) * 100) : 0}% online`,
|
|
209
|
+
color: 'text-green-400 border-green-500/20',
|
|
210
|
+
popover: total === 0 ? null : [
|
|
211
|
+
{ k: 'working', v: working, dot: '', color: '#4ade80' },
|
|
212
|
+
{ k: 'idle', v: idleCount, dot: '', color: '#22d3ee' },
|
|
213
|
+
{ k: 'offline', v: offlineCount, dot: '', color: '#9ca3af' },
|
|
214
|
+
],
|
|
215
|
+
},
|
|
216
|
+
{
|
|
217
|
+
href: '/tasks', label: 'Tasks',
|
|
218
|
+
value: String(Object.values(taskStats).reduce((a, b) => a + b, 0) || 0),
|
|
219
|
+
sub: 'all-time',
|
|
220
|
+
color: 'text-cyan-400 border-cyan-500/20',
|
|
221
|
+
popover: Object.keys(taskStats).length === 0 ? null
|
|
222
|
+
: orderedStatuses
|
|
223
|
+
.filter(s => taskStats[s])
|
|
224
|
+
.map(s => {
|
|
225
|
+
// Inline hex avoids Tailwind purging dynamic
|
|
226
|
+
// `bg-${color}-400` class names.
|
|
227
|
+
const hex = ({
|
|
228
|
+
running: '#4ade80', replied: '#a78bfa', failed: '#f87171',
|
|
229
|
+
cancelled: '#facc15', expired: '#fb923c', closed: '#9ca3af',
|
|
230
|
+
created: '#9ca3af', delivered: '#60a5fa', acked: '#22d3ee',
|
|
231
|
+
} as Record<string, string>)[s] || '#9ca3af';
|
|
232
|
+
return { k: s, v: taskStats[s], dot: '', color: hex };
|
|
233
|
+
}),
|
|
234
|
+
},
|
|
235
|
+
{
|
|
236
|
+
href: '/tasks?status=failed', label: 'Failed',
|
|
237
|
+
value: String(taskStats['failed'] || 0),
|
|
238
|
+
sub: taskStats['failed'] ? 'needs review' : 'none',
|
|
239
|
+
color: taskStats['failed'] ? 'text-red-400 border-red-500/25' : 'text-gray-500 border-gray-700/30',
|
|
240
|
+
popover: !failedRecent ? [{ k: 'no failures yet', v: '', dot: '', color: '#4b5563' }]
|
|
241
|
+
: [{ k: `${failedRecent} in current view`, v: '', dot: '', color: '#f87171' }],
|
|
242
|
+
},
|
|
243
|
+
];
|
|
244
|
+
|
|
245
|
+
return cards.map(a => (
|
|
246
|
+
<Link
|
|
247
|
+
key={a.href}
|
|
248
|
+
href={a.href}
|
|
249
|
+
prefetch={false}
|
|
250
|
+
className={`anet-stat-link group relative rounded-xl border ${a.color} bg-[#111128] px-3 py-3 transition-all hover:-translate-y-px`}
|
|
251
|
+
>
|
|
252
|
+
<div className="flex items-baseline justify-between">
|
|
253
|
+
<div className={`text-xl font-semibold tabular-nums ${a.color.split(' ')[0]}`}>{a.value}</div>
|
|
254
|
+
<div className="hidden sm:block text-[10px] text-gray-600 group-hover:text-gray-400 transition-colors">View →</div>
|
|
255
|
+
</div>
|
|
256
|
+
<div className="text-[11px] text-gray-400 mt-0.5">{a.label}</div>
|
|
257
|
+
<div className="text-[10px] text-gray-600 mt-px">{a.sub}</div>
|
|
258
|
+
|
|
259
|
+
{/* Hover popover — CSS-only, restrained. Hidden on touch
|
|
260
|
+
(no :hover) so mobile is unaffected. Positioned just
|
|
261
|
+
below the card so it doesn't fight nav rail. */}
|
|
262
|
+
{a.popover && a.popover.length > 0 && (
|
|
263
|
+
<div className="anet-stat-popover hidden md:block pointer-events-none absolute left-2 right-2 top-full mt-1 z-20 rounded-lg border border-[#2a2a4a] bg-[#0d0d1a] shadow-lg shadow-black/30 px-3 py-2 opacity-0 translate-y-[-2px] group-hover:opacity-100 group-hover:translate-y-0 transition-all duration-150 delay-100">
|
|
264
|
+
<div className="text-[10px] text-gray-600 uppercase tracking-wider mb-1.5">Breakdown</div>
|
|
265
|
+
<ul className="space-y-1">
|
|
266
|
+
{a.popover.map(row => (
|
|
267
|
+
<li key={row.k} className="flex items-center gap-2 text-[11px]">
|
|
268
|
+
<span
|
|
269
|
+
className="inline-block w-1.5 h-1.5 rounded-full shrink-0"
|
|
270
|
+
style={{ backgroundColor: row.color }}
|
|
271
|
+
aria-hidden
|
|
272
|
+
/>
|
|
273
|
+
<span className="text-gray-400 capitalize">{row.k}</span>
|
|
274
|
+
{row.v !== '' && <span className="ml-auto text-gray-300 tabular-nums font-medium">{row.v}</span>}
|
|
275
|
+
</li>
|
|
276
|
+
))}
|
|
277
|
+
</ul>
|
|
278
|
+
</div>
|
|
279
|
+
)}
|
|
280
|
+
</Link>
|
|
281
|
+
));
|
|
282
|
+
})()}
|
|
283
|
+
</section>
|
|
284
|
+
|
|
285
|
+
{/* Nav rail — pure navigation, icon + label, no data */}
|
|
286
|
+
<section className="mb-6 grid grid-cols-3 gap-2 sm:gap-3">
|
|
190
287
|
{[
|
|
191
|
-
{ href: '/
|
|
192
|
-
{ href: '/
|
|
193
|
-
{ href: '/
|
|
194
|
-
{ href: '/messages', label: 'Messages', value: '→', color: 'text-blue-400 border-blue-500/15' },
|
|
195
|
-
{ href: '/logs', label: 'Logs', value: '→', color: 'text-purple-400 border-purple-500/15' },
|
|
196
|
-
{ href: '/admin', label: 'Admin', value: '→', color: 'text-gray-400 border-gray-500/15' },
|
|
288
|
+
{ href: '/messages', label: 'Messages', icon: 'M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z' },
|
|
289
|
+
{ href: '/logs', label: 'Audit log', icon: 'M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z M14 2v6h6 M16 13H8 M16 17H8 M10 9H8' },
|
|
290
|
+
{ href: '/admin', label: 'Admin', icon: 'M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4z M6 21v-2a4 4 0 0 1 4-4h4a4 4 0 0 1 4 4v2' },
|
|
197
291
|
].map(a => (
|
|
198
|
-
<Link key={a.href} href={a.href} prefetch={false}
|
|
199
|
-
|
|
200
|
-
<
|
|
292
|
+
<Link key={a.href} href={a.href} prefetch={false}
|
|
293
|
+
className="anet-nav-tile flex items-center justify-center gap-2 rounded-xl border border-[#2a2a4a] bg-[#111128] px-3 py-2.5 text-[12px] text-gray-400 hover:text-gray-200 transition-colors">
|
|
294
|
+
<svg className="w-4 h-4 shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
|
|
295
|
+
<path d={a.icon} />
|
|
296
|
+
</svg>
|
|
297
|
+
<span>{a.label}</span>
|
|
201
298
|
</Link>
|
|
202
299
|
))}
|
|
203
300
|
</section>
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import { useEffect, useState, useCallback } from 'react';
|
|
4
4
|
import Link from 'next/link';
|
|
5
5
|
import { timeAgo } from '../../components/utils';
|
|
6
|
+
import { EmptyState } from '../../components/EmptyState';
|
|
6
7
|
import useSWR from 'swr';
|
|
7
8
|
|
|
8
9
|
const fetcher = (url: string) => fetch(url).then(r => r.json());
|
|
@@ -126,7 +127,11 @@ export default function NetworksPage() {
|
|
|
126
127
|
{loading ? (
|
|
127
128
|
<div className="animate-pulse space-y-2">{[1,2].map(i => <div key={i} className="h-14 bg-gray-800/20 rounded" />)}</div>
|
|
128
129
|
) : networks.length === 0 ? (
|
|
129
|
-
<
|
|
130
|
+
<EmptyState
|
|
131
|
+
variant="networks"
|
|
132
|
+
compact
|
|
133
|
+
sub="Create your first network above, or sign in with V3 auth to see existing ones."
|
|
134
|
+
/>
|
|
130
135
|
) : (
|
|
131
136
|
<div className="space-y-3">
|
|
132
137
|
{networks.map(n => (
|
package/app/settings/page.tsx
CHANGED
|
@@ -20,7 +20,11 @@ export default function SettingsPage() {
|
|
|
20
20
|
<div className="min-h-screen bg-[#0a0a1a] text-gray-100 p-4 sm:p-6 font-mono">
|
|
21
21
|
<h1 className="text-2xl font-bold text-white mb-6 lg:ml-0 ml-10">Settings</h1>
|
|
22
22
|
|
|
23
|
-
<div className="max-w-2xl space-y-
|
|
23
|
+
<div className="max-w-2xl space-y-8">
|
|
24
|
+
{/* ── Group: Connection ─────────────────────────────────── */}
|
|
25
|
+
<div className="space-y-4">
|
|
26
|
+
<div className="text-[10px] uppercase tracking-[0.12em] text-gray-600 px-1">Connection</div>
|
|
27
|
+
|
|
24
28
|
{/* CommHub Connection */}
|
|
25
29
|
<section className="bg-[#111128] border border-[#2a2a4a] rounded-xl p-5">
|
|
26
30
|
<h2 className="text-sm font-semibold text-gray-300 mb-4">CommHub Connection</h2>
|
|
@@ -96,25 +100,41 @@ export default function SettingsPage() {
|
|
|
96
100
|
</div>
|
|
97
101
|
</div>
|
|
98
102
|
</section>
|
|
103
|
+
</div>
|
|
104
|
+
|
|
105
|
+
{/* ── Group: Account ────────────────────────────────────── */}
|
|
106
|
+
<div className="space-y-4">
|
|
107
|
+
<div className="text-[10px] uppercase tracking-[0.12em] text-gray-600 px-1">Account</div>
|
|
99
108
|
|
|
100
109
|
{/* License */}
|
|
101
110
|
<section className="bg-[#111128] border border-[#2a2a4a] rounded-xl p-5">
|
|
102
|
-
<h2 className="text-sm font-semibold text-gray-300 mb-4">
|
|
111
|
+
<h2 className="text-sm font-semibold text-gray-300 mb-4 flex items-center gap-2">
|
|
112
|
+
License
|
|
113
|
+
{licData?.license && (
|
|
114
|
+
<span
|
|
115
|
+
className={`inline-flex items-center gap-1.5 text-[10px] font-medium px-2 py-0.5 rounded-full border ${
|
|
116
|
+
licData.license.type === 'pro'
|
|
117
|
+
? 'text-green-300 bg-green-500/10 border-green-500/30'
|
|
118
|
+
: licData.license.days_left <= 7
|
|
119
|
+
? 'text-red-300 bg-red-500/10 border-red-500/30'
|
|
120
|
+
: 'text-amber-300 bg-amber-500/10 border-amber-500/30'
|
|
121
|
+
}`}
|
|
122
|
+
>
|
|
123
|
+
<span aria-hidden className="w-1.5 h-1.5 rounded-full bg-current" />
|
|
124
|
+
{licData.license.type}{licData.license.days_left ? ` · ${licData.license.days_left}d left` : ''}
|
|
125
|
+
</span>
|
|
126
|
+
)}
|
|
127
|
+
</h2>
|
|
103
128
|
{licData?.license ? (
|
|
104
129
|
<div className="space-y-3 text-sm">
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
<span className={`${licData.license.days_left <= 7 ? 'text-red-400' : 'text-gray-300'}`}>
|
|
114
|
-
{licData.license.days_left} days
|
|
115
|
-
{licData.license.days_left <= 7 && ' — expiring soon!'}
|
|
116
|
-
</span>
|
|
117
|
-
</div>
|
|
130
|
+
{/* Type + Days Left are summarized in the inline chip in the
|
|
131
|
+
header. Surface "expiring soon" only when relevant. */}
|
|
132
|
+
{licData.license.days_left <= 7 && (
|
|
133
|
+
<div className={rowClass}>
|
|
134
|
+
<span className="text-red-400 font-medium">⚠ Expiring soon</span>
|
|
135
|
+
<span className="text-red-400">{licData.license.days_left} days left</span>
|
|
136
|
+
</div>
|
|
137
|
+
)}
|
|
118
138
|
<div className={rowClass}>
|
|
119
139
|
<span className="text-gray-500">Expires</span>
|
|
120
140
|
<span className={`text-gray-300 ${valueClass}`}>{licData.license.expires_at}</span>
|
|
@@ -195,6 +215,26 @@ export default function SettingsPage() {
|
|
|
195
215
|
{pwdResult && <div className={`mt-2 text-xs ${pwdResult.startsWith('Failed') ? 'text-red-400' : 'text-green-400'}`}>{pwdResult}</div>}
|
|
196
216
|
</section>
|
|
197
217
|
|
|
218
|
+
{/* Session — tone-neutral, no longer "danger zone" red */}
|
|
219
|
+
<section className="bg-[#111128] border border-[#2a2a4a] rounded-xl p-5">
|
|
220
|
+
<h2 className="text-sm font-semibold text-gray-300 mb-4">Sign out</h2>
|
|
221
|
+
<p className="text-xs text-gray-500 mb-3">Signing out clears your dashboard session cookie. You'll return to the login page.</p>
|
|
222
|
+
<button
|
|
223
|
+
onClick={async () => {
|
|
224
|
+
await fetch('/api/auth/logout', { method: 'POST' }).catch(() => {});
|
|
225
|
+
window.location.assign('/login');
|
|
226
|
+
}}
|
|
227
|
+
className="px-4 py-2 bg-transparent hover:bg-[#1a1a2a] text-gray-300 text-sm rounded-lg border border-[#2a2a4a] hover:border-[#3a3a5a] transition-colors"
|
|
228
|
+
>
|
|
229
|
+
Sign out
|
|
230
|
+
</button>
|
|
231
|
+
</section>
|
|
232
|
+
</div>
|
|
233
|
+
|
|
234
|
+
{/* ── Group: Resources ──────────────────────────────────── */}
|
|
235
|
+
<div className="space-y-4">
|
|
236
|
+
<div className="text-[10px] uppercase tracking-[0.12em] text-gray-600 px-1">Resources</div>
|
|
237
|
+
|
|
198
238
|
{/* API Tokens + Networks */}
|
|
199
239
|
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
|
200
240
|
<Link href="/settings/tokens" className="bg-[#111128] border border-[#2a2a4a] rounded-xl p-5 hover:border-cyan-500/30 transition-colors">
|
|
@@ -208,21 +248,8 @@ export default function SettingsPage() {
|
|
|
208
248
|
<span className="text-xs text-cyan-400 mt-3 inline-block">Manage →</span>
|
|
209
249
|
</Link>
|
|
210
250
|
</div>
|
|
251
|
+
</div>
|
|
211
252
|
|
|
212
|
-
{/* Danger Zone */}
|
|
213
|
-
<section className="bg-[#111128] border border-red-900/30 rounded-xl p-5">
|
|
214
|
-
<h2 className="text-sm font-semibold text-red-400 mb-4">Session</h2>
|
|
215
|
-
<p className="text-xs text-gray-500 mb-3">Sign out will clear your dashboard session cookie.</p>
|
|
216
|
-
<button
|
|
217
|
-
onClick={async () => {
|
|
218
|
-
await fetch('/api/auth/logout', { method: 'POST' }).catch(() => {});
|
|
219
|
-
window.location.assign('/login');
|
|
220
|
-
}}
|
|
221
|
-
className="px-4 py-2 bg-red-600/20 hover:bg-red-600/30 text-red-300 text-sm rounded-lg border border-red-800/30 transition-colors"
|
|
222
|
-
>
|
|
223
|
-
Sign out
|
|
224
|
-
</button>
|
|
225
|
-
</section>
|
|
226
253
|
</div>
|
|
227
254
|
</div>
|
|
228
255
|
);
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import { useEffect, useState, useCallback } from 'react';
|
|
4
4
|
import Link from 'next/link';
|
|
5
5
|
import { timeAgo } from '../../components/utils';
|
|
6
|
+
import { EmptyState } from '../../components/EmptyState';
|
|
6
7
|
|
|
7
8
|
interface Token {
|
|
8
9
|
token_id: string;
|
|
@@ -100,7 +101,11 @@ export default function TokensPage() {
|
|
|
100
101
|
{loading ? (
|
|
101
102
|
<div className="animate-pulse space-y-2">{[1,2].map(i => <div key={i} className="h-12 bg-gray-800/20 rounded" />)}</div>
|
|
102
103
|
) : tokens.length === 0 ? (
|
|
103
|
-
<
|
|
104
|
+
<EmptyState
|
|
105
|
+
variant="tokens"
|
|
106
|
+
compact
|
|
107
|
+
sub="Tokens authenticate CLI tools and external integrations. Sign in with V3 auth, then create one above."
|
|
108
|
+
/>
|
|
104
109
|
) : (
|
|
105
110
|
<div className="space-y-2">
|
|
106
111
|
{tokens.map(t => (
|
package/app/tasks/page.tsx
CHANGED
|
@@ -5,6 +5,7 @@ import { useSearchParams } from 'next/navigation';
|
|
|
5
5
|
import Link from 'next/link';
|
|
6
6
|
import { useNetworkId } from '../lib/network-context';
|
|
7
7
|
import { TaskDrawer } from '../components/TaskDrawer';
|
|
8
|
+
import { EmptyState } from '../components/EmptyState';
|
|
8
9
|
|
|
9
10
|
interface Task {
|
|
10
11
|
task_id: string;
|
|
@@ -47,6 +48,21 @@ const STATUS_COLORS: Record<string, string> = {
|
|
|
47
48
|
expired: 'bg-orange-500/10 text-orange-300 border-orange-500/20',
|
|
48
49
|
};
|
|
49
50
|
|
|
51
|
+
/** Small colored dot per status — visible on every tab (active + inactive)
|
|
52
|
+
* so users can scan the row at a glance. Hex inlined to avoid Tailwind
|
|
53
|
+
* purging dynamic `bg-${family}-400` class names. */
|
|
54
|
+
const STATUS_DOTS: Record<string, string> = {
|
|
55
|
+
created: '#9ca3af',
|
|
56
|
+
delivered: '#60a5fa',
|
|
57
|
+
acked: '#22d3ee',
|
|
58
|
+
running: '#4ade80',
|
|
59
|
+
replied: '#a78bfa',
|
|
60
|
+
closed: '#6b7280',
|
|
61
|
+
failed: '#f87171',
|
|
62
|
+
cancelled: '#facc15',
|
|
63
|
+
expired: '#fb923c',
|
|
64
|
+
};
|
|
65
|
+
|
|
50
66
|
function statusBadge(status: string) {
|
|
51
67
|
const color = STATUS_COLORS[status] || 'bg-gray-500/10 text-gray-400 border-gray-500/20';
|
|
52
68
|
return `text-xs px-2 py-0.5 rounded-md border ${color}`;
|
|
@@ -133,16 +149,28 @@ function TasksContent() {
|
|
|
133
149
|
</span>
|
|
134
150
|
</div>
|
|
135
151
|
|
|
136
|
-
{/* Status Tabs
|
|
137
|
-
|
|
152
|
+
{/* Status Tabs — color-coded dots per status family so users can
|
|
153
|
+
scan the row at a glance. Active tab gets full chip styling
|
|
154
|
+
(bg + border + text color), inactive tabs only carry the dot
|
|
155
|
+
+ neutral label so the active state remains the strong cue.
|
|
156
|
+
On narrow viewports (<sm) the row scrolls horizontally with
|
|
157
|
+
subtle fade edges instead of wrapping to 2 lines. */}
|
|
158
|
+
<div className="anet-tabstrip flex sm:flex-wrap gap-1 mb-4 bg-[#111128] rounded-lg border border-[#2a2a4a] p-1 overflow-x-auto sm:overflow-x-visible scrollbar-thin">
|
|
138
159
|
{['', ...STATUS_OPTIONS.filter(Boolean)].map(s => (
|
|
139
160
|
<button key={s} onClick={() => setFilterStatus(s)}
|
|
140
|
-
className={`px-3 py-1.5 rounded-md text-xs transition-colors ${
|
|
161
|
+
className={`px-3 py-1.5 rounded-md text-xs transition-colors flex items-center gap-1.5 shrink-0 whitespace-nowrap ${
|
|
141
162
|
filterStatus === s
|
|
142
163
|
? `${STATUS_COLORS[s] || 'bg-cyan-500/10 text-cyan-300 border-cyan-500/20'} border`
|
|
143
|
-
: 'text-gray-500 hover:text-gray-300'
|
|
164
|
+
: 'text-gray-500 hover:text-gray-300 hover:bg-[#1a1a2a]/40'
|
|
144
165
|
}`}>
|
|
145
|
-
{s
|
|
166
|
+
{s && (
|
|
167
|
+
<span
|
|
168
|
+
aria-hidden
|
|
169
|
+
className="inline-block w-1.5 h-1.5 rounded-full shrink-0"
|
|
170
|
+
style={{ backgroundColor: STATUS_DOTS[s] || '#6b7280' }}
|
|
171
|
+
/>
|
|
172
|
+
)}
|
|
173
|
+
<span>{s || 'All'}</span>
|
|
146
174
|
</button>
|
|
147
175
|
))}
|
|
148
176
|
</div>
|
|
@@ -201,15 +229,12 @@ function TasksContent() {
|
|
|
201
229
|
))}
|
|
202
230
|
</div>
|
|
203
231
|
) : tasks.length === 0 ? (
|
|
204
|
-
<
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
: 'Tasks will appear here when agents send them via CommHub.'}
|
|
211
|
-
</p>
|
|
212
|
-
</div>
|
|
232
|
+
<EmptyState
|
|
233
|
+
variant="tasks"
|
|
234
|
+
sub={(filterStatus || filterFrom || filterTo)
|
|
235
|
+
? 'No tasks match the current filters. Try clearing them.'
|
|
236
|
+
: 'Tasks will appear here when agents send them via CommHub.'}
|
|
237
|
+
/>
|
|
213
238
|
) : (
|
|
214
239
|
<div className="space-y-2">
|
|
215
240
|
{/* Table header */}
|