@zhin.js/console 1.0.51 → 1.0.52

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.
Files changed (65) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/README.md +22 -0
  3. package/browser.tsconfig.json +19 -0
  4. package/client/src/components/PageHeader.tsx +26 -0
  5. package/client/src/components/ui/accordion.tsx +2 -1
  6. package/client/src/components/ui/badge.tsx +1 -3
  7. package/client/src/components/ui/scroll-area.tsx +5 -2
  8. package/client/src/components/ui/select.tsx +7 -3
  9. package/client/src/components/ui/separator.tsx +5 -2
  10. package/client/src/components/ui/tabs.tsx +4 -2
  11. package/client/src/layouts/dashboard.tsx +223 -121
  12. package/client/src/main.tsx +34 -34
  13. package/client/src/pages/bot-detail/MessageBody.tsx +110 -0
  14. package/client/src/pages/bot-detail/date-utils.ts +8 -0
  15. package/client/src/pages/bot-detail/index.tsx +798 -0
  16. package/client/src/pages/bot-detail/types.ts +92 -0
  17. package/client/src/pages/bot-detail/useBotConsole.tsx +600 -0
  18. package/client/src/pages/bots.tsx +111 -73
  19. package/client/src/pages/database/constants.ts +16 -0
  20. package/client/src/pages/database/database-page.tsx +170 -0
  21. package/client/src/pages/database/document-collection-view.tsx +155 -0
  22. package/client/src/pages/database/index.tsx +1 -0
  23. package/client/src/pages/database/json-field.tsx +11 -0
  24. package/client/src/pages/database/kv-bucket-view.tsx +169 -0
  25. package/client/src/pages/database/related-table-view.tsx +221 -0
  26. package/client/src/pages/env.tsx +38 -28
  27. package/client/src/pages/files/code-editor.tsx +85 -0
  28. package/client/src/pages/files/editor-constants.ts +9 -0
  29. package/client/src/pages/files/file-editor.tsx +133 -0
  30. package/client/src/pages/files/file-icons.tsx +25 -0
  31. package/client/src/pages/files/files-page.tsx +92 -0
  32. package/client/src/pages/files/hljs-global.d.ts +10 -0
  33. package/client/src/pages/files/index.tsx +1 -0
  34. package/client/src/pages/files/language.ts +18 -0
  35. package/client/src/pages/files/tree-node.tsx +69 -0
  36. package/client/src/pages/files/use-hljs-theme.ts +23 -0
  37. package/client/src/pages/logs.tsx +77 -22
  38. package/client/src/style.css +144 -0
  39. package/client/src/utils/parseComposerContent.ts +57 -0
  40. package/client/tailwind.config.js +1 -0
  41. package/client/tsconfig.json +3 -1
  42. package/dist/assets/index-COKXlFo2.js +124 -0
  43. package/dist/assets/style-kkLO-vsa.css +3 -0
  44. package/dist/client.js +482 -464
  45. package/dist/index.html +2 -2
  46. package/dist/style.css +1 -1
  47. package/lib/index.js +1010 -81
  48. package/lib/transform.js +16 -2
  49. package/lib/websocket.js +845 -28
  50. package/node.tsconfig.json +18 -0
  51. package/package.json +13 -15
  52. package/src/bin.ts +24 -0
  53. package/src/bot-db-models.ts +74 -0
  54. package/src/bot-hub.ts +240 -0
  55. package/src/bot-persistence.ts +270 -0
  56. package/src/build.ts +90 -0
  57. package/src/dev.ts +107 -0
  58. package/src/index.ts +337 -0
  59. package/src/transform.ts +199 -0
  60. package/src/websocket.ts +1369 -0
  61. package/client/src/pages/database.tsx +0 -708
  62. package/client/src/pages/files.tsx +0 -470
  63. package/client/src/pages/login-assist.tsx +0 -225
  64. package/dist/assets/index-DS4RbHWX.js +0 -124
  65. package/dist/assets/style-DS-m6WEr.css +0 -3
@@ -1,20 +1,20 @@
1
1
  import { StrictMode, useCallback, useEffect, useState } from 'react'
2
2
  import { createRoot } from 'react-dom/client'
3
3
  import { Provider as ReduxProvider } from 'react-redux'
4
- import { Home, Package, Bot, FileText, Settings, KeyRound, FolderOpen, Database, LogIn } from 'lucide-react'
4
+ import { Home, Package, Bot, FileText, Settings, KeyRound, FolderOpen, Database } from 'lucide-react'
5
5
  import { store, DynamicRouter, persistor, addPage, useSelector, useWebSocket } from '@zhin.js/client'
6
6
  import DashboardLayout from './layouts/dashboard'
7
7
  import HomePage from './pages/dashboard'
8
8
  import PluginsPage from './pages/plugins'
