@lobehub/chat 0.147.15 → 0.147.17
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 +50 -0
- package/contributing/Basic/Feature-Development.md +7 -7
- package/contributing/Basic/Feature-Development.zh-CN.md +7 -7
- package/next.config.mjs +61 -13
- package/package.json +2 -1
- package/sentry.client.config.ts +30 -0
- package/sentry.edge.config.ts +17 -0
- package/sentry.server.config.ts +19 -0
- package/src/app/api/auth/[...nextauth]/route.ts +1 -1
- package/src/app/chat/(desktop)/features/ChatInput/Footer/index.tsx +7 -1
- package/src/app/chat/(desktop)/features/ChatInput/TextArea.tsx +7 -1
- package/src/app/home/Redirect.tsx +2 -2
- package/src/app/layout.tsx +2 -2
- package/src/config/server/app.ts +0 -18
- package/src/config/server/auth.ts +71 -0
- package/src/config/server/index.ts +3 -1
- package/src/database/client/models/__tests__/session.test.ts +1 -3
- package/src/database/client/models/session.ts +4 -4
- package/src/layout/AuthProvider/NextAuth/index.tsx +10 -0
- package/src/layout/AuthProvider/index.tsx +3 -7
- package/src/layout/DefaultLayout/Desktop/SideBar/Avatar.tsx +11 -0
- package/src/layout/{GlobalLayout → DefaultLayout}/Desktop/SideBar/index.tsx +2 -2
- package/src/layout/{GlobalLayout/Mobile/Client.tsx → DefaultLayout/Mobile/index.tsx} +2 -0
- package/src/layout/DefaultLayout/index.ts +2 -0
- package/src/layout/{GlobalLayout/Desktop/index.tsx → routes/Desktop.tsx} +5 -3
- package/src/layout/{GlobalLayout/Mobile/index.tsx → routes/Mobile.tsx} +3 -4
- package/src/layout/{GlobalLayout → routes}/index.tsx +2 -2
- package/src/{app/api/auth/next-auth.ts → libs/next-auth/index.ts} +1 -1
- package/src/middleware.ts +1 -1
- package/src/services/config.ts +4 -4
- package/src/services/file/client.test.ts +2 -2
- package/src/services/file/client.ts +35 -33
- package/src/services/file/index.ts +8 -2
- package/src/services/file/type.ts +11 -0
- package/src/services/message/client.test.ts +6 -32
- package/src/services/message/client.ts +24 -37
- package/src/services/message/index.test.ts +48 -0
- package/src/services/message/index.ts +22 -2
- package/src/services/message/type.ts +33 -0
- package/src/services/plugin/client.test.ts +2 -2
- package/src/services/plugin/client.ts +1 -1
- package/src/services/plugin/index.ts +9 -3
- package/src/services/session/client.test.ts +37 -44
- package/src/services/session/client.ts +30 -22
- package/src/services/session/index.ts +9 -2
- package/src/services/session/type.ts +44 -0
- package/src/services/topic/client.test.ts +18 -22
- package/src/services/topic/client.ts +31 -23
- package/src/services/topic/index.ts +10 -2
- package/src/services/topic/type.ts +32 -0
- package/src/services/user/client.ts +1 -1
- package/src/services/user/index.ts +10 -2
- package/src/store/chat/slices/message/action.test.ts +12 -12
- package/src/store/chat/slices/message/action.ts +4 -4
- package/src/store/chat/slices/plugin/action.test.ts +5 -6
- package/src/store/chat/slices/plugin/action.ts +1 -1
- package/src/store/chat/slices/topic/action.test.ts +11 -6
- package/src/store/chat/slices/topic/action.ts +7 -5
- package/src/store/session/slices/agent/action.test.ts +175 -0
- package/src/store/session/slices/agent/action.ts +1 -1
- package/src/store/session/slices/session/action.test.ts +14 -15
- package/src/store/session/slices/session/action.ts +4 -4
- package/src/store/session/slices/sessionGroup/action.test.ts +6 -4
- package/src/store/session/slices/sessionGroup/action.ts +3 -3
- /package/src/layout/{GlobalLayout → DefaultLayout}/Desktop/SideBar/BottomActions.tsx +0 -0
- /package/src/layout/{GlobalLayout → DefaultLayout}/Desktop/SideBar/TopActions.tsx +0 -0
- /package/src/layout/{GlobalLayout/Desktop/Client.tsx → DefaultLayout/Desktop/index.tsx} +0 -0
- /package/src/{app/api/auth → libs/next-auth}/sso-providers/auth0.ts +0 -0
- /package/src/{app/api/auth → libs/next-auth}/sso-providers/authentik.ts +0 -0
- /package/src/{app/api/auth → libs/next-auth}/sso-providers/azure-ad.ts +0 -0
- /package/src/{app/api/auth → libs/next-auth}/sso-providers/github.ts +0 -0
- /package/src/{app/api/auth → libs/next-auth}/sso-providers/index.ts +0 -0
- /package/src/{app/api/auth → libs/next-auth}/sso-providers/zitadel.ts +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,56 @@
|
|
|
2
2
|
|
|
3
3
|
# Changelog
|
|
4
4
|
|
|
5
|
+
### [Version 0.147.17](https://github.com/lobehub/lobe-chat/compare/v0.147.16...v0.147.17)
|
|
6
|
+
|
|
7
|
+
<sup>Released on **2024-04-16**</sup>
|
|
8
|
+
|
|
9
|
+
#### ♻ Code Refactoring
|
|
10
|
+
|
|
11
|
+
- **misc**: Refactor service to a uniform interface.
|
|
12
|
+
|
|
13
|
+
<br/>
|
|
14
|
+
|
|
15
|
+
<details>
|
|
16
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
|
17
|
+
|
|
18
|
+
#### Code refactoring
|
|
19
|
+
|
|
20
|
+
- **misc**: Refactor service to a uniform interface, closes [#2062](https://github.com/lobehub/lobe-chat/issues/2062) ([86779e2](https://github.com/lobehub/lobe-chat/commit/86779e2))
|
|
21
|
+
|
|
22
|
+
</details>
|
|
23
|
+
|
|
24
|
+
<div align="right">
|
|
25
|
+
|
|
26
|
+
[](#readme-top)
|
|
27
|
+
|
|
28
|
+
</div>
|
|
29
|
+
|
|
30
|
+
### [Version 0.147.16](https://github.com/lobehub/lobe-chat/compare/v0.147.15...v0.147.16)
|
|
31
|
+
|
|
32
|
+
<sup>Released on **2024-04-14**</sup>
|
|
33
|
+
|
|
34
|
+
#### ♻ Code Refactoring
|
|
35
|
+
|
|
36
|
+
- **misc**: Refactor the auth.
|
|
37
|
+
|
|
38
|
+
<br/>
|
|
39
|
+
|
|
40
|
+
<details>
|
|
41
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
|
42
|
+
|
|
43
|
+
#### Code refactoring
|
|
44
|
+
|
|
45
|
+
- **misc**: Refactor the auth, closes [#2043](https://github.com/lobehub/lobe-chat/issues/2043) ([37ecb41](https://github.com/lobehub/lobe-chat/commit/37ecb41))
|
|
46
|
+
|
|
47
|
+
</details>
|
|
48
|
+
|
|
49
|
+
<div align="right">
|
|
50
|
+
|
|
51
|
+
[](#readme-top)
|
|
52
|
+
|
|
53
|
+
</div>
|
|
54
|
+
|
|
5
55
|
### [Version 0.147.15](https://github.com/lobehub/lobe-chat/compare/v0.147.14...v0.147.15)
|
|
6
56
|
|
|
7
57
|
<sup>Released on **2024-04-14**</sup>
|
|
@@ -231,7 +231,7 @@ This requirement involves upgrading the Sessions feature to transform it from a
|
|
|
231
231
|
|
|
232
232
|
To handle these groups, we need to refactor the implementation logic of `useFetchSessions`. Here are the key changes:
|
|
233
233
|
|
|
234
|
-
1. Use the `sessionService.
|
|
234
|
+
1. Use the `sessionService.getGroupedSessions` method to call the backend API and retrieve the grouped session data.
|
|
235
235
|
2. Save the retrieved data into three different state fields: `pinnedSessions`, `customSessionGroups`, and `defaultSessions`.
|
|
236
236
|
|
|
237
237
|
#### `useFetchSessions` Method
|
|
@@ -247,7 +247,7 @@ export const createSessionSlice: StateCreator<
|
|
|
247
247
|
> = (set, get) => ({
|
|
248
248
|
// ... other methods
|
|
249
249
|
useFetchSessions: () =>
|
|
250
|
-
useSWR<ChatSessionList>(FETCH_SESSIONS_KEY, sessionService.
|
|
250
|
+
useSWR<ChatSessionList>(FETCH_SESSIONS_KEY, sessionService.getGroupedSessions, {
|
|
251
251
|
onSuccess: (data) => {
|
|
252
252
|
set(
|
|
253
253
|
{
|
|
@@ -267,15 +267,15 @@ export const createSessionSlice: StateCreator<
|
|
|
267
267
|
|
|
268
268
|
After successfully retrieving the data, we use the `set` method to update the `customSessionGroups`, `defaultSessions`, `pinnedSessions`, and `sessions` states. This ensures that the states are synchronized with the latest session data.
|
|
269
269
|
|
|
270
|
-
#### `sessionService.
|
|
270
|
+
#### `sessionService.getGroupedSessions` Method
|
|
271
271
|
|
|
272
|
-
The `sessionService.
|
|
272
|
+
The `sessionService.getGroupedSessions` method is responsible for calling the backend API `SessionModel.queryWithGroups()`.
|
|
273
273
|
|
|
274
274
|
```typescript
|
|
275
275
|
class SessionService {
|
|
276
276
|
// ... other SessionGroup related implementations
|
|
277
277
|
|
|
278
|
-
async
|
|
278
|
+
async getGroupedSessions(): Promise<ChatSessionList> {
|
|
279
279
|
return SessionModel.queryWithGroups();
|
|
280
280
|
}
|
|
281
281
|
}
|
|
@@ -283,7 +283,7 @@ class SessionService {
|
|
|
283
283
|
|
|
284
284
|
#### `SessionModel.queryWithGroups` Method
|
|
285
285
|
|
|
286
|
-
This method is the core method called by `sessionService.
|
|
286
|
+
This method is the core method called by `sessionService.getGroupedSessions`, and it is responsible for querying and organizing session data. The code is as follows:
|
|
287
287
|
|
|
288
288
|
```typescript
|
|
289
289
|
class _SessionModel extends BaseModel {
|
|
@@ -617,7 +617,7 @@ class ConfigService {
|
|
|
617
617
|
// ... Other code omitted
|
|
618
618
|
|
|
619
619
|
exportSessions = async () => {
|
|
620
|
-
const sessions = await sessionService.
|
|
620
|
+
const sessions = await sessionService.getAllSessions();
|
|
621
621
|
+ const sessionGroups = await sessionService.getSessionGroups();
|
|
622
622
|
const messages = await messageService.getAllMessages();
|
|
623
623
|
const topics = await topicService.getAllTopics();
|
|
@@ -231,7 +231,7 @@ export const createSessionGroupSlice: StateCreator<
|
|
|
231
231
|
|
|
232
232
|
为了处理这些分组,我们需要改造 `useFetchSessions` 的实现逻辑。以下是关键的改动点:
|
|
233
233
|
|
|
234
|
-
1. 使用 `sessionService.
|
|
234
|
+
1. 使用 `sessionService.getGroupedSessions` 方法负责调用后端接口来获取分组后的会话数据;
|
|
235
235
|
2. 将获取后的数据保存为三到不同的状态字段中:`pinnedSessions`、`customSessionGroups` 和 `defaultSessions`;
|
|
236
236
|
|
|
237
237
|
#### `useFetchSessions` 方法
|
|
@@ -247,7 +247,7 @@ export const createSessionSlice: StateCreator<
|
|
|
247
247
|
> = (set, get) => ({
|
|
248
248
|
// ... 其他方法
|
|
249
249
|
useFetchSessions: () =>
|
|
250
|
-
useSWR<ChatSessionList>(FETCH_SESSIONS_KEY, sessionService.
|
|
250
|
+
useSWR<ChatSessionList>(FETCH_SESSIONS_KEY, sessionService.getGroupedSessions, {
|
|
251
251
|
onSuccess: (data) => {
|
|
252
252
|
set(
|
|
253
253
|
{
|
|
@@ -267,15 +267,15 @@ export const createSessionSlice: StateCreator<
|
|
|
267
267
|
|
|
268
268
|
在成功获取数据后,我们使用 `set` 方法来更新 `customSessionGroups`、`defaultSessions`、`pinnedSessions` 和 `sessions` 状态。这将保证状态与最新的会话数据同步。
|
|
269
269
|
|
|
270
|
-
####
|
|
270
|
+
#### getGroupedSessions
|
|
271
271
|
|
|
272
|
-
使用 `sessionService.
|
|
272
|
+
使用 `sessionService.getGroupedSessions` 方法负责调用后端接口 `SessionModel.queryWithGroups()`
|
|
273
273
|
|
|
274
274
|
```typescript
|
|
275
275
|
class SessionService {
|
|
276
276
|
// ... 其他 SessionGroup 相关的实现
|
|
277
277
|
|
|
278
|
-
async
|
|
278
|
+
async getGroupedSessions(): Promise<ChatSessionList> {
|
|
279
279
|
return SessionModel.queryWithGroups();
|
|
280
280
|
}
|
|
281
281
|
}
|
|
@@ -283,7 +283,7 @@ class SessionService {
|
|
|
283
283
|
|
|
284
284
|
#### `SessionModel.queryWithGroups` 方法
|
|
285
285
|
|
|
286
|
-
此方法是 `sessionService.
|
|
286
|
+
此方法是 `sessionService.getGroupedSessions` 调用的核心方法,它负责查询和组织会话数据,代码如下:
|
|
287
287
|
|
|
288
288
|
```typescript
|
|
289
289
|
class _SessionModel extends BaseModel {
|
|
@@ -611,7 +611,7 @@ class ConfigService {
|
|
|
611
611
|
// ... 省略其他
|
|
612
612
|
|
|
613
613
|
exportSessions = async () => {
|
|
614
|
-
const sessions = await sessionService.
|
|
614
|
+
const sessions = await sessionService.getAllSessions();
|
|
615
615
|
+ const sessionGroups = await sessionService.getSessionGroups();
|
|
616
616
|
const messages = await messageService.getAllMessages();
|
|
617
617
|
const topics = await topicService.getAllTopics();
|
package/next.config.mjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import nextPWA from '@ducanh2912/next-pwa';
|
|
2
2
|
import analyzer from '@next/bundle-analyzer';
|
|
3
|
+
import { withSentryConfig } from '@sentry/nextjs';
|
|
3
4
|
|
|
4
5
|
const isProd = process.env.NODE_ENV === 'production';
|
|
5
6
|
const buildWithDocker = process.env.DOCKER === 'true';
|
|
@@ -9,18 +10,6 @@ const API_PROXY_ENDPOINT = process.env.API_PROXY_ENDPOINT || '';
|
|
|
9
10
|
|
|
10
11
|
const basePath = process.env.NEXT_PUBLIC_BASE_PATH;
|
|
11
12
|
|
|
12
|
-
const withBundleAnalyzer = analyzer({
|
|
13
|
-
enabled: process.env.ANALYZE === 'true',
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
const withPWA = nextPWA({
|
|
17
|
-
dest: 'public',
|
|
18
|
-
register: true,
|
|
19
|
-
workboxOptions: {
|
|
20
|
-
skipWaiting: true,
|
|
21
|
-
},
|
|
22
|
-
});
|
|
23
|
-
|
|
24
13
|
/** @type {import('next').NextConfig} */
|
|
25
14
|
const nextConfig = {
|
|
26
15
|
compress: isProd,
|
|
@@ -67,4 +56,63 @@ const nextConfig = {
|
|
|
67
56
|
},
|
|
68
57
|
};
|
|
69
58
|
|
|
70
|
-
|
|
59
|
+
const noWrapper = (config) => config;
|
|
60
|
+
|
|
61
|
+
const withBundleAnalyzer = process.env.ANALYZE === 'true' ? analyzer() : noWrapper;
|
|
62
|
+
|
|
63
|
+
const withPWA = isProd
|
|
64
|
+
? nextPWA({
|
|
65
|
+
dest: 'public',
|
|
66
|
+
register: true,
|
|
67
|
+
workboxOptions: {
|
|
68
|
+
skipWaiting: true,
|
|
69
|
+
},
|
|
70
|
+
})
|
|
71
|
+
: noWrapper;
|
|
72
|
+
|
|
73
|
+
const hasSentry = !!process.env.NEXT_PUBLIC_SENTRY_DSN;
|
|
74
|
+
const withSentry =
|
|
75
|
+
isProd && hasSentry
|
|
76
|
+
? (c) =>
|
|
77
|
+
withSentryConfig(
|
|
78
|
+
c,
|
|
79
|
+
{
|
|
80
|
+
// For all available options, see:
|
|
81
|
+
// https://github.com/getsentry/sentry-webpack-plugin#options
|
|
82
|
+
|
|
83
|
+
// Suppresses source map uploading logs during build
|
|
84
|
+
silent: true,
|
|
85
|
+
org: process.env.SENTRY_ORG,
|
|
86
|
+
project: process.env.SENTRY_PROJECT,
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
// For all available options, see:
|
|
90
|
+
// https://docs.sentry.io/platforms/javascript/guides/nextjs/manual-setup/
|
|
91
|
+
|
|
92
|
+
// Upload a larger set of source maps for prettier stack traces (increases build time)
|
|
93
|
+
widenClientFileUpload: true,
|
|
94
|
+
|
|
95
|
+
// Transpiles SDK to be compatible with IE11 (increases bundle size)
|
|
96
|
+
transpileClientSDK: true,
|
|
97
|
+
|
|
98
|
+
// Routes browser requests to Sentry through a Next.js rewrite to circumvent ad-blockers. (increases server load)
|
|
99
|
+
// Note: Check that the configured route will not match with your Next.js middleware, otherwise reporting of client-
|
|
100
|
+
// side errors will fail.
|
|
101
|
+
tunnelRoute: '/monitoring',
|
|
102
|
+
|
|
103
|
+
// Hides source maps from generated client bundles
|
|
104
|
+
hideSourceMaps: true,
|
|
105
|
+
|
|
106
|
+
// Automatically tree-shake Sentry logger statements to reduce bundle size
|
|
107
|
+
disableLogger: true,
|
|
108
|
+
|
|
109
|
+
// Enables automatic instrumentation of Vercel Cron Monitors.
|
|
110
|
+
// See the following for more information:
|
|
111
|
+
// https://docs.sentry.io/product/crons/
|
|
112
|
+
// https://vercel.com/docs/cron-jobs
|
|
113
|
+
automaticVercelMonitors: true,
|
|
114
|
+
},
|
|
115
|
+
)
|
|
116
|
+
: noWrapper;
|
|
117
|
+
|
|
118
|
+
export default withBundleAnalyzer(withPWA(withSentry(nextConfig)));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lobehub/chat",
|
|
3
|
-
"version": "0.147.
|
|
3
|
+
"version": "0.147.17",
|
|
4
4
|
"description": "Lobe Chat - an open-source, high-performance chatbot framework that supports speech synthesis, multimodal, and extensible Function Call plugin system. Supports one-click free deployment of your private ChatGPT/LLM web application.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"framework",
|
|
@@ -94,6 +94,7 @@
|
|
|
94
94
|
"@lobehub/tts": "latest",
|
|
95
95
|
"@lobehub/ui": "^1.137.7",
|
|
96
96
|
"@next/third-parties": "^14.1.4",
|
|
97
|
+
"@sentry/nextjs": "^7.105.0",
|
|
97
98
|
"@vercel/analytics": "^1.2.2",
|
|
98
99
|
"@vercel/speed-insights": "^1.0.10",
|
|
99
100
|
"ahooks": "^3.7.11",
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// This file configures the initialization of Sentry on the client.
|
|
2
|
+
// The config you add here will be used whenever a users loads a page in their browser.
|
|
3
|
+
// https://docs.sentry.io/platforms/javascript/guides/nextjs/
|
|
4
|
+
import * as Sentry from '@sentry/nextjs';
|
|
5
|
+
|
|
6
|
+
if (!!process.env.NEXT_PUBLIC_SENTRY_DSN) {
|
|
7
|
+
Sentry.init({
|
|
8
|
+
// Setting this option to true will print useful information to the console while you're setting up Sentry.
|
|
9
|
+
debug: false,
|
|
10
|
+
|
|
11
|
+
dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
|
|
12
|
+
// You can remove this option if you're not planning to use the Sentry Session Replay feature:
|
|
13
|
+
integrations: [
|
|
14
|
+
Sentry.replayIntegration({
|
|
15
|
+
blockAllMedia: true,
|
|
16
|
+
// Additional Replay configuration goes in here, for example:
|
|
17
|
+
maskAllText: true,
|
|
18
|
+
}),
|
|
19
|
+
],
|
|
20
|
+
|
|
21
|
+
replaysOnErrorSampleRate: 1,
|
|
22
|
+
|
|
23
|
+
// This sets the sample rate to be 10%. You may want this to be 100% while
|
|
24
|
+
// in development and sample at a lower rate in production
|
|
25
|
+
replaysSessionSampleRate: 0.1,
|
|
26
|
+
|
|
27
|
+
// Adjust this value in production, or use tracesSampler for greater control
|
|
28
|
+
tracesSampleRate: 1,
|
|
29
|
+
});
|
|
30
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// This file configures the initialization of Sentry for edge features (middleware, edge routes, and so on).
|
|
2
|
+
// The config you add here will be used whenever one of the edge features is loaded.
|
|
3
|
+
// Note that this config is unrelated to the Vercel Edge Runtime and is also required when running locally.
|
|
4
|
+
// https://docs.sentry.io/platforms/javascript/guides/nextjs/
|
|
5
|
+
import * as Sentry from '@sentry/nextjs';
|
|
6
|
+
|
|
7
|
+
if (!!process.env.NEXT_PUBLIC_SENTRY_DSN) {
|
|
8
|
+
Sentry.init({
|
|
9
|
+
// Setting this option to true will print useful information to the console while you're setting up Sentry.
|
|
10
|
+
debug: false,
|
|
11
|
+
|
|
12
|
+
dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
|
|
13
|
+
|
|
14
|
+
// Adjust this value in production, or use tracesSampler for greater control
|
|
15
|
+
tracesSampleRate: 1,
|
|
16
|
+
});
|
|
17
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// This file configures the initialization of Sentry on the server.
|
|
2
|
+
// The config you add here will be used whenever the server handles a request.
|
|
3
|
+
// https://docs.sentry.io/platforms/javascript/guides/nextjs/
|
|
4
|
+
import * as Sentry from '@sentry/nextjs';
|
|
5
|
+
|
|
6
|
+
if (!!process.env.NEXT_PUBLIC_SENTRY_DSN) {
|
|
7
|
+
Sentry.init({
|
|
8
|
+
// Setting this option to true will print useful information to the console while you're setting up Sentry.
|
|
9
|
+
debug: false,
|
|
10
|
+
|
|
11
|
+
dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
|
|
12
|
+
|
|
13
|
+
// Adjust this value in production, or use tracesSampler for greater control
|
|
14
|
+
tracesSampleRate: 1,
|
|
15
|
+
|
|
16
|
+
// uncomment the line below to enable Spotlight (https://spotlightjs.com)
|
|
17
|
+
// spotlight: process.env.NODE_ENV === 'development',
|
|
18
|
+
});
|
|
19
|
+
}
|
|
@@ -56,7 +56,11 @@ const useStyles = createStyles(({ css, prefixCls, token }) => {
|
|
|
56
56
|
|
|
57
57
|
const isMac = isMacOS();
|
|
58
58
|
|
|
59
|
-
|
|
59
|
+
interface FooterProps {
|
|
60
|
+
setExpand?: (expand: boolean) => void;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const Footer = memo<FooterProps>(({ setExpand }) => {
|
|
60
64
|
const { t } = useTranslation('chat');
|
|
61
65
|
|
|
62
66
|
const { theme, styles } = useStyles();
|
|
@@ -193,4 +197,6 @@ const Footer = memo<{ setExpand?: (expand: boolean) => void }>(({ setExpand }) =
|
|
|
193
197
|
);
|
|
194
198
|
});
|
|
195
199
|
|
|
200
|
+
Footer.displayName = 'Footer';
|
|
201
|
+
|
|
196
202
|
export default Footer;
|
|
@@ -31,7 +31,11 @@ const useStyles = createStyles(({ css }) => {
|
|
|
31
31
|
};
|
|
32
32
|
});
|
|
33
33
|
|
|
34
|
-
|
|
34
|
+
interface InputAreaProps {
|
|
35
|
+
setExpand?: (expand: boolean) => void;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const InputArea = memo<InputAreaProps>(({ setExpand }) => {
|
|
35
39
|
const { t } = useTranslation('chat');
|
|
36
40
|
const { styles } = useStyles();
|
|
37
41
|
const ref = useRef<TextAreaRef>(null);
|
|
@@ -119,4 +123,6 @@ const InputArea = memo<{ setExpand?: (expand: boolean) => void }>(({ setExpand }
|
|
|
119
123
|
);
|
|
120
124
|
});
|
|
121
125
|
|
|
126
|
+
InputArea.displayName = 'InputArea';
|
|
127
|
+
|
|
122
128
|
export default InputArea;
|
|
@@ -8,8 +8,8 @@ import { sessionService } from '@/services/session';
|
|
|
8
8
|
|
|
9
9
|
const checkHasConversation = async () => {
|
|
10
10
|
const hasMessages = await messageService.hasMessages();
|
|
11
|
-
const hasAgents = await sessionService.
|
|
12
|
-
return hasMessages || hasAgents;
|
|
11
|
+
const hasAgents = await sessionService.countSessions();
|
|
12
|
+
return hasMessages || hasAgents === 0;
|
|
13
13
|
};
|
|
14
14
|
|
|
15
15
|
const Redirect = memo(() => {
|
package/src/app/layout.tsx
CHANGED
|
@@ -7,8 +7,8 @@ import { isRtlLang } from 'rtl-detect';
|
|
|
7
7
|
import Analytics from '@/components/Analytics';
|
|
8
8
|
import { DEFAULT_LANG, LOBE_LOCALE_COOKIE } from '@/const/locale';
|
|
9
9
|
import AuthProvider from '@/layout/AuthProvider';
|
|
10
|
-
import GlobalLayout from '@/layout/GlobalLayout';
|
|
11
10
|
import GlobalProvider from '@/layout/GlobalProvider';
|
|
11
|
+
import LayoutRoutes from '@/layout/routes';
|
|
12
12
|
import { isMobileDevice } from '@/utils/responsive';
|
|
13
13
|
|
|
14
14
|
const RootLayout = async ({ children }: PropsWithChildren) => {
|
|
@@ -22,7 +22,7 @@ const RootLayout = async ({ children }: PropsWithChildren) => {
|
|
|
22
22
|
<body>
|
|
23
23
|
<GlobalProvider>
|
|
24
24
|
<AuthProvider>
|
|
25
|
-
<
|
|
25
|
+
<LayoutRoutes>{children}</LayoutRoutes>
|
|
26
26
|
</AuthProvider>
|
|
27
27
|
</GlobalProvider>
|
|
28
28
|
<Analytics />
|
package/src/config/server/app.ts
CHANGED
|
@@ -57,24 +57,6 @@ export const getAppConfig = () => {
|
|
|
57
57
|
|
|
58
58
|
PLUGIN_SETTINGS: process.env.PLUGIN_SETTINGS,
|
|
59
59
|
|
|
60
|
-
ENABLE_OAUTH_SSO: !!process.env.ENABLE_OAUTH_SSO,
|
|
61
|
-
SSO_PROVIDERS: process.env.SSO_PROVIDERS || 'auth0',
|
|
62
|
-
AUTH0_CLIENT_ID: process.env.AUTH0_CLIENT_ID || '',
|
|
63
|
-
AUTH0_CLIENT_SECRET: process.env.AUTH0_CLIENT_SECRET || '',
|
|
64
|
-
AUTH0_ISSUER: process.env.AUTH0_ISSUER || '',
|
|
65
|
-
GITHUB_CLIENT_ID: process.env.GITHUB_CLIENT_ID || '',
|
|
66
|
-
GITHUB_CLIENT_SECRET: process.env.GITHUB_CLIENT_SECRET || '',
|
|
67
|
-
AZURE_AD_CLIENT_ID: process.env.AZURE_AD_CLIENT_ID || '',
|
|
68
|
-
AZURE_AD_CLIENT_SECRET: process.env.AZURE_AD_CLIENT_SECRET || '',
|
|
69
|
-
AZURE_AD_TENANT_ID: process.env.AZURE_AD_TENANT_ID || '',
|
|
70
|
-
AUTHENTIK_CLIENT_ID: process.env.AUTHENTIK_CLIENT_ID || '',
|
|
71
|
-
AUTHENTIK_CLIENT_SECRET: process.env.AUTHENTIK_CLIENT_SECRET || '',
|
|
72
|
-
AUTHENTIK_ISSUER: process.env.AUTHENTIK_ISSUER || '',
|
|
73
|
-
ZITADEL_CLIENT_ID: process.env.ZITADEL_CLIENT_ID || '',
|
|
74
|
-
ZITADEL_CLIENT_SECRET: process.env.ZITADEL_CLIENT_SECRET || '',
|
|
75
|
-
ZITADEL_ISSUER: process.env.ZITADEL_ISSUER || '',
|
|
76
|
-
NEXTAUTH_SECRET: process.env.NEXTAUTH_SECRET || '',
|
|
77
|
-
|
|
78
60
|
ENABLE_LANGFUSE: process.env.ENABLE_LANGFUSE === '1',
|
|
79
61
|
LANGFUSE_SECRET_KEY: process.env.LANGFUSE_SECRET_KEY || '',
|
|
80
62
|
LANGFUSE_PUBLIC_KEY: process.env.LANGFUSE_PUBLIC_KEY || '',
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/* eslint-disable sort-keys-fix/sort-keys-fix , typescript-sort-keys/interface */
|
|
2
|
+
|
|
3
|
+
declare global {
|
|
4
|
+
// eslint-disable-next-line @typescript-eslint/no-namespace
|
|
5
|
+
namespace NodeJS {
|
|
6
|
+
interface ProcessEnv {
|
|
7
|
+
ENABLE_OAUTH_SSO?: string;
|
|
8
|
+
SSO_PROVIDERS?: string;
|
|
9
|
+
|
|
10
|
+
AUTH0_CLIENT_ID?: string;
|
|
11
|
+
AUTH0_CLIENT_SECRET?: string;
|
|
12
|
+
AUTH0_ISSUER?: string;
|
|
13
|
+
|
|
14
|
+
// Github
|
|
15
|
+
GITHUB_CLIENT_ID?: string;
|
|
16
|
+
GITHUB_CLIENT_SECRET?: string;
|
|
17
|
+
|
|
18
|
+
// Azure AD
|
|
19
|
+
AZURE_AD_CLIENT_ID?: string;
|
|
20
|
+
AZURE_AD_CLIENT_SECRET?: string;
|
|
21
|
+
AZURE_AD_TENANT_ID?: string;
|
|
22
|
+
|
|
23
|
+
// AUTHENTIK
|
|
24
|
+
AUTHENTIK_CLIENT_ID?: string;
|
|
25
|
+
AUTHENTIK_CLIENT_SECRET?: string;
|
|
26
|
+
AUTHENTIK_ISSUER?: string;
|
|
27
|
+
|
|
28
|
+
// ZITADEL
|
|
29
|
+
ZITADEL_CLIENT_ID?: string;
|
|
30
|
+
ZITADEL_CLIENT_SECRET?: string;
|
|
31
|
+
ZITADEL_ISSUER?: string;
|
|
32
|
+
NEXTAUTH_SECRET?: string;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export const getAuthConfig = () => {
|
|
38
|
+
if (typeof process === 'undefined') {
|
|
39
|
+
throw new Error('[Server Config] you are importing a server-only module outside of server');
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return {
|
|
43
|
+
ENABLE_OAUTH_SSO: !!process.env.ENABLE_OAUTH_SSO,
|
|
44
|
+
SSO_PROVIDERS: process.env.SSO_PROVIDERS || 'auth0',
|
|
45
|
+
|
|
46
|
+
// Auth0
|
|
47
|
+
AUTH0_CLIENT_ID: process.env.AUTH0_CLIENT_ID || '',
|
|
48
|
+
AUTH0_CLIENT_SECRET: process.env.AUTH0_CLIENT_SECRET || '',
|
|
49
|
+
AUTH0_ISSUER: process.env.AUTH0_ISSUER || '',
|
|
50
|
+
|
|
51
|
+
// Github
|
|
52
|
+
GITHUB_CLIENT_ID: process.env.GITHUB_CLIENT_ID || '',
|
|
53
|
+
GITHUB_CLIENT_SECRET: process.env.GITHUB_CLIENT_SECRET || '',
|
|
54
|
+
|
|
55
|
+
// Azure AD
|
|
56
|
+
AZURE_AD_CLIENT_ID: process.env.AZURE_AD_CLIENT_ID || '',
|
|
57
|
+
AZURE_AD_CLIENT_SECRET: process.env.AZURE_AD_CLIENT_SECRET || '',
|
|
58
|
+
AZURE_AD_TENANT_ID: process.env.AZURE_AD_TENANT_ID || '',
|
|
59
|
+
|
|
60
|
+
// AUTHENTIK
|
|
61
|
+
AUTHENTIK_CLIENT_ID: process.env.AUTHENTIK_CLIENT_ID || '',
|
|
62
|
+
AUTHENTIK_CLIENT_SECRET: process.env.AUTHENTIK_CLIENT_SECRET || '',
|
|
63
|
+
AUTHENTIK_ISSUER: process.env.AUTHENTIK_ISSUER || '',
|
|
64
|
+
|
|
65
|
+
// ZITADEL
|
|
66
|
+
ZITADEL_CLIENT_ID: process.env.ZITADEL_CLIENT_ID || '',
|
|
67
|
+
ZITADEL_CLIENT_SECRET: process.env.ZITADEL_CLIENT_SECRET || '',
|
|
68
|
+
ZITADEL_ISSUER: process.env.ZITADEL_ISSUER || '',
|
|
69
|
+
NEXTAUTH_SECRET: process.env.NEXTAUTH_SECRET || '',
|
|
70
|
+
};
|
|
71
|
+
};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { getAnalyticsConfig } from './analytics';
|
|
2
2
|
import { getAppConfig } from './app';
|
|
3
|
+
import { getAuthConfig } from './auth';
|
|
3
4
|
import { getProviderConfig } from './provider';
|
|
4
5
|
|
|
5
6
|
export const getServerConfig = () => {
|
|
@@ -9,7 +10,8 @@ export const getServerConfig = () => {
|
|
|
9
10
|
|
|
10
11
|
const provider = getProviderConfig();
|
|
11
12
|
const app = getAppConfig();
|
|
13
|
+
const auth = getAuthConfig();
|
|
12
14
|
const analytics = getAnalyticsConfig();
|
|
13
15
|
|
|
14
|
-
return { ...provider, ...app, ...analytics };
|
|
16
|
+
return { ...provider, ...app, ...analytics, ...auth };
|
|
15
17
|
};
|
|
@@ -111,12 +111,10 @@ describe('SessionModel', () => {
|
|
|
111
111
|
|
|
112
112
|
expect(updatedSession).toHaveProperty('group', 'newGroup');
|
|
113
113
|
});
|
|
114
|
-
});
|
|
115
114
|
|
|
116
|
-
describe('updatePinned', () => {
|
|
117
115
|
it('should update pinned status of a session', async () => {
|
|
118
116
|
const createdSession = await SessionModel.create('agent', sessionData);
|
|
119
|
-
await SessionModel.
|
|
117
|
+
await SessionModel.update(createdSession.id, { pinned: 1 });
|
|
120
118
|
const updatedSession = await SessionModel.findById(createdSession.id);
|
|
121
119
|
expect(updatedSession).toHaveProperty('pinned', 1);
|
|
122
120
|
});
|
|
@@ -171,6 +171,10 @@ class _SessionModel extends BaseModel {
|
|
|
171
171
|
return (await this.table.count()) === 0;
|
|
172
172
|
}
|
|
173
173
|
|
|
174
|
+
async count() {
|
|
175
|
+
return this.table.count();
|
|
176
|
+
}
|
|
177
|
+
|
|
174
178
|
// **************** Create *************** //
|
|
175
179
|
|
|
176
180
|
async create(type: 'agent' | 'group', defaultValue: Partial<LobeAgentSession>, id = uuid()) {
|
|
@@ -238,10 +242,6 @@ class _SessionModel extends BaseModel {
|
|
|
238
242
|
return super._updateWithSync(id, data);
|
|
239
243
|
}
|
|
240
244
|
|
|
241
|
-
async updatePinned(id: string, pinned: boolean) {
|
|
242
|
-
return this.update(id, { pinned: pinned ? 1 : 0 });
|
|
243
|
-
}
|
|
244
|
-
|
|
245
245
|
async updateConfig(id: string, data: DeepPartial<LobeAgentConfig>) {
|
|
246
246
|
const session = await this.findById(id);
|
|
247
247
|
if (!session) return;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { SessionProvider } from 'next-auth/react';
|
|
2
|
+
import { PropsWithChildren } from 'react';
|
|
3
|
+
|
|
4
|
+
import { API_ENDPOINTS } from '@/services/_url';
|
|
5
|
+
|
|
6
|
+
const NextAuth = ({ children }: PropsWithChildren) => {
|
|
7
|
+
return <SessionProvider basePath={API_ENDPOINTS.oauth}>{children}</SessionProvider>;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export default NextAuth;
|
|
@@ -1,16 +1,12 @@
|
|
|
1
|
-
import { SessionProvider } from 'next-auth/react';
|
|
2
1
|
import { PropsWithChildren } from 'react';
|
|
3
2
|
|
|
4
3
|
import { getServerConfig } from '@/config/server';
|
|
5
|
-
|
|
4
|
+
|
|
5
|
+
import NextAuth from './NextAuth';
|
|
6
6
|
|
|
7
7
|
const { ENABLE_OAUTH_SSO = false } = getServerConfig();
|
|
8
8
|
|
|
9
9
|
const AuthProvider = ({ children }: PropsWithChildren) =>
|
|
10
|
-
ENABLE_OAUTH_SSO ?
|
|
11
|
-
<SessionProvider basePath={API_ENDPOINTS.oauth}>{children}</SessionProvider>
|
|
12
|
-
) : (
|
|
13
|
-
children
|
|
14
|
-
);
|
|
10
|
+
ENABLE_OAUTH_SSO ? <NextAuth>{children}</NextAuth> : children;
|
|
15
11
|
|
|
16
12
|
export default AuthProvider;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { SideNav } from '@lobehub/ui';
|
|
2
2
|
import { memo } from 'react';
|
|
3
3
|
|
|
4
|
-
import AvatarWithUpload from '@/features/AvatarWithUpload';
|
|
5
4
|
import { SidebarTabKey } from '@/store/global/initialState';
|
|
6
5
|
|
|
6
|
+
import Avatar from './Avatar';
|
|
7
7
|
import BottomActions from './BottomActions';
|
|
8
8
|
import TopActions from './TopActions';
|
|
9
9
|
|
|
@@ -14,7 +14,7 @@ interface Props {
|
|
|
14
14
|
export default memo<Props>(({ sidebarKey }) => {
|
|
15
15
|
return (
|
|
16
16
|
<SideNav
|
|
17
|
-
avatar={<
|
|
17
|
+
avatar={<Avatar />}
|
|
18
18
|
bottomActions={<BottomActions tab={sidebarKey} />}
|
|
19
19
|
style={{ height: '100%' }}
|
|
20
20
|
topActions={<TopActions tab={sidebarKey} />}
|