@lobehub/chat 1.49.11 → 1.49.12
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 +25 -0
- package/changelog/v1.json +9 -0
- package/package.json +1 -1
- package/src/app/(main)/chat/(workspace)/@portal/_layout/Mobile.tsx +1 -0
- package/src/app/(main)/chat/(workspace)/_layout/Desktop/Portal.tsx +26 -2
- package/src/components/Thinking/index.tsx +14 -16
- package/src/config/modelProviders/siliconcloud.ts +2 -2
- package/src/features/Conversation/components/MarkdownElements/LobeThinking/Render.tsx +7 -58
- package/src/libs/agent-runtime/siliconcloud/index.ts +33 -1
- package/src/store/chat/slices/aiChat/actions/__tests__/generateAIChat.test.ts +10 -10
- package/src/store/chat/slices/aiChat/actions/generateAIChat.ts +4 -3
- package/src/store/chat/slices/aiChat/initialState.ts +1 -1
- package/src/store/chat/slices/message/action.ts +4 -3
- package/src/store/global/initialState.ts +2 -0
- package/src/store/global/selectors.ts +2 -0
package/CHANGELOG.md
CHANGED
@@ -2,6 +2,31 @@
|
|
2
2
|
|
3
3
|
# Changelog
|
4
4
|
|
5
|
+
### [Version 1.49.12](https://github.com/lobehub/lobe-chat/compare/v1.49.11...v1.49.12)
|
6
|
+
|
7
|
+
<sup>Released on **2025-02-02**</sup>
|
8
|
+
|
9
|
+
#### 🐛 Bug Fixes
|
10
|
+
|
11
|
+
- **misc**: Fix can not stop generating.
|
12
|
+
|
13
|
+
<br/>
|
14
|
+
|
15
|
+
<details>
|
16
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
17
|
+
|
18
|
+
#### What's fixed
|
19
|
+
|
20
|
+
- **misc**: Fix can not stop generating, closes [#5671](https://github.com/lobehub/lobe-chat/issues/5671) ([ae39c35](https://github.com/lobehub/lobe-chat/commit/ae39c35))
|
21
|
+
|
22
|
+
</details>
|
23
|
+
|
24
|
+
<div align="right">
|
25
|
+
|
26
|
+
[](#readme-top)
|
27
|
+
|
28
|
+
</div>
|
29
|
+
|
5
30
|
### [Version 1.49.11](https://github.com/lobehub/lobe-chat/compare/v1.49.10...v1.49.11)
|
6
31
|
|
7
32
|
<sup>Released on **2025-02-02**</sup>
|
package/changelog/v1.json
CHANGED
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@lobehub/chat",
|
3
|
-
"version": "1.49.
|
3
|
+
"version": "1.49.12",
|
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",
|
@@ -1,9 +1,10 @@
|
|
1
1
|
'use client';
|
2
2
|
|
3
|
-
import { DraggablePanel, DraggablePanelContainer } from '@lobehub/ui';
|
3
|
+
import { DraggablePanel, DraggablePanelContainer, type DraggablePanelProps } from '@lobehub/ui';
|
4
4
|
import { createStyles, useResponsive } from 'antd-style';
|
5
|
+
import isEqual from 'fast-deep-equal';
|
5
6
|
import { rgba } from 'polished';
|
6
|
-
import { PropsWithChildren, memo } from 'react';
|
7
|
+
import { PropsWithChildren, memo, useState } from 'react';
|
7
8
|
import { Flexbox } from 'react-layout-kit';
|
8
9
|
|
9
10
|
import {
|
@@ -13,6 +14,8 @@ import {
|
|
13
14
|
} from '@/const/layoutTokens';
|
14
15
|
import { useChatStore } from '@/store/chat';
|
15
16
|
import { chatPortalSelectors, portalThreadSelectors } from '@/store/chat/selectors';
|
17
|
+
import { useGlobalStore } from '@/store/global';
|
18
|
+
import { systemStatusSelectors } from '@/store/global/selectors';
|
16
19
|
|
17
20
|
const useStyles = createStyles(({ css, token, isDarkMode }) => ({
|
18
21
|
content: css`
|
@@ -49,6 +52,24 @@ const PortalPanel = memo(({ children }: PropsWithChildren) => {
|
|
49
52
|
portalThreadSelectors.showThread(s),
|
50
53
|
]);
|
51
54
|
|
55
|
+
const [portalWidth, updateSystemStatus] = useGlobalStore((s) => [
|
56
|
+
systemStatusSelectors.portalWidth(s),
|
57
|
+
s.updateSystemStatus,
|
58
|
+
]);
|
59
|
+
|
60
|
+
const [tmpWidth, setWidth] = useState(portalWidth);
|
61
|
+
if (tmpWidth !== portalWidth) setWidth(portalWidth);
|
62
|
+
|
63
|
+
const handleSizeChange: DraggablePanelProps['onSizeChange'] = (_, size) => {
|
64
|
+
if (!size) return;
|
65
|
+
const nextWidth = typeof size.width === 'string' ? Number.parseInt(size.width) : size.width;
|
66
|
+
if (!nextWidth) return;
|
67
|
+
|
68
|
+
if (isEqual(nextWidth, portalWidth)) return;
|
69
|
+
setWidth(nextWidth);
|
70
|
+
updateSystemStatus({ portalWidth: nextWidth });
|
71
|
+
};
|
72
|
+
|
52
73
|
return (
|
53
74
|
showInspector && (
|
54
75
|
<DraggablePanel
|
@@ -56,6 +77,7 @@ const PortalPanel = memo(({ children }: PropsWithChildren) => {
|
|
56
77
|
classNames={{
|
57
78
|
content: styles.content,
|
58
79
|
}}
|
80
|
+
defaultSize={{ width: tmpWidth }}
|
59
81
|
expand
|
60
82
|
hanlderStyle={{ display: 'none' }}
|
61
83
|
maxWidth={CHAT_PORTAL_MAX_WIDTH}
|
@@ -63,9 +85,11 @@ const PortalPanel = memo(({ children }: PropsWithChildren) => {
|
|
63
85
|
showArtifactUI || showToolUI || showThread ? CHAT_PORTAL_TOOL_UI_WIDTH : CHAT_PORTAL_WIDTH
|
64
86
|
}
|
65
87
|
mode={md ? 'fixed' : 'float'}
|
88
|
+
onSizeChange={handleSizeChange}
|
66
89
|
placement={'right'}
|
67
90
|
showHandlerWhenUnexpand={false}
|
68
91
|
showHandlerWideArea={false}
|
92
|
+
size={{ height: '100%', width: portalWidth }}
|
69
93
|
>
|
70
94
|
<DraggablePanelContainer
|
71
95
|
style={{
|
@@ -3,7 +3,7 @@ import { createStyles } from 'antd-style';
|
|
3
3
|
import { AnimatePresence, motion } from 'framer-motion';
|
4
4
|
import { AtomIcon, ChevronDown, ChevronRight } from 'lucide-react';
|
5
5
|
import { rgba } from 'polished';
|
6
|
-
import { memo, useEffect, useState } from 'react';
|
6
|
+
import { CSSProperties, memo, useEffect, useState } from 'react';
|
7
7
|
import { useTranslation } from 'react-i18next';
|
8
8
|
import { Flexbox } from 'react-layout-kit';
|
9
9
|
|
@@ -61,30 +61,26 @@ const useStyles = createStyles(({ css, token, isDarkMode }) => ({
|
|
61
61
|
interface ThinkingProps {
|
62
62
|
content?: string;
|
63
63
|
duration?: number;
|
64
|
+
style?: CSSProperties;
|
64
65
|
thinking?: boolean;
|
65
66
|
}
|
66
67
|
|
67
|
-
const Thinking = memo<ThinkingProps>(({ content, duration, thinking }) => {
|
68
|
+
const Thinking = memo<ThinkingProps>(({ content, duration, thinking, style }) => {
|
68
69
|
const { t } = useTranslation(['components', 'common']);
|
69
70
|
const { styles, cx } = useStyles();
|
70
71
|
|
71
72
|
const [showDetail, setShowDetail] = useState(false);
|
72
73
|
|
73
74
|
useEffect(() => {
|
74
|
-
|
75
|
-
|
76
|
-
}
|
77
|
-
|
78
|
-
if (!thinking) {
|
79
|
-
setShowDetail(false);
|
80
|
-
}
|
81
|
-
}, [thinking, content]);
|
75
|
+
setShowDetail(!!thinking);
|
76
|
+
}, [thinking]);
|
82
77
|
|
83
78
|
return (
|
84
|
-
<Flexbox className={cx(styles.container, showDetail && styles.expand)} gap={16}>
|
79
|
+
<Flexbox className={cx(styles.container, showDetail && styles.expand)} gap={16} style={style}>
|
85
80
|
<Flexbox
|
86
81
|
distribution={'space-between'}
|
87
82
|
flex={1}
|
83
|
+
gap={8}
|
88
84
|
horizontal
|
89
85
|
onClick={() => {
|
90
86
|
setShowDetail(!showDetail);
|
@@ -92,18 +88,20 @@ const Thinking = memo<ThinkingProps>(({ content, duration, thinking }) => {
|
|
92
88
|
style={{ cursor: 'pointer' }}
|
93
89
|
>
|
94
90
|
{thinking ? (
|
95
|
-
<Flexbox gap={8} horizontal>
|
91
|
+
<Flexbox align={'center'} gap={8} horizontal>
|
96
92
|
<Icon icon={AtomIcon} />
|
97
93
|
<Flexbox className={styles.shinyText} horizontal>
|
98
94
|
{t('Thinking.thinking')}
|
99
95
|
</Flexbox>
|
100
96
|
</Flexbox>
|
101
97
|
) : (
|
102
|
-
<Flexbox gap={8} horizontal>
|
98
|
+
<Flexbox align={'center'} gap={8} horizontal>
|
103
99
|
<Icon icon={AtomIcon} />
|
104
|
-
|
105
|
-
|
106
|
-
|
100
|
+
<Flexbox>
|
101
|
+
{!duration
|
102
|
+
? t('Thinking.thoughtWithDuration')
|
103
|
+
: t('Thinking.thought', { duration: ((duration || 0) / 1000).toFixed(1) })}
|
104
|
+
</Flexbox>
|
107
105
|
</Flexbox>
|
108
106
|
)}
|
109
107
|
<Flexbox gap={4} horizontal>
|
@@ -1,6 +1,6 @@
|
|
1
1
|
import { ModelProviderCard } from '@/types/llm';
|
2
2
|
|
3
|
-
// ref
|
3
|
+
// ref: https://siliconflow.cn/zh-cn/pricing
|
4
4
|
const SiliconCloud: ModelProviderCard = {
|
5
5
|
chatModels: [
|
6
6
|
{
|
@@ -582,7 +582,7 @@ const SiliconCloud: ModelProviderCard = {
|
|
582
582
|
vision: true,
|
583
583
|
},
|
584
584
|
],
|
585
|
-
checkModel: 'Qwen/Qwen2.
|
585
|
+
checkModel: 'Pro/Qwen/Qwen2-1.5B-Instruct',
|
586
586
|
description: 'SiliconCloud,基于优秀开源基础模型的高性价比 GenAI 云服务',
|
587
587
|
id: 'siliconcloud',
|
588
588
|
modelList: { showModelFetcher: true },
|
@@ -1,14 +1,9 @@
|
|
1
|
-
import {
|
2
|
-
import { createStyles } from 'antd-style';
|
3
|
-
import { BringToFrontIcon, ChevronDown, ChevronRight, Loader2Icon } from 'lucide-react';
|
4
|
-
import { memo, useState } from 'react';
|
5
|
-
import { useTranslation } from 'react-i18next';
|
6
|
-
import { Flexbox } from 'react-layout-kit';
|
1
|
+
import { memo } from 'react';
|
7
2
|
|
3
|
+
import Thinking from '@/components/Thinking';
|
8
4
|
import { ARTIFACT_THINKING_TAG } from '@/const/plugin';
|
9
5
|
import { useChatStore } from '@/store/chat';
|
10
6
|
import { chatSelectors } from '@/store/chat/selectors';
|
11
|
-
import { dotLoading } from '@/styles/loading';
|
12
7
|
|
13
8
|
import { MarkdownElementProps } from '../type';
|
14
9
|
|
@@ -22,64 +17,18 @@ export const isLobeThinkingClosed = (input: string = '') => {
|
|
22
17
|
return input.includes(openTag) && input.includes(closeTag);
|
23
18
|
};
|
24
19
|
|
25
|
-
const useStyles = createStyles(({ css, token }) => ({
|
26
|
-
container: css`
|
27
|
-
cursor: pointer;
|
28
|
-
|
29
|
-
padding-block: 8px;
|
30
|
-
padding-inline: 12px;
|
31
|
-
padding-inline-end: 12px;
|
32
|
-
border-radius: 8px;
|
33
|
-
|
34
|
-
color: ${token.colorText};
|
35
|
-
|
36
|
-
background: ${token.colorFillQuaternary};
|
37
|
-
`,
|
38
|
-
title: css`
|
39
|
-
overflow: hidden;
|
40
|
-
display: -webkit-box;
|
41
|
-
-webkit-box-orient: vertical;
|
42
|
-
-webkit-line-clamp: 1;
|
43
|
-
|
44
|
-
font-size: 12px;
|
45
|
-
text-overflow: ellipsis;
|
46
|
-
`,
|
47
|
-
}));
|
48
|
-
|
49
20
|
const Render = memo<MarkdownElementProps>(({ children, id }) => {
|
50
|
-
const { t } = useTranslation('chat');
|
51
|
-
const { styles, cx } = useStyles();
|
52
|
-
|
53
21
|
const [isGenerating] = useChatStore((s) => {
|
54
22
|
const message = chatSelectors.getMessageById(id)(s);
|
55
23
|
return [!isLobeThinkingClosed(message?.content)];
|
56
24
|
});
|
57
25
|
|
58
|
-
const [showDetail, setShowDetail] = useState(false);
|
59
|
-
|
60
|
-
const expand = showDetail || isGenerating;
|
61
26
|
return (
|
62
|
-
<
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
}}
|
68
|
-
width={'100%'}
|
69
|
-
>
|
70
|
-
<Flexbox distribution={'space-between'} flex={1} horizontal>
|
71
|
-
<Flexbox gap={8} horizontal>
|
72
|
-
<Icon icon={isGenerating ? Loader2Icon : BringToFrontIcon} spin={isGenerating} />
|
73
|
-
{isGenerating ? (
|
74
|
-
<span className={cx(dotLoading)}>{t('artifact.thinking')}</span>
|
75
|
-
) : (
|
76
|
-
t('artifact.thought')
|
77
|
-
)}
|
78
|
-
</Flexbox>
|
79
|
-
<Icon icon={expand ? ChevronDown : ChevronRight} />
|
80
|
-
</Flexbox>
|
81
|
-
{expand && children}
|
82
|
-
</Flexbox>
|
27
|
+
<Thinking
|
28
|
+
content={children as string}
|
29
|
+
style={{ width: isGenerating ? '100%' : undefined }}
|
30
|
+
thinking={isGenerating}
|
31
|
+
/>
|
83
32
|
);
|
84
33
|
});
|
85
34
|
|
@@ -1,4 +1,5 @@
|
|
1
|
-
import {
|
1
|
+
import { AgentRuntimeErrorType } from '../error';
|
2
|
+
import { ChatCompletionErrorPayload, ModelProvider } from '../types';
|
2
3
|
import { LobeOpenAICompatibleFactory } from '../utils/openaiCompatibleFactory';
|
3
4
|
|
4
5
|
import { LOBE_DEFAULT_MODEL_LIST } from '@/config/aiModels';
|
@@ -10,6 +11,33 @@ export interface SiliconCloudModelCard {
|
|
10
11
|
export const LobeSiliconCloudAI = LobeOpenAICompatibleFactory({
|
11
12
|
baseURL: 'https://api.siliconflow.cn/v1',
|
12
13
|
chatCompletion: {
|
14
|
+
handleError: (error: any): Omit<ChatCompletionErrorPayload, 'provider'> | undefined => {
|
15
|
+
let errorResponse: Response | undefined;
|
16
|
+
if (error instanceof Response) {
|
17
|
+
errorResponse = error;
|
18
|
+
} else if ('status' in (error as any)) {
|
19
|
+
errorResponse = error as Response;
|
20
|
+
}
|
21
|
+
if (errorResponse) {
|
22
|
+
if (errorResponse.status === 401) {
|
23
|
+
return {
|
24
|
+
error: errorResponse.status,
|
25
|
+
errorType: AgentRuntimeErrorType.InvalidProviderAPIKey,
|
26
|
+
};
|
27
|
+
}
|
28
|
+
|
29
|
+
if (errorResponse.status === 403) {
|
30
|
+
return {
|
31
|
+
error: errorResponse.status,
|
32
|
+
errorType: AgentRuntimeErrorType.ProviderBizError,
|
33
|
+
message: '请检查 API Key 余额是否充足,或者是否在用未实名的 API Key 访问需要实名的模型。',
|
34
|
+
};
|
35
|
+
}
|
36
|
+
}
|
37
|
+
return {
|
38
|
+
error,
|
39
|
+
};
|
40
|
+
},
|
13
41
|
handlePayload: (payload) => {
|
14
42
|
return {
|
15
43
|
...payload,
|
@@ -20,6 +48,10 @@ export const LobeSiliconCloudAI = LobeOpenAICompatibleFactory({
|
|
20
48
|
debug: {
|
21
49
|
chatCompletion: () => process.env.DEBUG_SILICONCLOUD_CHAT_COMPLETION === '1',
|
22
50
|
},
|
51
|
+
errorType: {
|
52
|
+
bizError: AgentRuntimeErrorType.ProviderBizError,
|
53
|
+
invalidAPIKey: AgentRuntimeErrorType.InvalidProviderAPIKey,
|
54
|
+
},
|
23
55
|
models: {
|
24
56
|
transformModel: (m) => {
|
25
57
|
const functionCallKeywords = [
|
@@ -576,7 +576,7 @@ describe('chatMessage actions', () => {
|
|
576
576
|
const abortController = new AbortController();
|
577
577
|
|
578
578
|
act(() => {
|
579
|
-
useChatStore.setState({ abortController });
|
579
|
+
useChatStore.setState({ chatLoadingIdsAbortController: abortController });
|
580
580
|
});
|
581
581
|
|
582
582
|
await act(async () => {
|
@@ -596,18 +596,18 @@ describe('chatMessage actions', () => {
|
|
596
596
|
|
597
597
|
await act(async () => {
|
598
598
|
// 确保没有设置 abortController
|
599
|
-
useChatStore.setState({
|
599
|
+
useChatStore.setState({ chatLoadingIdsAbortController: undefined });
|
600
600
|
|
601
601
|
result.current.stopGenerateMessage();
|
602
602
|
});
|
603
603
|
|
604
604
|
// 由于没有 abortController,不应调用任何方法
|
605
|
-
expect(result.current.
|
605
|
+
expect(result.current.chatLoadingIdsAbortController).toBeUndefined();
|
606
606
|
});
|
607
607
|
|
608
608
|
it('should return early if abortController is undefined', () => {
|
609
609
|
act(() => {
|
610
|
-
useChatStore.setState({
|
610
|
+
useChatStore.setState({ chatLoadingIdsAbortController: undefined });
|
611
611
|
});
|
612
612
|
|
613
613
|
const { result } = renderHook(() => useChatStore());
|
@@ -625,7 +625,7 @@ describe('chatMessage actions', () => {
|
|
625
625
|
const abortMock = vi.fn();
|
626
626
|
const abortController = { abort: abortMock } as unknown as AbortController;
|
627
627
|
act(() => {
|
628
|
-
useChatStore.setState({ abortController });
|
628
|
+
useChatStore.setState({ chatLoadingIdsAbortController: abortController });
|
629
629
|
});
|
630
630
|
const { result } = renderHook(() => useChatStore());
|
631
631
|
|
@@ -639,7 +639,7 @@ describe('chatMessage actions', () => {
|
|
639
639
|
it('should call internal_toggleChatLoading with correct parameters', () => {
|
640
640
|
const abortController = new AbortController();
|
641
641
|
act(() => {
|
642
|
-
useChatStore.setState({ abortController });
|
642
|
+
useChatStore.setState({ chatLoadingIdsAbortController: abortController });
|
643
643
|
});
|
644
644
|
const { result } = renderHook(() => useChatStore());
|
645
645
|
const spy = vi.spyOn(result.current, 'internal_toggleChatLoading');
|
@@ -868,7 +868,7 @@ describe('chatMessage actions', () => {
|
|
868
868
|
});
|
869
869
|
|
870
870
|
const state = useChatStore.getState();
|
871
|
-
expect(state.
|
871
|
+
expect(state.chatLoadingIdsAbortController).toBeInstanceOf(AbortController);
|
872
872
|
expect(state.chatLoadingIds).toEqual(['message-id']);
|
873
873
|
});
|
874
874
|
|
@@ -887,7 +887,7 @@ describe('chatMessage actions', () => {
|
|
887
887
|
});
|
888
888
|
|
889
889
|
const state = useChatStore.getState();
|
890
|
-
expect(state.
|
890
|
+
expect(state.chatLoadingIdsAbortController).toBeUndefined();
|
891
891
|
expect(state.chatLoadingIds).toEqual([]);
|
892
892
|
});
|
893
893
|
|
@@ -920,12 +920,12 @@ describe('chatMessage actions', () => {
|
|
920
920
|
const abortController = new AbortController();
|
921
921
|
|
922
922
|
act(() => {
|
923
|
-
useChatStore.setState({ abortController });
|
923
|
+
useChatStore.setState({ chatLoadingIdsAbortController: abortController });
|
924
924
|
result.current.internal_toggleChatLoading(true, 'message-id', 'loading-action');
|
925
925
|
});
|
926
926
|
|
927
927
|
const state = useChatStore.getState();
|
928
|
-
expect(state.
|
928
|
+
expect(state.chatLoadingIdsAbortController).toEqual(abortController);
|
929
929
|
});
|
930
930
|
});
|
931
931
|
|
@@ -267,10 +267,11 @@ export const generateAIChat: StateCreator<
|
|
267
267
|
await Promise.all([summaryTitle(), addFilesToAgent()]);
|
268
268
|
},
|
269
269
|
stopGenerateMessage: () => {
|
270
|
-
const {
|
271
|
-
if (!abortController) return;
|
270
|
+
const { chatLoadingIdsAbortController, internal_toggleChatLoading } = get();
|
272
271
|
|
273
|
-
|
272
|
+
if (!chatLoadingIdsAbortController) return;
|
273
|
+
|
274
|
+
chatLoadingIdsAbortController.abort(MESSAGE_CANCEL_FLAT);
|
274
275
|
|
275
276
|
internal_toggleChatLoading(false, undefined, n('stopGenerateMessage') as string);
|
276
277
|
},
|
@@ -368,13 +368,14 @@ export const chatMessage: StateCreator<
|
|
368
368
|
);
|
369
369
|
},
|
370
370
|
internal_toggleLoadingArrays: (key, loading, id, action) => {
|
371
|
+
const abortControllerKey = `${key}AbortController`;
|
371
372
|
if (loading) {
|
372
373
|
window.addEventListener('beforeunload', preventLeavingFn);
|
373
374
|
|
374
375
|
const abortController = new AbortController();
|
375
376
|
set(
|
376
377
|
{
|
377
|
-
abortController,
|
378
|
+
[abortControllerKey]: abortController,
|
378
379
|
[key]: toggleBooleanList(get()[key] as string[], id!, loading),
|
379
380
|
},
|
380
381
|
false,
|
@@ -384,11 +385,11 @@ export const chatMessage: StateCreator<
|
|
384
385
|
return abortController;
|
385
386
|
} else {
|
386
387
|
if (!id) {
|
387
|
-
set({
|
388
|
+
set({ [abortControllerKey]: undefined, [key]: [] }, false, action);
|
388
389
|
} else
|
389
390
|
set(
|
390
391
|
{
|
391
|
-
|
392
|
+
[abortControllerKey]: undefined,
|
392
393
|
[key]: toggleBooleanList(get()[key] as string[], id, loading),
|
393
394
|
},
|
394
395
|
false,
|
@@ -52,6 +52,7 @@ export interface SystemStatus {
|
|
52
52
|
latestChangelogId?: string;
|
53
53
|
mobileShowPortal?: boolean;
|
54
54
|
mobileShowTopic?: boolean;
|
55
|
+
portalWidth: number;
|
55
56
|
sessionsWidth: number;
|
56
57
|
showChatSideBar?: boolean;
|
57
58
|
showFilePanel?: boolean;
|
@@ -86,6 +87,7 @@ export const INITIAL_STATUS = {
|
|
86
87
|
hideThreadLimitAlert: false,
|
87
88
|
inputHeight: 200,
|
88
89
|
mobileShowTopic: false,
|
90
|
+
portalWidth: 400,
|
89
91
|
sessionsWidth: 320,
|
90
92
|
showChatSideBar: true,
|
91
93
|
showFilePanel: true,
|
@@ -20,6 +20,7 @@ const hidePWAInstaller = (s: GlobalStore) => s.status.hidePWAInstaller;
|
|
20
20
|
const showChatHeader = (s: GlobalStore) => !s.status.zenMode;
|
21
21
|
const inZenMode = (s: GlobalStore) => s.status.zenMode;
|
22
22
|
const sessionWidth = (s: GlobalStore) => s.status.sessionsWidth;
|
23
|
+
const portalWidth = (s: GlobalStore) => s.status.portalWidth || 400;
|
23
24
|
const filePanelWidth = (s: GlobalStore) => s.status.filePanelWidth;
|
24
25
|
const inputHeight = (s: GlobalStore) => s.status.inputHeight;
|
25
26
|
const threadInputHeight = (s: GlobalStore) => s.status.threadInputHeight;
|
@@ -59,6 +60,7 @@ export const systemStatusSelectors = {
|
|
59
60
|
isPgliteNotInited,
|
60
61
|
mobileShowPortal,
|
61
62
|
mobileShowTopic,
|
63
|
+
portalWidth,
|
62
64
|
sessionGroupKeys,
|
63
65
|
sessionWidth,
|
64
66
|
showChatHeader,
|