@swarmclawai/swarmclaw 0.5.2 → 0.6.0
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/README.md +42 -7
- package/bin/swarmclaw.js +76 -16
- package/next.config.ts +11 -1
- package/package.json +4 -2
- package/public/screenshots/agents.png +0 -0
- package/public/screenshots/dashboard.png +0 -0
- package/public/screenshots/providers.png +0 -0
- package/public/screenshots/tasks.png +0 -0
- package/scripts/postinstall.mjs +18 -0
- package/src/app/api/chatrooms/[id]/chat/route.ts +410 -0
- package/src/app/api/chatrooms/[id]/members/route.ts +82 -0
- package/src/app/api/chatrooms/[id]/pins/route.ts +39 -0
- package/src/app/api/chatrooms/[id]/reactions/route.ts +42 -0
- package/src/app/api/chatrooms/[id]/route.ts +84 -0
- package/src/app/api/chatrooms/route.ts +50 -0
- package/src/app/api/credentials/route.ts +2 -3
- package/src/app/api/knowledge/[id]/route.ts +13 -2
- package/src/app/api/knowledge/route.ts +8 -1
- package/src/app/api/memory/route.ts +8 -0
- package/src/app/api/notifications/[id]/route.ts +27 -0
- package/src/app/api/notifications/route.ts +68 -0
- package/src/app/api/orchestrator/run/route.ts +1 -1
- package/src/app/api/plugins/install/route.ts +2 -2
- package/src/app/api/search/route.ts +155 -0
- package/src/app/api/sessions/[id]/chat/route.ts +2 -0
- package/src/app/api/sessions/[id]/edit-resend/route.ts +1 -1
- package/src/app/api/sessions/[id]/fork/route.ts +1 -1
- package/src/app/api/sessions/route.ts +3 -3
- package/src/app/api/settings/route.ts +9 -0
- package/src/app/api/setup/check-provider/route.ts +3 -16
- package/src/app/api/skills/[id]/route.ts +6 -0
- package/src/app/api/skills/route.ts +6 -0
- package/src/app/api/tasks/[id]/route.ts +20 -0
- package/src/app/api/tasks/bulk/route.ts +100 -0
- package/src/app/api/tasks/route.ts +1 -0
- package/src/app/api/usage/route.ts +45 -0
- package/src/app/api/webhooks/[id]/route.ts +15 -1
- package/src/app/globals.css +58 -15
- package/src/app/page.tsx +142 -13
- package/src/cli/index.js +42 -0
- package/src/cli/index.test.js +30 -0
- package/src/cli/spec.js +32 -0
- package/src/components/agents/agent-avatar.tsx +57 -10
- package/src/components/agents/agent-card.tsx +48 -15
- package/src/components/agents/agent-chat-list.tsx +123 -10
- package/src/components/agents/agent-list.tsx +50 -19
- package/src/components/agents/agent-sheet.tsx +56 -63
- package/src/components/auth/access-key-gate.tsx +10 -3
- package/src/components/auth/setup-wizard.tsx +2 -2
- package/src/components/auth/user-picker.tsx +31 -3
- package/src/components/chat/activity-moment.tsx +169 -0
- package/src/components/chat/chat-header.tsx +2 -0
- package/src/components/chat/chat-tool-toggles.tsx +1 -1
- package/src/components/chat/file-path-chip.tsx +125 -0
- package/src/components/chat/markdown-utils.ts +9 -0
- package/src/components/chat/message-bubble.tsx +46 -295
- package/src/components/chat/message-list.tsx +50 -1
- package/src/components/chat/streaming-bubble.tsx +36 -46
- package/src/components/chat/suggestions-bar.tsx +1 -1
- package/src/components/chat/thinking-indicator.tsx +72 -10
- package/src/components/chat/tool-call-bubble.tsx +66 -70
- package/src/components/chat/tool-request-banner.tsx +31 -7
- package/src/components/chat/transfer-agent-picker.tsx +63 -0
- package/src/components/chatrooms/agent-hover-card.tsx +124 -0
- package/src/components/chatrooms/chatroom-input.tsx +320 -0
- package/src/components/chatrooms/chatroom-list.tsx +123 -0
- package/src/components/chatrooms/chatroom-message.tsx +427 -0
- package/src/components/chatrooms/chatroom-sheet.tsx +215 -0
- package/src/components/chatrooms/chatroom-tool-request-banner.tsx +134 -0
- package/src/components/chatrooms/chatroom-typing-bar.tsx +88 -0
- package/src/components/chatrooms/chatroom-view.tsx +344 -0
- package/src/components/chatrooms/reaction-picker.tsx +273 -0
- package/src/components/connectors/connector-sheet.tsx +34 -47
- package/src/components/home/home-view.tsx +501 -0
- package/src/components/input/chat-input.tsx +79 -41
- package/src/components/knowledge/knowledge-list.tsx +31 -1
- package/src/components/knowledge/knowledge-sheet.tsx +83 -2
- package/src/components/layout/app-layout.tsx +209 -83
- package/src/components/layout/mobile-header.tsx +2 -0
- package/src/components/layout/update-banner.tsx +2 -2
- package/src/components/logs/log-list.tsx +2 -2
- package/src/components/mcp-servers/mcp-server-sheet.tsx +1 -1
- package/src/components/memory/memory-agent-list.tsx +143 -0
- package/src/components/memory/memory-browser.tsx +205 -0
- package/src/components/memory/memory-card.tsx +34 -7
- package/src/components/memory/memory-detail.tsx +359 -120
- package/src/components/memory/memory-sheet.tsx +157 -23
- package/src/components/plugins/plugin-list.tsx +1 -1
- package/src/components/plugins/plugin-sheet.tsx +1 -1
- package/src/components/projects/project-detail.tsx +509 -0
- package/src/components/projects/project-list.tsx +195 -59
- package/src/components/providers/provider-list.tsx +2 -2
- package/src/components/providers/provider-sheet.tsx +3 -3
- package/src/components/schedules/schedule-card.tsx +3 -2
- package/src/components/schedules/schedule-list.tsx +1 -1
- package/src/components/schedules/schedule-sheet.tsx +25 -25
- package/src/components/secrets/secret-sheet.tsx +47 -24
- package/src/components/secrets/secrets-list.tsx +18 -8
- package/src/components/sessions/new-session-sheet.tsx +33 -65
- package/src/components/sessions/session-card.tsx +45 -14
- package/src/components/sessions/session-list.tsx +35 -18
- package/src/components/shared/agent-picker-list.tsx +90 -0
- package/src/components/shared/agent-switch-dialog.tsx +156 -0
- package/src/components/shared/attachment-chip.tsx +165 -0
- package/src/components/shared/avatar.tsx +10 -1
- package/src/components/shared/check-icon.tsx +12 -0
- package/src/components/shared/confirm-dialog.tsx +1 -1
- package/src/components/shared/empty-state.tsx +32 -0
- package/src/components/shared/file-preview.tsx +34 -0
- package/src/components/shared/form-styles.ts +2 -0
- package/src/components/shared/keyboard-shortcuts-dialog.tsx +116 -0
- package/src/components/shared/notification-center.tsx +223 -0
- package/src/components/shared/profile-sheet.tsx +115 -0
- package/src/components/shared/reply-quote.tsx +26 -0
- package/src/components/shared/search-dialog.tsx +296 -0
- package/src/components/shared/section-label.tsx +12 -0
- package/src/components/shared/settings/plugin-manager.tsx +1 -1
- package/src/components/shared/settings/section-providers.tsx +1 -1
- package/src/components/shared/settings/section-secrets.tsx +1 -1
- package/src/components/shared/settings/section-theme.tsx +95 -0
- package/src/components/shared/settings/section-user-preferences.tsx +39 -0
- package/src/components/shared/settings/settings-page.tsx +180 -27
- package/src/components/shared/settings/settings-sheet.tsx +9 -73
- package/src/components/shared/sheet-footer.tsx +33 -0
- package/src/components/skills/skill-list.tsx +61 -30
- package/src/components/skills/skill-sheet.tsx +81 -2
- package/src/components/tasks/task-board.tsx +448 -26
- package/src/components/tasks/task-card.tsx +46 -9
- package/src/components/tasks/task-column.tsx +62 -3
- package/src/components/tasks/task-list.tsx +12 -4
- package/src/components/tasks/task-sheet.tsx +89 -72
- package/src/components/ui/hover-card.tsx +52 -0
- package/src/components/usage/metrics-dashboard.tsx +78 -0
- package/src/components/usage/usage-list.tsx +1 -1
- package/src/components/webhooks/webhook-sheet.tsx +1 -1
- package/src/hooks/use-view-router.ts +69 -19
- package/src/instrumentation.ts +15 -1
- package/src/lib/chat.ts +2 -0
- package/src/lib/cron-human.ts +114 -0
- package/src/lib/memory.ts +3 -0
- package/src/lib/server/chat-execution.ts +24 -4
- package/src/lib/server/connectors/manager.ts +11 -0
- package/src/lib/server/context-manager.ts +225 -13
- package/src/lib/server/create-notification.ts +42 -0
- package/src/lib/server/daemon-state.ts +165 -10
- package/src/lib/server/execution-log.ts +1 -0
- package/src/lib/server/heartbeat-service.ts +40 -5
- package/src/lib/server/heartbeat-wake.ts +110 -0
- package/src/lib/server/langgraph-checkpoint.ts +1 -0
- package/src/lib/server/memory-consolidation.ts +92 -0
- package/src/lib/server/memory-db.ts +51 -6
- package/src/lib/server/openclaw-gateway.ts +9 -1
- package/src/lib/server/provider-health.ts +125 -0
- package/src/lib/server/queue.ts +5 -4
- package/src/lib/server/scheduler.ts +8 -0
- package/src/lib/server/session-run-manager.ts +4 -0
- package/src/lib/server/session-tools/chatroom.ts +136 -0
- package/src/lib/server/session-tools/context-mgmt.ts +36 -18
- package/src/lib/server/session-tools/index.ts +2 -0
- package/src/lib/server/session-tools/memory.ts +6 -1
- package/src/lib/server/storage.ts +80 -29
- package/src/lib/server/stream-agent-chat.ts +153 -47
- package/src/lib/server/system-events.ts +49 -0
- package/src/lib/server/ws-hub.ts +11 -0
- package/src/lib/soul-suggestions.ts +109 -0
- package/src/lib/tasks.ts +4 -1
- package/src/lib/view-routes.ts +36 -1
- package/src/lib/ws-client.ts +14 -4
- package/src/proxy.ts +79 -2
- package/src/stores/use-app-store.ts +94 -3
- package/src/stores/use-chat-store.ts +48 -3
- package/src/stores/use-chatroom-store.ts +276 -0
- package/src/types/index.ts +69 -2
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import { useState, useEffect, useRef, useMemo } from 'react'
|
|
4
|
+
|
|
5
|
+
const CATEGORIES: Array<{ id: string; label: string; icon: string; emojis: string[] }> = [
|
|
6
|
+
{
|
|
7
|
+
id: 'frequent',
|
|
8
|
+
label: 'Frequently Used',
|
|
9
|
+
icon: '🕐',
|
|
10
|
+
emojis: ['👍', '❤️', '😂', '🔥', '🎉', '👀', '🚀', '✅', '💯', '🤔'],
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
id: 'smileys',
|
|
14
|
+
label: 'Smileys & People',
|
|
15
|
+
icon: '😀',
|
|
16
|
+
emojis: [
|
|
17
|
+
'😀', '😃', '😄', '😁', '😆', '😅', '🤣', '😂', '🙂', '😊',
|
|
18
|
+
'😇', '🥰', '😍', '🤩', '😘', '😗', '😚', '😙', '🥲', '😋',
|
|
19
|
+
'😛', '😜', '🤪', '😝', '🤑', '🤗', '🤭', '🫢', '🤫', '🤔',
|
|
20
|
+
'🫡', '🤐', '🤨', '😐', '😑', '😶', '🫥', '😏', '😒', '🙄',
|
|
21
|
+
'😬', '🤥', '🫨', '😌', '😔', '😪', '🤤', '😴', '😷', '🤒',
|
|
22
|
+
'🤕', '🤢', '🤮', '🥴', '😵', '🤯', '🥳', '🥸', '😎', '🤓',
|
|
23
|
+
'🧐', '😕', '🫤', '😟', '🙁', '😮', '😯', '😲', '😳', '🥺',
|
|
24
|
+
'🥹', '😦', '😧', '😨', '😰', '😥', '😢', '😭', '😱', '😖',
|
|
25
|
+
'😣', '😞', '😓', '😩', '😫', '🥱', '😤', '😡', '😠', '🤬',
|
|
26
|
+
'😈', '👿', '💀', '☠️', '💩', '🤡', '👹', '👺', '👻', '👽',
|
|
27
|
+
'🤖', '😺', '😸', '😹', '😻', '😼', '😽', '🙀', '😿', '😾',
|
|
28
|
+
'🙈', '🙉', '🙊', '👋', '🤚', '🖐️', '✋', '🖖', '🫱', '🫲',
|
|
29
|
+
'🫳', '🫴', '👌', '🤌', '🤏', '✌️', '🤞', '🫰', '🤟', '🤘',
|
|
30
|
+
'🤙', '👈', '👉', '👆', '🖕', '👇', '☝️', '🫵', '👍', '👎',
|
|
31
|
+
'✊', '👊', '🤛', '🤜', '👏', '🙌', '🫶', '👐', '🤲', '🤝',
|
|
32
|
+
'🙏', '✍️', '💪', '🦾', '🧠', '👀', '👁️', '👅', '👄', '🫦',
|
|
33
|
+
],
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
id: 'nature',
|
|
37
|
+
label: 'Animals & Nature',
|
|
38
|
+
icon: '🐶',
|
|
39
|
+
emojis: [
|
|
40
|
+
'🐶', '🐱', '🐭', '🐹', '🐰', '🦊', '🐻', '🐼', '🐻❄️', '🐨',
|
|
41
|
+
'🐯', '🦁', '🐮', '🐷', '🐸', '🐵', '🐔', '🐧', '🐦', '🐤',
|
|
42
|
+
'🦆', '🦅', '🦉', '🦇', '🐺', '🐗', '🐴', '🦄', '🐝', '🪱',
|
|
43
|
+
'🐛', '🦋', '🐌', '🐞', '🐜', '🪲', '🪳', '🕷️', '🦂', '🐢',
|
|
44
|
+
'🐍', '🦎', '🐙', '🦑', '🦐', '🦞', '🦀', '🐡', '🐠', '🐟',
|
|
45
|
+
'🐬', '🐳', '🐋', '🦈', '🪸', '🐊', '🐅', '🐆', '🦓', '🦍',
|
|
46
|
+
'🐘', '🦛', '🦏', '🐪', '🐫', '🦒', '🦘', '🦬', '🐃', '🐂',
|
|
47
|
+
'🐄', '🐎', '🐖', '🐏', '🐑', '🦙', '🐐', '🦌', '🐕', '🐩',
|
|
48
|
+
'🌵', '🎄', '🌲', '🌳', '🌴', '🪵', '🌱', '🌿', '☘️', '🍀',
|
|
49
|
+
'🍁', '🍂', '🍃', '🪹', '🪺', '🌺', '🌻', '🌹', '🥀', '🌷',
|
|
50
|
+
'🌼', '🌸', '💐', '🍄', '🌰', '🎃', '🌍', '🌙', '⭐', '🌟',
|
|
51
|
+
'💫', '✨', '⚡', '☀️', '🌤️', '🌈', '☁️', '🌧️', '❄️', '🔥',
|
|
52
|
+
],
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
id: 'food',
|
|
56
|
+
label: 'Food & Drink',
|
|
57
|
+
icon: '🍕',
|
|
58
|
+
emojis: [
|
|
59
|
+
'🍎', '🍐', '🍊', '🍋', '🍌', '🍉', '🍇', '🍓', '🫐', '🍈',
|
|
60
|
+
'🍒', '🍑', '🥭', '🍍', '🥥', '🥝', '🍅', '🥑', '🍆', '🥦',
|
|
61
|
+
'🥬', '🥒', '🌶️', '🫑', '🌽', '🥕', '🧄', '🧅', '🥔', '🍠',
|
|
62
|
+
'🥐', '🍞', '🥖', '🥨', '🧀', '🥚', '🍳', '🥞', '🧇', '🥓',
|
|
63
|
+
'🥩', '🍗', '🍖', '🌭', '🍔', '🍟', '🍕', '🫓', '🥪', '🥙',
|
|
64
|
+
'🧆', '🌮', '🌯', '🫔', '🥗', '🍝', '🍜', '🍲', '🍛', '🍣',
|
|
65
|
+
'🍱', '🥟', '🍤', '🍙', '🍚', '🍘', '🍥', '🥠', '🥮', '🍡',
|
|
66
|
+
'🍧', '🍨', '🍦', '🥧', '🧁', '🍰', '🎂', '🍮', '🍭', '🍬',
|
|
67
|
+
'🍫', '🍿', '🧈', '🥤', '☕', '🍵', '🧃', '🧉', '🍶', '🍺',
|
|
68
|
+
'🍻', '🥂', '🍷', '🍸', '🍹', '🍾', '🧊', '🥄', '🍴', '🥢',
|
|
69
|
+
],
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
id: 'activity',
|
|
73
|
+
label: 'Activities',
|
|
74
|
+
icon: '⚽',
|
|
75
|
+
emojis: [
|
|
76
|
+
'⚽', '🏀', '🏈', '⚾', '🥎', '🎾', '🏐', '🏉', '🥏', '🎱',
|
|
77
|
+
'🏓', '🏸', '🏒', '🥊', '🥋', '🥅', '⛳', '⛸️', '🎣', '🤿',
|
|
78
|
+
'🎿', '🛷', '🥌', '🎯', '🪀', '🪁', '🎮', '🕹️', '🎰', '🧩',
|
|
79
|
+
'♟️', '🎲', '🎭', '🎨', '🎬', '🎤', '🎧', '🎼', '🎹', '🥁',
|
|
80
|
+
'🎷', '🎺', '🪗', '🎸', '🎻', '🎪', '🎫', '🎟️', '🏆', '🥇',
|
|
81
|
+
'🥈', '🥉', '🏅', '🎖️', '🏵️', '🎗️', '🎁', '🎀', '🎈', '🎊',
|
|
82
|
+
],
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
id: 'travel',
|
|
86
|
+
label: 'Travel & Places',
|
|
87
|
+
icon: '✈️',
|
|
88
|
+
emojis: [
|
|
89
|
+
'🚗', '🚕', '🚙', '🚌', '🚎', '🏎️', '🚓', '🚑', '🚒', '🚐',
|
|
90
|
+
'🛻', '🚚', '🚛', '🚜', '🏍️', '🛵', '🚲', '🛴', '🛺', '🚔',
|
|
91
|
+
'🚍', '🚘', '🚖', '✈️', '🚀', '🛸', '🚁', '🛶', '⛵', '🚢',
|
|
92
|
+
'🏠', '🏡', '🏘️', '🏢', '🏣', '🏥', '🏦', '🏪', '🏫', '🏩',
|
|
93
|
+
'💒', '🏛️', '⛪', '🕌', '🛕', '🕍', '⛩️', '🏰', '🏯', '🗼',
|
|
94
|
+
'🗽', '🗿', '🏟️', '🎡', '🎢', '🎠', '⛲', '⛱️', '🏖️', '🏝️',
|
|
95
|
+
'🏔️', '🗻', '🌋', '🏕️', '🛤️', '🛣️', '🌅', '🌄', '🌃', '🌉',
|
|
96
|
+
],
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
id: 'objects',
|
|
100
|
+
label: 'Objects',
|
|
101
|
+
icon: '💡',
|
|
102
|
+
emojis: [
|
|
103
|
+
'⌚', '📱', '💻', '⌨️', '🖥️', '🖨️', '🖱️', '🖲️', '💽', '💾',
|
|
104
|
+
'💿', '📀', '🎥', '📷', '📸', '📹', '📼', '🔍', '🔎', '🕯️',
|
|
105
|
+
'💡', '🔦', '🏮', '🪔', '📔', '📕', '📖', '📗', '📘', '📙',
|
|
106
|
+
'📚', '📓', '📒', '📃', '📜', '📄', '📰', '📑', '🔖', '💰',
|
|
107
|
+
'🪙', '💴', '💵', '💶', '💷', '💸', '💳', '✉️', '📧', '📨',
|
|
108
|
+
'📩', '📤', '📥', '📦', '📫', '📪', '📬', '📭', '📮', '🗳️',
|
|
109
|
+
'✏️', '✒️', '🖋️', '🖊️', '🖌️', '🖍️', '📝', '📁', '📂', '🗂️',
|
|
110
|
+
'📅', '📆', '📇', '📈', '📉', '📊', '📋', '📌', '📍', '📎',
|
|
111
|
+
'🔐', '🔑', '🗝️', '🔨', '🪓', '⛏️', '⚒️', '🛠️', '🗡️', '⚔️',
|
|
112
|
+
'🔧', '🪛', '🔩', '⚙️', '🗜️', '⚖️', '🦯', '🔗', '⛓️', '🪝',
|
|
113
|
+
],
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
id: 'symbols',
|
|
117
|
+
label: 'Symbols',
|
|
118
|
+
icon: '❤️',
|
|
119
|
+
emojis: [
|
|
120
|
+
'❤️', '🧡', '💛', '💚', '💙', '💜', '🖤', '🤍', '🤎', '💔',
|
|
121
|
+
'❤️🔥', '❤️🩹', '❣️', '💕', '💞', '💓', '💗', '💖', '💘', '💝',
|
|
122
|
+
'💟', '☮️', '✝️', '☪️', '🕉️', '☸️', '✡️', '🔯', '🕎', '☯️',
|
|
123
|
+
'♈', '♉', '♊', '♋', '♌', '♍', '♎', '♏', '♐', '♑',
|
|
124
|
+
'♒', '♓', '⛎', '🔀', '🔁', '🔂', '▶️', '⏩', '⏭️', '⏯️',
|
|
125
|
+
'◀️', '⏪', '⏮️', '🔼', '⏫', '🔽', '⏬', '⏸️', '⏹️', '⏺️',
|
|
126
|
+
'⏏️', '🎦', '🔅', '🔆', '📶', '🛜', '📳', '📴', '♀️', '♂️',
|
|
127
|
+
'⚧️', '✖️', '➕', '➖', '➗', '🟰', '♾️', '‼️', '⁉️', '❓',
|
|
128
|
+
'❔', '❕', '❗', '〰️', '💱', '💲', '⚕️', '♻️', '⚜️', '🔱',
|
|
129
|
+
'✔️', '☑️', '✅', '❌', '❎', '➰', '➿', '〽️', '✳️', '✴️',
|
|
130
|
+
'❇️', '©️', '®️', '™️', '#️⃣', '*️⃣', '0️⃣', '1️⃣', '2️⃣', '3️⃣',
|
|
131
|
+
'🔴', '🟠', '🟡', '🟢', '🔵', '🟣', '⚫', '⚪', '🟤', '🔶',
|
|
132
|
+
'🔷', '🔸', '🔹', '🔺', '🔻', '💠', '🔘', '🔳', '🔲', '🏁',
|
|
133
|
+
'🚩', '🎌', '🏴', '🏳️', '🏳️🌈', '🏳️⚧️', '🏴☠️', '🇺🇸', '🇬🇧', '🇯🇵',
|
|
134
|
+
],
|
|
135
|
+
},
|
|
136
|
+
]
|
|
137
|
+
|
|
138
|
+
interface Props {
|
|
139
|
+
onSelect: (emoji: string) => void
|
|
140
|
+
onClose: () => void
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
export function ReactionPicker({ onSelect, onClose }: Props) {
|
|
144
|
+
const ref = useRef<HTMLDivElement>(null)
|
|
145
|
+
const searchRef = useRef<HTMLInputElement>(null)
|
|
146
|
+
const [search, setSearch] = useState('')
|
|
147
|
+
const [activeCategory, setActiveCategory] = useState('frequent')
|
|
148
|
+
|
|
149
|
+
useEffect(() => {
|
|
150
|
+
const handler = (e: MouseEvent) => {
|
|
151
|
+
if (ref.current && !ref.current.contains(e.target as Node)) {
|
|
152
|
+
onClose()
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
document.addEventListener('mousedown', handler)
|
|
156
|
+
return () => document.removeEventListener('mousedown', handler)
|
|
157
|
+
}, [onClose])
|
|
158
|
+
|
|
159
|
+
// Auto-focus search on open
|
|
160
|
+
useEffect(() => {
|
|
161
|
+
setTimeout(() => searchRef.current?.focus(), 50)
|
|
162
|
+
}, [])
|
|
163
|
+
|
|
164
|
+
const filteredEmojis = useMemo(() => {
|
|
165
|
+
if (!search.trim()) return null
|
|
166
|
+
const q = search.toLowerCase()
|
|
167
|
+
// Simple search: match against category names or just return all emojis that are visible
|
|
168
|
+
const results: string[] = []
|
|
169
|
+
const seen = new Set<string>()
|
|
170
|
+
for (const cat of CATEGORIES) {
|
|
171
|
+
if (cat.id === 'frequent') continue
|
|
172
|
+
for (const emoji of cat.emojis) {
|
|
173
|
+
if (!seen.has(emoji)) {
|
|
174
|
+
seen.add(emoji)
|
|
175
|
+
results.push(emoji)
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
// For basic emoji search, filter by category label matching
|
|
180
|
+
// Since emoji don't have text names in this simple implementation,
|
|
181
|
+
// we filter categories that match and show all their emojis
|
|
182
|
+
const matchingCats = CATEGORIES.filter(
|
|
183
|
+
(c) => c.id !== 'frequent' && c.label.toLowerCase().includes(q)
|
|
184
|
+
)
|
|
185
|
+
if (matchingCats.length > 0) {
|
|
186
|
+
const catResults: string[] = []
|
|
187
|
+
const catSeen = new Set<string>()
|
|
188
|
+
for (const cat of matchingCats) {
|
|
189
|
+
for (const emoji of cat.emojis) {
|
|
190
|
+
if (!catSeen.has(emoji)) {
|
|
191
|
+
catSeen.add(emoji)
|
|
192
|
+
catResults.push(emoji)
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
return catResults
|
|
197
|
+
}
|
|
198
|
+
// If no category match, just return all emojis (user can visually scan)
|
|
199
|
+
return results
|
|
200
|
+
}, [search])
|
|
201
|
+
|
|
202
|
+
return (
|
|
203
|
+
<div
|
|
204
|
+
ref={ref}
|
|
205
|
+
className="absolute right-0 bottom-8 z-50 bg-[#13131e] border border-white/[0.1] rounded-[12px] shadow-[0_8px_40px_rgba(0,0,0,0.6)] w-[320px] flex flex-col overflow-hidden"
|
|
206
|
+
style={{ animation: 'msg-in 0.15s ease-out both' }}
|
|
207
|
+
>
|
|
208
|
+
{/* Search */}
|
|
209
|
+
<div className="px-3 pt-3 pb-2">
|
|
210
|
+
<input
|
|
211
|
+
ref={searchRef}
|
|
212
|
+
type="text"
|
|
213
|
+
value={search}
|
|
214
|
+
onChange={(e) => setSearch(e.target.value)}
|
|
215
|
+
placeholder="Search emoji..."
|
|
216
|
+
className="w-full px-2.5 py-1.5 rounded-[8px] bg-white/[0.06] border border-white/[0.08] text-[12px] text-text placeholder:text-text-3 focus:outline-none focus:border-accent-bright/40"
|
|
217
|
+
/>
|
|
218
|
+
</div>
|
|
219
|
+
|
|
220
|
+
{/* Category tabs */}
|
|
221
|
+
{!search.trim() && (
|
|
222
|
+
<div className="flex px-2 gap-0.5 pb-1">
|
|
223
|
+
{CATEGORIES.map((cat) => (
|
|
224
|
+
<button
|
|
225
|
+
key={cat.id}
|
|
226
|
+
onClick={() => setActiveCategory(cat.id)}
|
|
227
|
+
title={cat.label}
|
|
228
|
+
className={`flex-1 py-1 flex items-center justify-center rounded-[6px] text-[14px] cursor-pointer transition-all ${
|
|
229
|
+
activeCategory === cat.id ? 'bg-white/[0.08]' : 'hover:bg-white/[0.04]'
|
|
230
|
+
}`}
|
|
231
|
+
>
|
|
232
|
+
{cat.icon}
|
|
233
|
+
</button>
|
|
234
|
+
))}
|
|
235
|
+
</div>
|
|
236
|
+
)}
|
|
237
|
+
|
|
238
|
+
{/* Emoji grid */}
|
|
239
|
+
<div className="px-2 pb-2 max-h-[220px] overflow-y-auto">
|
|
240
|
+
{search.trim() ? (
|
|
241
|
+
<div className="grid grid-cols-8 gap-0.5">
|
|
242
|
+
{filteredEmojis?.map((emoji, i) => (
|
|
243
|
+
<button
|
|
244
|
+
key={`${emoji}-${i}`}
|
|
245
|
+
onClick={() => onSelect(emoji)}
|
|
246
|
+
className="w-[34px] h-[34px] flex items-center justify-center rounded-[6px] hover:bg-white/[0.08] transition-all cursor-pointer text-[18px]"
|
|
247
|
+
>
|
|
248
|
+
{emoji}
|
|
249
|
+
</button>
|
|
250
|
+
))}
|
|
251
|
+
</div>
|
|
252
|
+
) : (
|
|
253
|
+
CATEGORIES.filter((c) => c.id === activeCategory).map((cat) => (
|
|
254
|
+
<div key={cat.id}>
|
|
255
|
+
<div className="text-[10px] font-600 text-text-3 uppercase tracking-wider px-1 py-1.5">{cat.label}</div>
|
|
256
|
+
<div className="grid grid-cols-8 gap-0.5">
|
|
257
|
+
{cat.emojis.map((emoji, i) => (
|
|
258
|
+
<button
|
|
259
|
+
key={`${emoji}-${i}`}
|
|
260
|
+
onClick={() => onSelect(emoji)}
|
|
261
|
+
className="w-[34px] h-[34px] flex items-center justify-center rounded-[6px] hover:bg-white/[0.08] transition-all cursor-pointer text-[18px]"
|
|
262
|
+
>
|
|
263
|
+
{emoji}
|
|
264
|
+
</button>
|
|
265
|
+
))}
|
|
266
|
+
</div>
|
|
267
|
+
</div>
|
|
268
|
+
))
|
|
269
|
+
)}
|
|
270
|
+
</div>
|
|
271
|
+
</div>
|
|
272
|
+
)
|
|
273
|
+
}
|
|
@@ -8,6 +8,9 @@ import { useWs } from '@/hooks/use-ws'
|
|
|
8
8
|
import { toast } from 'sonner'
|
|
9
9
|
import type { Connector, ConnectorPlatform } from '@/types'
|
|
10
10
|
import { ConnectorPlatformBadge } from '@/components/shared/connector-platform-icon'
|
|
11
|
+
import { AgentPickerList } from '@/components/shared/agent-picker-list'
|
|
12
|
+
import { SheetFooter } from '@/components/shared/sheet-footer'
|
|
13
|
+
import { SectionLabel } from '@/components/shared/section-label'
|
|
11
14
|
|
|
12
15
|
/** Auto-detect URLs in text and make them clickable links that open in a new tab */
|
|
13
16
|
function linkify(text: string) {
|
|
@@ -283,10 +286,10 @@ export function ConnectorSheet() {
|
|
|
283
286
|
const pollWaStatus = useCallback(async () => {
|
|
284
287
|
if (!editing) return
|
|
285
288
|
try {
|
|
286
|
-
const data = await api<
|
|
287
|
-
setQrDataUrl(data.qrDataUrl || null)
|
|
288
|
-
setWaAuthenticated(data.authenticated ?? false)
|
|
289
|
-
setWaHasCreds(data.hasCredentials ?? false)
|
|
289
|
+
const data = await api<Record<string, unknown>>('GET', `/connectors/${editing.id}`)
|
|
290
|
+
setQrDataUrl((data.qrDataUrl as string | null) || null)
|
|
291
|
+
setWaAuthenticated((data.authenticated as boolean) ?? false)
|
|
292
|
+
setWaHasCreds((data.hasCredentials as boolean) ?? false)
|
|
290
293
|
if (data.status === 'running' && editing.status !== 'running') {
|
|
291
294
|
const store = useAppStore.getState()
|
|
292
295
|
const updated = { ...store.connectors }
|
|
@@ -316,8 +319,8 @@ export function ConnectorSheet() {
|
|
|
316
319
|
await loadConnectors()
|
|
317
320
|
setOpen(false)
|
|
318
321
|
setEditingId(null)
|
|
319
|
-
} catch (err:
|
|
320
|
-
toast.error(err.message)
|
|
322
|
+
} catch (err: unknown) {
|
|
323
|
+
toast.error(err instanceof Error ? err.message : String(err))
|
|
321
324
|
} finally {
|
|
322
325
|
setSaving(false)
|
|
323
326
|
}
|
|
@@ -340,9 +343,9 @@ export function ConnectorSheet() {
|
|
|
340
343
|
setQrDataUrl(null)
|
|
341
344
|
}
|
|
342
345
|
await loadConnectors()
|
|
343
|
-
} catch (err:
|
|
346
|
+
} catch (err: unknown) {
|
|
344
347
|
setWaConnecting(false)
|
|
345
|
-
toast.error(`Failed to ${action}: ${err.message}`)
|
|
348
|
+
toast.error(`Failed to ${action}: ${err instanceof Error ? err.message : String(err)}`)
|
|
346
349
|
} finally {
|
|
347
350
|
setActionLoading(false)
|
|
348
351
|
}
|
|
@@ -357,7 +360,7 @@ export function ConnectorSheet() {
|
|
|
357
360
|
}
|
|
358
361
|
|
|
359
362
|
const platformConfig = PLATFORMS.find((p) => p.id === platform)!
|
|
360
|
-
const agentList = Object.values(agents)
|
|
363
|
+
const agentList = Object.values(agents).sort((a, b) => a.name.localeCompare(b.name))
|
|
361
364
|
const credList = Object.values(credentials)
|
|
362
365
|
|
|
363
366
|
const inputClass = "w-full px-4 py-3 rounded-[12px] border border-white/[0.08] bg-surface text-text text-[14px] outline-none transition-all placeholder:text-text-3/50 focus:border-white/[0.15]"
|
|
@@ -374,7 +377,7 @@ export function ConnectorSheet() {
|
|
|
374
377
|
{/* Platform selector (only for new) */}
|
|
375
378
|
{!editing && (
|
|
376
379
|
<div className="mb-8">
|
|
377
|
-
<
|
|
380
|
+
<SectionLabel>Platform</SectionLabel>
|
|
378
381
|
<div className="grid grid-cols-2 gap-3">
|
|
379
382
|
{PLATFORMS.map((p) => (
|
|
380
383
|
<button
|
|
@@ -460,17 +463,12 @@ export function ConnectorSheet() {
|
|
|
460
463
|
<div className="mb-6">
|
|
461
464
|
<label className="block font-display text-[12px] font-600 text-text-2 uppercase tracking-[0.08em] mb-2">Route to Agent</label>
|
|
462
465
|
<p className="text-[12px] text-text-3/60 mb-2">Incoming messages will be handled by this agent</p>
|
|
463
|
-
<
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
<option value="">Select a agent...</option>
|
|
470
|
-
{agentList.map((p: any) => (
|
|
471
|
-
<option key={p.id} value={p.id}>{p.name}{p.isOrchestrator ? ' (Orchestrator)' : ''}</option>
|
|
472
|
-
))}
|
|
473
|
-
</select>
|
|
466
|
+
<AgentPickerList
|
|
467
|
+
agents={agentList}
|
|
468
|
+
selected={agentId}
|
|
469
|
+
onSelect={(id) => setAgentId(id)}
|
|
470
|
+
showOrchBadge={true}
|
|
471
|
+
/>
|
|
474
472
|
</div>
|
|
475
473
|
|
|
476
474
|
{/* Bot token credential */}
|
|
@@ -495,7 +493,7 @@ export function ConnectorSheet() {
|
|
|
495
493
|
style={{ fontFamily: 'inherit' }}
|
|
496
494
|
>
|
|
497
495
|
<option value="">Select credential...</option>
|
|
498
|
-
{credList.map((c
|
|
496
|
+
{credList.map((c) => (
|
|
499
497
|
<option key={c.id} value={c.id}>{c.name} ({c.provider})</option>
|
|
500
498
|
))}
|
|
501
499
|
<option value="__new__">+ Add new key...</option>
|
|
@@ -547,7 +545,7 @@ export function ConnectorSheet() {
|
|
|
547
545
|
onClick={async () => {
|
|
548
546
|
setSavingCred(true)
|
|
549
547
|
try {
|
|
550
|
-
const cred = await api<
|
|
548
|
+
const cred = await api<{ id: string }>('POST', '/credentials', {
|
|
551
549
|
provider: platform,
|
|
552
550
|
name: newCredName.trim() || `${platformConfig.label} Bot Token`,
|
|
553
551
|
apiKey: newCredValue.trim(),
|
|
@@ -557,8 +555,8 @@ export function ConnectorSheet() {
|
|
|
557
555
|
setShowNewCred(false)
|
|
558
556
|
setNewCredName('')
|
|
559
557
|
setNewCredValue('')
|
|
560
|
-
} catch (err:
|
|
561
|
-
toast.error(`Failed to save: ${err.message}`)
|
|
558
|
+
} catch (err: unknown) {
|
|
559
|
+
toast.error(`Failed to save: ${err instanceof Error ? err.message : String(err)}`)
|
|
562
560
|
} finally {
|
|
563
561
|
setSavingCred(false)
|
|
564
562
|
}
|
|
@@ -730,8 +728,8 @@ export function ConnectorSheet() {
|
|
|
730
728
|
setQrDataUrl(null)
|
|
731
729
|
setWaConnecting(true)
|
|
732
730
|
await loadConnectors()
|
|
733
|
-
} catch (err:
|
|
734
|
-
toast.error(`Failed to unlink: ${err.message}`)
|
|
731
|
+
} catch (err: unknown) {
|
|
732
|
+
toast.error(`Failed to unlink: ${err instanceof Error ? err.message : String(err)}`)
|
|
735
733
|
} finally {
|
|
736
734
|
setActionLoading(false)
|
|
737
735
|
}
|
|
@@ -771,8 +769,8 @@ export function ConnectorSheet() {
|
|
|
771
769
|
setQrDataUrl(null)
|
|
772
770
|
setWaConnecting(true)
|
|
773
771
|
await loadConnectors()
|
|
774
|
-
} catch (err:
|
|
775
|
-
toast.error(`Failed to re-pair: ${err.message}`)
|
|
772
|
+
} catch (err: unknown) {
|
|
773
|
+
toast.error(`Failed to re-pair: ${err instanceof Error ? err.message : String(err)}`)
|
|
776
774
|
} finally {
|
|
777
775
|
setActionLoading(false)
|
|
778
776
|
}
|
|
@@ -796,28 +794,17 @@ export function ConnectorSheet() {
|
|
|
796
794
|
)}
|
|
797
795
|
|
|
798
796
|
{/* Actions */}
|
|
799
|
-
<
|
|
800
|
-
{
|
|
797
|
+
<SheetFooter
|
|
798
|
+
onCancel={() => { setOpen(false); setEditingId(null) }}
|
|
799
|
+
onSave={handleSave}
|
|
800
|
+
saveLabel={saving ? 'Saving...' : editing ? 'Save' : 'Create Connector'}
|
|
801
|
+
saveDisabled={saving || !agentId}
|
|
802
|
+
left={editing && (
|
|
801
803
|
<button onClick={handleDelete} className="py-3.5 px-6 rounded-[14px] border border-red-500/20 bg-transparent text-red-400 text-[15px] font-600 cursor-pointer hover:bg-red-500/10 transition-all" style={{ fontFamily: 'inherit' }}>
|
|
802
804
|
Delete
|
|
803
805
|
</button>
|
|
804
806
|
)}
|
|
805
|
-
|
|
806
|
-
onClick={() => { setOpen(false); setEditingId(null) }}
|
|
807
|
-
className="flex-1 py-3.5 rounded-[14px] border border-white/[0.08] bg-transparent text-text-2 text-[15px] font-600 cursor-pointer hover:bg-surface-2 transition-all"
|
|
808
|
-
style={{ fontFamily: 'inherit' }}
|
|
809
|
-
>
|
|
810
|
-
Cancel
|
|
811
|
-
</button>
|
|
812
|
-
<button
|
|
813
|
-
onClick={handleSave}
|
|
814
|
-
disabled={saving || !agentId}
|
|
815
|
-
className="flex-1 py-3.5 rounded-[14px] border-none bg-[#6366F1] text-white text-[15px] font-600 cursor-pointer active:scale-[0.97] disabled:opacity-30 transition-all shadow-[0_4px_20px_rgba(99,102,241,0.25)] hover:brightness-110"
|
|
816
|
-
style={{ fontFamily: 'inherit' }}
|
|
817
|
-
>
|
|
818
|
-
{saving ? 'Saving...' : editing ? 'Save' : 'Create Connector'}
|
|
819
|
-
</button>
|
|
820
|
-
</div>
|
|
807
|
+
/>
|
|
821
808
|
</BottomSheet>
|
|
822
809
|
)
|
|
823
810
|
}
|