@roj-ai/debug 0.0.2
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/dist/components/debug/DebugContext.d.ts +10 -0
- package/dist/components/debug/DebugNavigation.d.ts +29 -0
- package/dist/components/debug/DebugShell.d.ts +18 -0
- package/dist/components/debug/LLMCallDetail.d.ts +7 -0
- package/dist/components/debug/TimelineDetailInspector.d.ts +6 -0
- package/dist/components/debug/communication/CommunicationDiagram.d.ts +9 -0
- package/dist/components/debug/communication/DiagramHeader.d.ts +7 -0
- package/dist/components/debug/communication/ParticipantLane.d.ts +7 -0
- package/dist/components/debug/communication/TimeAxis.d.ts +9 -0
- package/dist/components/debug/communication/elements/IdleGap.d.ts +9 -0
- package/dist/components/debug/communication/elements/LLMBlock.d.ts +9 -0
- package/dist/components/debug/communication/elements/MessageArrow.d.ts +10 -0
- package/dist/components/debug/communication/elements/ToolBlock.d.ts +9 -0
- package/dist/components/debug/communication/hooks/useDiagramData.d.ts +12 -0
- package/dist/components/debug/communication/hooks/useTimeCompression.d.ts +7 -0
- package/dist/components/debug/communication/hooks/useZoomPan.d.ts +11 -0
- package/dist/components/debug/communication/popovers/ElementPopover.d.ts +8 -0
- package/dist/components/debug/communication/types.d.ts +136 -0
- package/dist/components/debug/index.d.ts +11 -0
- package/dist/components/debug/pages/AgentDetailPage.d.ts +3 -0
- package/dist/components/debug/pages/AgentsPage.d.ts +1 -0
- package/dist/components/debug/pages/CommunicationPage.d.ts +1 -0
- package/dist/components/debug/pages/DashboardPage.d.ts +1 -0
- package/dist/components/debug/pages/EventsPage.d.ts +1 -0
- package/dist/components/debug/pages/FilesPage.d.ts +1 -0
- package/dist/components/debug/pages/LLMCallPage.d.ts +1 -0
- package/dist/components/debug/pages/LLMCallsPage.d.ts +1 -0
- package/dist/components/debug/pages/LogsPage.d.ts +1 -0
- package/dist/components/debug/pages/MailboxPage.d.ts +1 -0
- package/dist/components/debug/pages/ServicesPage.d.ts +1 -0
- package/dist/components/debug/pages/TimelinePage.d.ts +1 -0
- package/dist/components/debug/pages/UserChatPage.d.ts +1 -0
- package/dist/components/debug/pages/index.d.ts +13 -0
- package/dist/index.d.ts +9 -0
- package/dist/lib/domain-utils.d.ts +7 -0
- package/dist/providers/EventPollingProvider.d.ts +27 -0
- package/dist/stores/event-store.d.ts +93 -0
- package/dist/utils/format.d.ts +1 -0
- package/package.json +43 -0
- package/src/components/debug/DebugContext.tsx +18 -0
- package/src/components/debug/DebugNavigation.tsx +55 -0
- package/src/components/debug/DebugShell.tsx +321 -0
- package/src/components/debug/LLMCallDetail.tsx +740 -0
- package/src/components/debug/TimelineDetailInspector.tsx +204 -0
- package/src/components/debug/communication/CommunicationDiagram.tsx +260 -0
- package/src/components/debug/communication/DiagramHeader.tsx +113 -0
- package/src/components/debug/communication/ParticipantLane.tsx +60 -0
- package/src/components/debug/communication/TimeAxis.tsx +106 -0
- package/src/components/debug/communication/elements/IdleGap.tsx +90 -0
- package/src/components/debug/communication/elements/LLMBlock.tsx +107 -0
- package/src/components/debug/communication/elements/MessageArrow.tsx +119 -0
- package/src/components/debug/communication/elements/ToolBlock.tsx +99 -0
- package/src/components/debug/communication/hooks/useDiagramData.ts +294 -0
- package/src/components/debug/communication/hooks/useTimeCompression.ts +140 -0
- package/src/components/debug/communication/hooks/useZoomPan.ts +87 -0
- package/src/components/debug/communication/popovers/ElementPopover.tsx +158 -0
- package/src/components/debug/communication/types.ts +180 -0
- package/src/components/debug/index.ts +37 -0
- package/src/components/debug/pages/AgentDetailPage.tsx +1295 -0
- package/src/components/debug/pages/AgentsPage.tsx +297 -0
- package/src/components/debug/pages/CommunicationPage.tsx +89 -0
- package/src/components/debug/pages/DashboardPage.tsx +1504 -0
- package/src/components/debug/pages/EventsPage.tsx +276 -0
- package/src/components/debug/pages/FilesPage.tsx +366 -0
- package/src/components/debug/pages/LLMCallPage.tsx +32 -0
- package/src/components/debug/pages/LLMCallsPage.tsx +473 -0
- package/src/components/debug/pages/LogsPage.tsx +199 -0
- package/src/components/debug/pages/MailboxPage.tsx +232 -0
- package/src/components/debug/pages/ServicesPage.tsx +193 -0
- package/src/components/debug/pages/TimelinePage.tsx +569 -0
- package/src/components/debug/pages/UserChatPage.tsx +250 -0
- package/src/components/debug/pages/index.ts +13 -0
- package/src/index.ts +55 -0
- package/src/lib/domain-utils.ts +12 -0
- package/src/providers/EventPollingProvider.tsx +60 -0
- package/src/stores/event-store.ts +497 -0
- package/src/utils/format.ts +8 -0
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unified navigation utilities for debug UI.
|
|
3
|
+
*
|
|
4
|
+
* All navigation goes through DebugContext, which is provided by the host app
|
|
5
|
+
* (admin via buzola, worker SPA via react-router, etc.).
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { SessionId } from '@roj-ai/shared'
|
|
9
|
+
import type { ReactNode } from 'react'
|
|
10
|
+
import { useCallback } from 'react'
|
|
11
|
+
import { useDebugContext } from './DebugContext'
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Get the session ID from the debug context.
|
|
15
|
+
*/
|
|
16
|
+
export function useDebugSessionId(): SessionId {
|
|
17
|
+
return useDebugContext().sessionId
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Get route params from the debug context.
|
|
22
|
+
*/
|
|
23
|
+
export function useDebugParams<T extends Record<string, string | undefined>>(): T {
|
|
24
|
+
return useDebugContext().params as T
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Navigate to a debug subpath (e.g., "agents/abc123", "llm-calls/xyz").
|
|
29
|
+
*/
|
|
30
|
+
export function useDebugNavigate(): (subpath: string) => void {
|
|
31
|
+
const { navigate } = useDebugContext()
|
|
32
|
+
return useCallback((subpath: string) => navigate(subpath), [navigate])
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Link component for debug navigation.
|
|
37
|
+
* Renders an <a> tag with proper href for right-click/open-in-new-tab support.
|
|
38
|
+
*/
|
|
39
|
+
export function DebugLink({ to, className, children }: { to: string; className?: string; children: ReactNode }) {
|
|
40
|
+
const { navigate, createHref } = useDebugContext()
|
|
41
|
+
|
|
42
|
+
return (
|
|
43
|
+
<a
|
|
44
|
+
href={createHref(to)}
|
|
45
|
+
className={className}
|
|
46
|
+
onClick={(e) => {
|
|
47
|
+
if (e.metaKey || e.ctrlKey || e.shiftKey) return
|
|
48
|
+
e.preventDefault()
|
|
49
|
+
navigate(to)
|
|
50
|
+
}}
|
|
51
|
+
>
|
|
52
|
+
{children}
|
|
53
|
+
</a>
|
|
54
|
+
)
|
|
55
|
+
}
|
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
import { type ReactNode, useState } from 'react'
|
|
2
|
+
import { api, unwrap } from '@roj-ai/client'
|
|
3
|
+
import { useEventPolling } from '../../providers/EventPollingProvider'
|
|
4
|
+
import { useEventStore, useMetrics } from '../../stores/event-store'
|
|
5
|
+
|
|
6
|
+
export interface NavItem {
|
|
7
|
+
to: string
|
|
8
|
+
label: string
|
|
9
|
+
icon: React.FC
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export const navItems: NavItem[] = [
|
|
13
|
+
{ to: 'dashboard', label: 'Dashboard', icon: DashboardIcon },
|
|
14
|
+
{ to: 'agents', label: 'Agents', icon: AgentsIcon },
|
|
15
|
+
{ to: 'communication', label: 'Communication', icon: CommunicationIcon },
|
|
16
|
+
{ to: 'user-chat', label: 'User Chat', icon: UserChatIcon },
|
|
17
|
+
{ to: 'timeline', label: 'Timeline', icon: TimelineIcon },
|
|
18
|
+
{ to: 'llm-calls', label: 'LLM Calls', icon: LLMIcon },
|
|
19
|
+
{ to: 'events', label: 'Events', icon: EventsIcon },
|
|
20
|
+
{ to: 'mailbox', label: 'Mailbox', icon: MailboxIcon },
|
|
21
|
+
{ to: 'files', label: 'Files', icon: FilesIcon },
|
|
22
|
+
{ to: 'services', label: 'Services', icon: ServicesIcon },
|
|
23
|
+
{ to: 'logs', label: 'Logs', icon: LogsIcon },
|
|
24
|
+
]
|
|
25
|
+
|
|
26
|
+
interface DebugShellProps {
|
|
27
|
+
sessionId: string
|
|
28
|
+
children: ReactNode
|
|
29
|
+
className?: string
|
|
30
|
+
renderNavItem: (item: NavItem) => ReactNode
|
|
31
|
+
sidebarFooter?: ReactNode
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function DebugShell({ sessionId, children, className = 'fixed inset-0 flex flex-col', renderNavItem, sidebarFooter }: DebugShellProps) {
|
|
35
|
+
const { isLoading } = useEventPolling(sessionId)
|
|
36
|
+
const metrics = useMetrics()
|
|
37
|
+
const hasEvents = useEventStore((s) => s.events.length > 0)
|
|
38
|
+
|
|
39
|
+
return (
|
|
40
|
+
<div className={`${className} bg-surface`}>
|
|
41
|
+
{/* Header */}
|
|
42
|
+
<header className="h-14 bg-white shadow-card flex items-center px-5 shrink-0 z-10">
|
|
43
|
+
<div className="flex items-center gap-3">
|
|
44
|
+
<span className="bg-accent-lime rounded-full px-4 py-1.5 text-sm font-bold text-gray-900">
|
|
45
|
+
Roj
|
|
46
|
+
</span>
|
|
47
|
+
<span className="text-gray-300">/</span>
|
|
48
|
+
<span className="text-sm text-gray-400 font-mono">{sessionId.slice(0, 8)}</span>
|
|
49
|
+
<span className="text-gray-300">/</span>
|
|
50
|
+
<span className="text-sm font-semibold text-gray-700">Debug</span>
|
|
51
|
+
</div>
|
|
52
|
+
|
|
53
|
+
{/* Metrics in header */}
|
|
54
|
+
<div className="ml-auto flex items-center gap-5 text-sm">
|
|
55
|
+
{hasEvents && (
|
|
56
|
+
<>
|
|
57
|
+
{isLoading && <span className="text-gray-400 text-xs animate-pulse">Loading...</span>}
|
|
58
|
+
<MetricBadge label="Tokens" value={metrics.totalTokens.toLocaleString()} />
|
|
59
|
+
<MetricBadge label="LLM" value={metrics.llmCalls.toString()} />
|
|
60
|
+
<MetricBadge label="Tools" value={metrics.toolCalls.toString()} />
|
|
61
|
+
<MetricBadge label="Agents" value={metrics.agentCount.toString()} />
|
|
62
|
+
{metrics.totalCost !== undefined && metrics.totalCost > 0 && (
|
|
63
|
+
<MetricBadge
|
|
64
|
+
label="Cost"
|
|
65
|
+
value={`$${metrics.totalCost.toFixed(4)}`}
|
|
66
|
+
className="text-green-600"
|
|
67
|
+
/>
|
|
68
|
+
)}
|
|
69
|
+
</>
|
|
70
|
+
)}
|
|
71
|
+
<SessionActionButton sessionId={sessionId} />
|
|
72
|
+
</div>
|
|
73
|
+
</header>
|
|
74
|
+
|
|
75
|
+
<div className="flex flex-1 overflow-hidden">
|
|
76
|
+
{/* Sidebar */}
|
|
77
|
+
<nav className="w-52 bg-white shadow-card flex flex-col shrink-0 z-[5]">
|
|
78
|
+
<div className="flex-1 py-3 px-3 space-y-0.5">
|
|
79
|
+
{navItems.map((item) => renderNavItem(item))}
|
|
80
|
+
</div>
|
|
81
|
+
|
|
82
|
+
{sidebarFooter && (
|
|
83
|
+
<div className="p-3 border-t border-gray-100">
|
|
84
|
+
{sidebarFooter}
|
|
85
|
+
</div>
|
|
86
|
+
)}
|
|
87
|
+
</nav>
|
|
88
|
+
|
|
89
|
+
{/* Main content */}
|
|
90
|
+
<main className="flex-1 overflow-auto p-5">
|
|
91
|
+
{children}
|
|
92
|
+
</main>
|
|
93
|
+
</div>
|
|
94
|
+
</div>
|
|
95
|
+
)
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export function getNavItemClassName(isActive: boolean) {
|
|
99
|
+
return `flex items-center gap-3 px-4 py-2.5 text-sm rounded-2xl transition-colors ${
|
|
100
|
+
isActive
|
|
101
|
+
? 'bg-accent-lime text-gray-900 font-semibold'
|
|
102
|
+
: 'text-gray-500 hover:bg-gray-100 hover:text-gray-800'
|
|
103
|
+
}`
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function SessionActionButton({ sessionId }: { sessionId: string }) {
|
|
107
|
+
const [loading, setLoading] = useState(false)
|
|
108
|
+
const status = useEventStore((s) => s.sessionInfoState.id ? s.sessionInfoState.status : null)
|
|
109
|
+
|
|
110
|
+
if (!status) return null
|
|
111
|
+
|
|
112
|
+
const handleAction = async () => {
|
|
113
|
+
if (loading) return
|
|
114
|
+
setLoading(true)
|
|
115
|
+
try {
|
|
116
|
+
if (status === 'active') {
|
|
117
|
+
unwrap(await api.call('sessions.close', { sessionId }))
|
|
118
|
+
} else {
|
|
119
|
+
unwrap(await api.call('sessions.reopen', { sessionId }))
|
|
120
|
+
}
|
|
121
|
+
} catch (e) {
|
|
122
|
+
console.error(`Failed to ${status === 'active' ? 'stop' : 'reopen'} session:`, e)
|
|
123
|
+
} finally {
|
|
124
|
+
setLoading(false)
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if (status === 'active') {
|
|
129
|
+
return (
|
|
130
|
+
<button
|
|
131
|
+
onClick={handleAction}
|
|
132
|
+
disabled={loading}
|
|
133
|
+
className={`px-4 py-1.5 text-xs font-medium rounded-full transition-colors ${
|
|
134
|
+
loading
|
|
135
|
+
? 'bg-red-500 text-white cursor-wait opacity-70'
|
|
136
|
+
: 'bg-gray-900 text-white hover:bg-gray-800'
|
|
137
|
+
}`}
|
|
138
|
+
>
|
|
139
|
+
{loading ? 'Stopping...' : 'Stop Session'}
|
|
140
|
+
</button>
|
|
141
|
+
)
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
return (
|
|
145
|
+
<button
|
|
146
|
+
onClick={handleAction}
|
|
147
|
+
disabled={loading}
|
|
148
|
+
className={`px-4 py-1.5 text-xs font-medium rounded-full transition-colors ${
|
|
149
|
+
loading
|
|
150
|
+
? 'bg-green-500 text-white cursor-wait opacity-70'
|
|
151
|
+
: 'bg-green-600 text-white hover:bg-green-500'
|
|
152
|
+
}`}
|
|
153
|
+
>
|
|
154
|
+
{loading ? 'Reopening...' : 'Reopen Session'}
|
|
155
|
+
</button>
|
|
156
|
+
)
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function MetricBadge({
|
|
160
|
+
label,
|
|
161
|
+
value,
|
|
162
|
+
className,
|
|
163
|
+
}: {
|
|
164
|
+
label: string
|
|
165
|
+
value: string
|
|
166
|
+
className?: string
|
|
167
|
+
}) {
|
|
168
|
+
return (
|
|
169
|
+
<div className="flex items-center gap-1.5">
|
|
170
|
+
<span className="text-gray-400 text-xs">{label}</span>
|
|
171
|
+
<span className={`font-semibold text-sm ${className || 'text-gray-700'}`}>{value}</span>
|
|
172
|
+
</div>
|
|
173
|
+
)
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// Icons — thin-line, rounded endpoints, 1.5px stroke
|
|
177
|
+
function DashboardIcon() {
|
|
178
|
+
return (
|
|
179
|
+
<svg className="w-[18px] h-[18px]" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
180
|
+
<path
|
|
181
|
+
strokeLinecap="round"
|
|
182
|
+
strokeLinejoin="round"
|
|
183
|
+
strokeWidth={1.5}
|
|
184
|
+
d="M4 6a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2-2V6zM14 6a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2V6zM4 16a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2-2v-2zM14 16a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2v-2z"
|
|
185
|
+
/>
|
|
186
|
+
</svg>
|
|
187
|
+
)
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
function AgentsIcon() {
|
|
191
|
+
return (
|
|
192
|
+
<svg className="w-[18px] h-[18px]" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
193
|
+
<path
|
|
194
|
+
strokeLinecap="round"
|
|
195
|
+
strokeLinejoin="round"
|
|
196
|
+
strokeWidth={1.5}
|
|
197
|
+
d="M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0zm6 3a2 2 0 11-4 0 2 2 0 014 0zM7 10a2 2 0 11-4 0 2 2 0 014 0z"
|
|
198
|
+
/>
|
|
199
|
+
</svg>
|
|
200
|
+
)
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
function TimelineIcon() {
|
|
204
|
+
return (
|
|
205
|
+
<svg className="w-[18px] h-[18px]" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
206
|
+
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.5} d="M13 10V3L4 14h7v7l9-11h-7z" />
|
|
207
|
+
</svg>
|
|
208
|
+
)
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
function LLMIcon() {
|
|
212
|
+
return (
|
|
213
|
+
<svg className="w-[18px] h-[18px]" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
214
|
+
<path
|
|
215
|
+
strokeLinecap="round"
|
|
216
|
+
strokeLinejoin="round"
|
|
217
|
+
strokeWidth={1.5}
|
|
218
|
+
d="M9.75 17L9 20l-1 1h8l-1-1-.75-3M3 13h18M5 17h14a2 2 0 002-2V5a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z"
|
|
219
|
+
/>
|
|
220
|
+
</svg>
|
|
221
|
+
)
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
function EventsIcon() {
|
|
225
|
+
return (
|
|
226
|
+
<svg className="w-[18px] h-[18px]" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
227
|
+
<path
|
|
228
|
+
strokeLinecap="round"
|
|
229
|
+
strokeLinejoin="round"
|
|
230
|
+
strokeWidth={1.5}
|
|
231
|
+
d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-3 7h3m-3 4h3m-6-4h.01M9 16h.01"
|
|
232
|
+
/>
|
|
233
|
+
</svg>
|
|
234
|
+
)
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
function MailboxIcon() {
|
|
238
|
+
return (
|
|
239
|
+
<svg className="w-[18px] h-[18px]" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
240
|
+
<path
|
|
241
|
+
strokeLinecap="round"
|
|
242
|
+
strokeLinejoin="round"
|
|
243
|
+
strokeWidth={1.5}
|
|
244
|
+
d="M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z"
|
|
245
|
+
/>
|
|
246
|
+
</svg>
|
|
247
|
+
)
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
function FilesIcon() {
|
|
251
|
+
return (
|
|
252
|
+
<svg className="w-[18px] h-[18px]" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
253
|
+
<path
|
|
254
|
+
strokeLinecap="round"
|
|
255
|
+
strokeLinejoin="round"
|
|
256
|
+
strokeWidth={1.5}
|
|
257
|
+
d="M3 7v10a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-6l-2-2H5a2 2 0 00-2 2z"
|
|
258
|
+
/>
|
|
259
|
+
</svg>
|
|
260
|
+
)
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
function ServicesIcon() {
|
|
264
|
+
return (
|
|
265
|
+
<svg className="w-[18px] h-[18px]" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
266
|
+
<path
|
|
267
|
+
strokeLinecap="round"
|
|
268
|
+
strokeLinejoin="round"
|
|
269
|
+
strokeWidth={1.5}
|
|
270
|
+
d="M5 12h14M5 12a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v4a2 2 0 01-2 2M5 12a2 2 0 00-2 2v4a2 2 0 002 2h14a2 2 0 002-2v-4a2 2 0 00-2-2m-2-4h.01M17 16h.01"
|
|
271
|
+
/>
|
|
272
|
+
</svg>
|
|
273
|
+
)
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
function LogsIcon() {
|
|
277
|
+
return (
|
|
278
|
+
<svg className="w-[18px] h-[18px]" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
279
|
+
<path
|
|
280
|
+
strokeLinecap="round"
|
|
281
|
+
strokeLinejoin="round"
|
|
282
|
+
strokeWidth={1.5}
|
|
283
|
+
d="M4 6h16M4 10h16M4 14h10M4 18h7"
|
|
284
|
+
/>
|
|
285
|
+
</svg>
|
|
286
|
+
)
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
export function BackIcon() {
|
|
290
|
+
return (
|
|
291
|
+
<svg className="w-[18px] h-[18px]" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
292
|
+
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.5} d="M10 19l-7-7m0 0l7-7m-7 7h18" />
|
|
293
|
+
</svg>
|
|
294
|
+
)
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
function CommunicationIcon() {
|
|
298
|
+
return (
|
|
299
|
+
<svg className="w-[18px] h-[18px]" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
300
|
+
<path
|
|
301
|
+
strokeLinecap="round"
|
|
302
|
+
strokeLinejoin="round"
|
|
303
|
+
strokeWidth={1.5}
|
|
304
|
+
d="M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z"
|
|
305
|
+
/>
|
|
306
|
+
</svg>
|
|
307
|
+
)
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
function UserChatIcon() {
|
|
311
|
+
return (
|
|
312
|
+
<svg className="w-[18px] h-[18px]" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
313
|
+
<path
|
|
314
|
+
strokeLinecap="round"
|
|
315
|
+
strokeLinejoin="round"
|
|
316
|
+
strokeWidth={1.5}
|
|
317
|
+
d="M17 8h2a2 2 0 012 2v6a2 2 0 01-2 2h-2v4l-4-4H9a1.994 1.994 0 01-1.414-.586m0 0L11 14h4a2 2 0 002-2V6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2v4l.586-.586z"
|
|
318
|
+
/>
|
|
319
|
+
</svg>
|
|
320
|
+
)
|
|
321
|
+
}
|