9
9
  import PluginDetailPage from './pages/plugin-detail'
10
- import BotMangePage from './pages/bots'
10
+ import BotManagePage from './pages/bots'
11
+ import BotDetailPage from './pages/bot-detail'
11
12
  import LogsPage from './pages/logs'
12
13
  import ConfigPage from './pages/config'
13
- import EnvMangePage from './pages/env'
14
- import FileMangePage from './pages/files'
14
+ import EnvManagePage from './pages/env'
15
+ import FileManagePage from './pages/files'
15
16
  import DatabasePage from './pages/database'
16
17
  import LoginPage from './pages/login'
17
- import LoginAssistPage from './pages/login-assist'
18
18
  import { hasToken } from './utils/auth'
19
19
  import './style.css'
20
20
  import { PersistGate } from 'redux-persist/integration/react'
@@ -60,7 +60,7 @@ function RouteInitializer() {
60
60
  useEffect(() => {
61
61
  const routes = [
62
62
  {
63
- key: 'dashboard-layout',
63
+ key: 'dashboardLayout',
64
64
  path: '/',
65
65
  title: 'Dashboard',
66
66
  element: <DashboardLayout />,
@@ -72,14 +72,23 @@ function RouteInitializer() {
72
72
  title: '系统概览',
73
73
  icon: <Home className="w-4 h-4" />,
74
74
  element: <HomePage />,
75
+ meta: { group: '系统', order: 0 },
75
76
  },
76
77
  {
77
- key: 'loginAssistPage',
78
- path: '/login-assist',
79
- title: '登录辅助',
80
- icon: <LogIn className="w-4 h-4" />,
81
- element: <LoginAssistPage />,
82
- meta: { order: 1 }
78
+ key: 'botManagePage',
79
+ path: '/bots',
80
+ title: '机器人',
81
+ icon: <Bot className="w-4 h-4" />,
82
+ element: <BotManagePage />,
83
+ meta: { group: '系统', order: 1 },
84
+ },
85
+ {
86
+ key: 'logsPage',
87
+ path: '/logs',
88
+ title: '系统日志',
89
+ icon: <FileText className="w-4 h-4" />,
90
+ element: <LogsPage />,
91
+ meta: { group: '系统', order: 2, fullWidth: true },
83
92
  },
84
93
  {
85
94
  key: 'pluginsPage',
@@ -87,14 +96,14 @@ function RouteInitializer() {
87
96
  title: '插件管理',
88
97
  icon: <Package className="w-4 h-4" />,
89
98
  element: <PluginsPage />,
90
- meta: { order: 2 }
99
+ meta: { group: '扩展', order: 3 },
91
100
  },
92
101
  {
93
102
  key: 'pluginDetailPage',
94
103
  title: '插件详情',
95
104
  path: '/plugins/:name',
96
105
  element: <PluginDetailPage />,
97
- meta: { hideInMenu: true }
106
+ meta: { hideInMenu: true },
98
107
  },
99
108
  {
100
109
  key: 'configPage',
@@ -102,23 +111,23 @@ function RouteInitializer() {
102
111
  title: '配置管理',
103
112
  icon: <Settings className="w-4 h-4" />,
104
113
  element: <ConfigPage />,
105
- meta: { order: 3 }
114
+ meta: { group: '配置与数据', order: 4 },
106
115
  },
107
116
  {
108
117
  key: 'envManagePage',
109
118
  path: '/env',
110
119
  title: '环境变量',
111
120
  icon: <KeyRound className="w-4 h-4" />,
112
- element: <EnvMangePage />,
113
- meta: { order: 4 }
121
+ element: <EnvManagePage />,
122
+ meta: { group: '配置与数据', order: 5 },
114
123
  },
115
124
  {
116
125
  key: 'fileManagePage',
117
126
  path: '/files',
118
127
  title: '文件管理',
119
128
  icon: <FolderOpen className="w-4 h-4" />,
120
- element: <FileMangePage />,
121
- meta: { order: 5 }
129
+ element: <FileManagePage />,
130
+ meta: { group: '配置与数据', order: 6 },
122
131
  },
123
132
  {
124
133
  key: 'databasePage',
@@ -126,24 +135,15 @@ function RouteInitializer() {
126
135
  title: '数据库',
127
136
  icon: <Database className="w-4 h-4" />,
128
137
  element: <DatabasePage />,
129
- meta: { order: 6 }
138
+ meta: { group: '配置与数据', order: 7, fullWidth: true },
130
139
  },
131
140
  {
132
- key: 'botManagePage',
133
- path: '/bots',
134
- title: '机器人',
135
- icon: <Bot className="w-4 h-4" />,
136
- element: <BotMangePage />,
137
- meta: { order: 7 }
141
+ key: 'botDetailPage',
142
+ path: '/bots/:adapter/:botId',
143
+ title: '机器人详情',
144
+ element: <BotDetailPage />,
145
+ meta: { hideInMenu: true, fullWidth: true },
138
146
  },
139
- {
140
- key: 'logsPage ',
141
- path: '/logs',
142
- title: '系统日志',
143
- icon: <FileText className="w-4 h-4" />,
144
- element: <LogsPage />,
145
- meta: { order: 8 }
146
- }
147
147
  ]
148
148
  }
149
149
  ]
@@ -0,0 +1,110 @@
1
+ import { cn, pickMediaRawUrl, resolveMediaSrc } from '@zhin.js/client'
2
+ import type { ReceivedMessage } from './types'
3
+
4
+ export function MessageBody({ content }: { content: ReceivedMessage['content'] }) {
5
+ return (
6
+ <>
7
+ {content.map((seg, i) => {
8
+ const d = (seg.data ?? {}) as Record<string, unknown>
9
+
10
+ if (seg.type === 'text' && d.text != null)
11
+ return <span key={i}>{String(d.text)}</span>
12
+
13
+ if (seg.type === 'at')
14
+ return (
15
+ <span key={i} className="im-at font-medium">
16
+ @{String(d.name ?? d.qq ?? '')}
17
+ </span>
18
+ )
19
+
20
+ if (seg.type === 'face')
21
+ return (
22
+ <img
23
+ key={i}
24
+ src={`https://face.viki.moe/apng/${d.id}.png`}
25
+ alt=""
26
+ className="w-6 h-6 inline-block align-middle mx-0.5"
27
+ />
28
+ )
29
+
30
+ if (seg.type === 'image') {
31
+ const raw = pickMediaRawUrl(d)
32
+ const src = resolveMediaSrc(raw, 'image')
33
+ if (!src)
34
+ return (
35
+ <span key={i} className="text-muted-foreground text-xs">
36
+ [图片]
37
+ </span>
38
+ )
39
+ return (
40
+ <div key={i} className="my-1.5 block w-full max-w-full">
41
+ <a href={src} target="_blank" rel="noreferrer" className="inline-block max-w-full">
42
+ <img
43
+ src={src}
44
+ alt=""
45
+ className={cn(
46
+ 'max-w-[min(280px,88vw)] max-h-64 rounded-lg border border-border/50 object-contain bg-muted/20',
47
+ )}
48
+ onError={(e) => {
49
+ ;(e.target as HTMLImageElement).style.display = 'none'
50
+ }}
51
+ />
52
+ </a>
53
+ </div>
54
+ )
55
+ }
56
+
57
+ if (seg.type === 'video') {
58
+ const raw = pickMediaRawUrl(d)
59
+ const src = resolveMediaSrc(raw, 'video')
60
+ if (!src)
61
+ return (
62
+ <span key={i} className="text-muted-foreground text-xs">
63
+ [视频]
64
+ </span>
65
+ )
66
+ return (
67
+ <div key={i} className="my-1.5 w-full max-w-full">
68
+ <video
69
+ src={src}
70
+ controls
71
+ playsInline
72
+ preload="metadata"
73
+ className="max-w-[min(320px,92vw)] max-h-72 rounded-lg border border-border/50 bg-black/10"
74
+ />
75
+ </div>
76
+ )
77
+ }
78
+
79
+ if (seg.type === 'audio' || seg.type === 'record') {
80
+ const raw = pickMediaRawUrl(d)
81
+ const src = resolveMediaSrc(raw, 'audio')
82
+ if (!src)
83
+ return (
84
+ <span key={i} className="text-muted-foreground text-xs">
85
+ [语音]
86
+ </span>
87
+ )
88
+ return (
89
+ <div key={i} className="my-1.5 w-full max-w-[min(320px,100%)]">
90
+ <audio src={src} controls preload="metadata" className="w-full h-9" />
91
+ </div>
92
+ )
93
+ }
94
+
95
+ if (seg.type === 'file')
96
+ return (
97
+ <span key={i} className="text-muted-foreground text-xs">
98
+ 📎 {String(d.name ?? '文件')}
99
+ </span>
100
+ )
101
+
102
+ return (
103
+ <span key={i} className="text-muted-foreground text-xs">
104
+ [{seg.type}]
105
+ </span>
106
+ )
107
+ })}
108
+ </>
109
+ )
110
+ }
@@ -0,0 +1,8 @@
1
+ export function dayKey(ts: number) {
2
+ const d = new Date(ts)
3
+ return `${d.getFullYear()}-${d.getMonth()}-${d.getDate()}`
4
+ }
5
+
6
+ export function dayLabel(ts: number) {
7
+ return new Date(ts).toLocaleDateString('zh-CN', { year: 'numeric', month: 'long', day: 'numeric' })
8
+ }