@zhin.js/console 1.0.51 → 1.0.53
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/CHANGELOG.md +21 -0
- package/README.md +22 -0
- package/browser.tsconfig.json +19 -0
- package/client/src/components/PageHeader.tsx +26 -0
- package/client/src/components/ui/accordion.tsx +2 -1
- package/client/src/components/ui/badge.tsx +1 -3
- package/client/src/components/ui/scroll-area.tsx +5 -2
- package/client/src/components/ui/select.tsx +7 -3
- package/client/src/components/ui/separator.tsx +5 -2
- package/client/src/components/ui/tabs.tsx +4 -2
- package/client/src/layouts/dashboard.tsx +223 -121
- package/client/src/main.tsx +34 -34
- package/client/src/pages/bot-detail/MessageBody.tsx +110 -0
- package/client/src/pages/bot-detail/date-utils.ts +8 -0
- package/client/src/pages/bot-detail/index.tsx +798 -0
- package/client/src/pages/bot-detail/types.ts +92 -0
- package/client/src/pages/bot-detail/useBotConsole.tsx +600 -0
- package/client/src/pages/bots.tsx +111 -73
- package/client/src/pages/database/constants.ts +16 -0
- package/client/src/pages/database/database-page.tsx +170 -0
- package/client/src/pages/database/document-collection-view.tsx +155 -0
- package/client/src/pages/database/index.tsx +1 -0
- package/client/src/pages/database/json-field.tsx +11 -0
- package/client/src/pages/database/kv-bucket-view.tsx +169 -0
- package/client/src/pages/database/related-table-view.tsx +221 -0
- package/client/src/pages/env.tsx +38 -28
- package/client/src/pages/files/code-editor.tsx +85 -0
- package/client/src/pages/files/editor-constants.ts +9 -0
- package/client/src/pages/files/file-editor.tsx +133 -0
- package/client/src/pages/files/file-icons.tsx +25 -0
- package/client/src/pages/files/files-page.tsx +92 -0
- package/client/src/pages/files/hljs-global.d.ts +10 -0
- package/client/src/pages/files/index.tsx +1 -0
- package/client/src/pages/files/language.ts +18 -0
- package/client/src/pages/files/tree-node.tsx +69 -0
- package/client/src/pages/files/use-hljs-theme.ts +23 -0
- package/client/src/pages/logs.tsx +77 -22
- package/client/src/style.css +144 -0
- package/client/src/utils/parseComposerContent.ts +57 -0
- package/client/tailwind.config.js +1 -0
- package/client/tsconfig.json +3 -1
- package/dist/assets/index-COKXlFo2.js +124 -0
- package/dist/assets/style-kkLO-vsa.css +3 -0
- package/dist/client.js +482 -464
- package/dist/index.html +2 -2
- package/dist/style.css +1 -1
- package/lib/index.js +1010 -81
- package/lib/transform.js +16 -2
- package/lib/websocket.js +845 -28
- package/node.tsconfig.json +18 -0
- package/package.json +13 -15
- package/src/bin.ts +24 -0
- package/src/bot-db-models.ts +74 -0
- package/src/bot-hub.ts +240 -0
- package/src/bot-persistence.ts +270 -0
- package/src/build.ts +90 -0
- package/src/dev.ts +107 -0
- package/src/index.ts +337 -0
- package/src/transform.ts +199 -0
- package/src/websocket.ts +1369 -0
- package/client/src/pages/database.tsx +0 -708
- package/client/src/pages/files.tsx +0 -470
- package/client/src/pages/login-assist.tsx +0 -225
- package/dist/assets/index-DS4RbHWX.js +0 -124
- package/dist/assets/style-DS-m6WEr.css +0 -3
package/client/src/main.tsx
CHANGED
|
@@ -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
|
|
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
|
|
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
|
|
14
|
-
import
|
|
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: '
|
|
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: '
|
|
78
|
-
path: '/
|
|
79
|
-
title: '
|
|
80
|
-
icon: <
|
|
81
|
-
element: <
|
|
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:
|
|
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:
|
|
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: <
|
|
113
|
-
meta: { order:
|
|
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: <
|
|
121
|
-
meta: { order:
|
|
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:
|
|
138
|
+
meta: { group: '配置与数据', order: 7, fullWidth: true },
|
|
130
139
|
},
|
|
131
140
|
{
|
|
132
|
-
key: '
|
|
133
|
-
path: '/bots',
|
|
134
|
-
title: '
|
|
135
|
-
|
|
136
|
-
|
|
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
|
+
}
|