@lobehub/lobehub 2.0.0-next.291 → 2.0.0-next.292
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/.conductor/setup.sh +107 -0
- package/.cursor/rules/linear.mdc +53 -0
- package/.github/actions/desktop-build-setup/action.yml +29 -0
- package/.github/actions/desktop-upload-artifacts/action.yml +46 -0
- package/.github/workflows/release-desktop-beta.yml +76 -115
- package/.github/workflows/release-desktop-stable.yml +461 -0
- package/CHANGELOG.md +33 -0
- package/CLAUDE.md +2 -48
- package/apps/desktop/dev-app-update.yml +10 -0
- package/apps/desktop/electron-builder.mjs +40 -10
- package/apps/desktop/electron.vite.config.ts +3 -2
- package/apps/desktop/package.json +2 -1
- package/apps/desktop/scripts/update-test/README.md +222 -0
- package/apps/desktop/scripts/update-test/dev-app-update.local.yml +18 -0
- package/apps/desktop/scripts/update-test/generate-manifest.sh +277 -0
- package/apps/desktop/scripts/update-test/run-test.sh +105 -0
- package/apps/desktop/scripts/update-test/setup.sh +111 -0
- package/apps/desktop/scripts/update-test/start-server.sh +70 -0
- package/apps/desktop/scripts/update-test/stop-server.sh +33 -0
- package/apps/desktop/src/main/core/infrastructure/UpdaterManager.ts +120 -9
- package/apps/desktop/src/main/core/infrastructure/__tests__/UpdaterManager.test.ts +17 -1
- package/apps/desktop/src/main/env.ts +19 -11
- package/apps/desktop/src/main/modules/updater/configs.ts +14 -1
- package/changelog/v1.json +9 -0
- package/conductor.json +5 -0
- package/locales/en-US/subscription.json +2 -2
- package/locales/zh-CN/subscription.json +2 -2
- package/package.json +1 -1
- package/packages/builtin-tool-notebook/src/client/Render/CreateDocument/DocumentCard.tsx +16 -14
- package/packages/electron-client-ipc/src/useWatchBroadcast.ts +10 -4
- package/packages/model-bank/src/aiModels/qiniu.ts +6 -6
- package/packages/observability-otel/src/node.ts +39 -37
- package/scripts/electronWorkflow/mergeMacReleaseFiles.js +22 -8
- package/src/app/(backend)/api/version/route.ts +13 -0
- package/src/app/[variants]/(desktop)/desktop-onboarding/_layout/index.tsx +2 -1
- package/src/app/[variants]/(main)/_layout/index.tsx +2 -1
- package/src/app/[variants]/(main)/agent/cron/[cronId]/features/CronJobScheduleConfig.tsx +0 -1
- package/src/app/[variants]/(main)/agent/cron/[cronId]/index.tsx +5 -5
- package/src/app/[variants]/(main)/agent/features/Conversation/ThreadHydration.tsx +3 -1
- package/src/app/[variants]/(main)/group/features/Conversation/ThreadHydration.tsx +3 -1
- package/src/app/[variants]/(main)/settings/provider/features/ProviderConfig/Checker.tsx +3 -3
- package/src/app/[variants]/(mobile)/router/mobileRouter.config.tsx +1 -4
- package/src/app/[variants]/router/desktopRouter.config.tsx +1 -4
- package/src/components/HtmlPreview/PreviewDrawer.tsx +1 -1
- package/src/features/Conversation/Messages/AssistantGroup/components/GroupItem.tsx +12 -2
- package/src/features/Conversation/Messages/Tool/Tool/index.tsx +10 -1
- package/src/features/{ElectronTitlebar/hooks → Electron/navigation}/useNavigationHistory.ts +1 -1
- package/src/features/{ElectronTitlebar/NavigationBar/index.tsx → Electron/titlebar/NavigationBar.tsx} +1 -1
- package/src/features/{ElectronTitlebar/NavigationBar → Electron/titlebar}/RecentlyViewed.tsx +1 -1
- package/src/features/{ElectronTitlebar/index.tsx → Electron/titlebar/TitleBar.tsx} +19 -9
- package/src/features/Electron/titlebar/WinControl.tsx +5 -0
- package/src/features/Electron/updater/UpdateModal.tsx +299 -0
- package/src/features/LibraryModal/AddFilesToKnowledgeBase/index.test.tsx +24 -0
- package/src/features/LibraryModal/AddFilesToKnowledgeBase/index.tsx +21 -24
- package/src/features/LibraryModal/CreateNew/index.tsx +18 -22
- package/src/features/PluginDevModal/index.tsx +1 -1
- package/src/layout/GlobalProvider/AppTheme.tsx +1 -1
- package/src/libs/swr/index.ts +26 -30
- package/src/store/aiInfra/slices/aiProvider/action.ts +16 -17
- package/src/store/chat/slices/portal/action.test.ts +0 -2
- package/src/store/chat/slices/portal/action.ts +17 -44
- package/src/store/chat/slices/thread/action.test.ts +4 -1
- package/src/store/chat/slices/thread/action.ts +6 -1
- package/src/components/FunctionModal/createModalHooks.ts +0 -48
- package/src/components/FunctionModal/index.ts +0 -1
- package/src/components/FunctionModal/style.tsx +0 -44
- package/src/features/ElectronTitlebar/UpdateModal.tsx +0 -274
- package/src/features/ElectronTitlebar/WinControl/index.tsx +0 -90
- /package/src/features/{ElectronTitlebar/Connection/index.tsx → Electron/connection/Connection.tsx} +0 -0
- /package/src/features/{ElectronTitlebar/Connection → Electron/connection}/ConnectionMode.tsx +0 -0
- /package/src/features/{ElectronTitlebar/Connection → Electron/connection}/Option.tsx +0 -0
- /package/src/features/{ElectronTitlebar/Connection → Electron/connection}/RemoteStatus.tsx +0 -0
- /package/src/features/{ElectronTitlebar/Connection → Electron/connection}/Waiting.tsx +0 -0
- /package/src/features/{ElectronTitlebar/Connection → Electron/connection}/WaitingAnim.tsx +0 -0
- /package/src/features/{ElectronTitlebar/helpers → Electron/navigation}/routeMetadata.ts +0 -0
- /package/src/features/{ElectronTitlebar/hooks → Electron/system}/useWatchThemeUpdate.ts +0 -0
- /package/src/features/{ElectronTitlebar → Electron/titlebar}/SimpleTitleBar.tsx +0 -0
- /package/src/features/{ElectronTitlebar → Electron/updater}/UpdateNotification.tsx +0 -0
|
@@ -42,71 +42,57 @@ export const chatPortalSlice: StateCreator<
|
|
|
42
42
|
[],
|
|
43
43
|
ChatPortalAction
|
|
44
44
|
> = (set, get) => ({
|
|
45
|
-
|
|
46
|
-
|
|
47
45
|
clearPortalStack: () => {
|
|
48
46
|
set({ portalStack: [], showPortal: false }, false, 'clearPortalStack');
|
|
49
47
|
},
|
|
50
48
|
|
|
51
|
-
|
|
52
|
-
closeArtifact: () => {
|
|
49
|
+
closeArtifact: () => {
|
|
53
50
|
const { portalStack } = get();
|
|
54
51
|
if (getCurrentViewType(portalStack) === PortalViewType.Artifact) {
|
|
55
52
|
get().popPortalView();
|
|
56
53
|
}
|
|
57
54
|
},
|
|
58
55
|
|
|
59
|
-
|
|
60
|
-
closeDocument: () => {
|
|
56
|
+
closeDocument: () => {
|
|
61
57
|
const { portalStack } = get();
|
|
62
58
|
if (getCurrentViewType(portalStack) === PortalViewType.Document) {
|
|
63
59
|
get().popPortalView();
|
|
64
60
|
}
|
|
65
61
|
},
|
|
66
62
|
|
|
67
|
-
|
|
68
|
-
closeFilePreview: () => {
|
|
63
|
+
closeFilePreview: () => {
|
|
69
64
|
const { portalStack } = get();
|
|
70
65
|
if (getCurrentViewType(portalStack) === PortalViewType.FilePreview) {
|
|
71
66
|
get().popPortalView();
|
|
72
67
|
}
|
|
73
68
|
},
|
|
74
69
|
|
|
75
|
-
|
|
76
|
-
closeMessageDetail: () => {
|
|
70
|
+
closeMessageDetail: () => {
|
|
77
71
|
const { portalStack } = get();
|
|
78
72
|
if (getCurrentViewType(portalStack) === PortalViewType.MessageDetail) {
|
|
79
73
|
get().popPortalView();
|
|
80
74
|
}
|
|
81
75
|
},
|
|
82
76
|
|
|
83
|
-
|
|
84
|
-
closeNotebook: () => {
|
|
77
|
+
closeNotebook: () => {
|
|
85
78
|
const { portalStack } = get();
|
|
86
79
|
if (getCurrentViewType(portalStack) === PortalViewType.Notebook) {
|
|
87
80
|
get().popPortalView();
|
|
88
81
|
}
|
|
89
82
|
},
|
|
90
83
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
closeToolUI: () => {
|
|
84
|
+
closeToolUI: () => {
|
|
95
85
|
const { portalStack } = get();
|
|
96
86
|
if (getCurrentViewType(portalStack) === PortalViewType.ToolUI) {
|
|
97
87
|
get().popPortalView();
|
|
98
88
|
}
|
|
99
89
|
},
|
|
100
90
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
goBack: () => {
|
|
91
|
+
goBack: () => {
|
|
104
92
|
get().popPortalView();
|
|
105
93
|
},
|
|
106
94
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
goHome: () => {
|
|
95
|
+
goHome: () => {
|
|
110
96
|
set(
|
|
111
97
|
{
|
|
112
98
|
portalStack: [{ type: PortalViewType.Home }],
|
|
@@ -117,45 +103,32 @@ goHome: () => {
|
|
|
117
103
|
);
|
|
118
104
|
},
|
|
119
105
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
// ============== Convenience Methods (using stack operations) ==============
|
|
123
|
-
openArtifact: (artifact) => {
|
|
106
|
+
// ============== Convenience Methods (using stack operations) ==============
|
|
107
|
+
openArtifact: (artifact) => {
|
|
124
108
|
get().pushPortalView({ artifact, type: PortalViewType.Artifact });
|
|
125
109
|
},
|
|
126
110
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
openDocument: (documentId) => {
|
|
111
|
+
openDocument: (documentId) => {
|
|
131
112
|
get().pushPortalView({ documentId, type: PortalViewType.Document });
|
|
132
113
|
},
|
|
133
114
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
openFilePreview: (file) => {
|
|
115
|
+
openFilePreview: (file) => {
|
|
138
116
|
get().pushPortalView({ file, type: PortalViewType.FilePreview });
|
|
139
117
|
},
|
|
140
118
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
openMessageDetail: (messageId) => {
|
|
119
|
+
openMessageDetail: (messageId) => {
|
|
144
120
|
get().pushPortalView({ messageId, type: PortalViewType.MessageDetail });
|
|
145
121
|
},
|
|
146
122
|
|
|
147
|
-
|
|
148
|
-
openNotebook: () => {
|
|
123
|
+
openNotebook: () => {
|
|
149
124
|
get().pushPortalView({ type: PortalViewType.Notebook });
|
|
150
125
|
},
|
|
151
126
|
|
|
152
|
-
|
|
153
|
-
openToolUI: (messageId, identifier) => {
|
|
127
|
+
openToolUI: (messageId, identifier) => {
|
|
154
128
|
get().pushPortalView({ identifier, messageId, type: PortalViewType.ToolUI });
|
|
155
129
|
},
|
|
156
130
|
|
|
157
|
-
|
|
158
|
-
popPortalView: () => {
|
|
131
|
+
popPortalView: () => {
|
|
159
132
|
const { portalStack } = get();
|
|
160
133
|
|
|
161
134
|
if (portalStack.length <= 1) {
|
|
@@ -167,7 +140,7 @@ popPortalView: () => {
|
|
|
167
140
|
},
|
|
168
141
|
|
|
169
142
|
// ============== Core Stack Operations ==============
|
|
170
|
-
pushPortalView: (view) => {
|
|
143
|
+
pushPortalView: (view) => {
|
|
171
144
|
const { portalStack } = get();
|
|
172
145
|
const top = portalStack.at(-1);
|
|
173
146
|
|
|
@@ -150,7 +150,10 @@ describe('thread action', () => {
|
|
|
150
150
|
expect(result.current.threadStartMessageId).toBe('message-id');
|
|
151
151
|
expect(result.current.portalThreadId).toBeUndefined();
|
|
152
152
|
expect(result.current.startToForkThread).toBe(true);
|
|
153
|
-
expect(pushPortalViewSpy).toHaveBeenCalledWith({
|
|
153
|
+
expect(pushPortalViewSpy).toHaveBeenCalledWith({
|
|
154
|
+
type: 'thread',
|
|
155
|
+
startMessageId: 'message-id',
|
|
156
|
+
});
|
|
154
157
|
});
|
|
155
158
|
});
|
|
156
159
|
|
|
@@ -2,7 +2,12 @@
|
|
|
2
2
|
// Disable the auto sort key eslint rule to make the code more logic and readable
|
|
3
3
|
import { LOADING_FLAT } from '@lobechat/const';
|
|
4
4
|
import { chainSummaryTitle } from '@lobechat/prompts';
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
type CreateMessageParams,
|
|
7
|
+
type IThreadType,
|
|
8
|
+
type ThreadItem,
|
|
9
|
+
type UIChatMessage,
|
|
10
|
+
} from '@lobechat/types';
|
|
6
11
|
import isEqual from 'fast-deep-equal';
|
|
7
12
|
import type { SWRResponse } from 'swr';
|
|
8
13
|
import { type StateCreator } from 'zustand/vanilla';
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import { App } from 'antd';
|
|
2
|
-
import { type ModalFuncProps } from 'antd/es/modal/interface';
|
|
3
|
-
import { type MutableRefObject, type ReactNode, type RefObject, useRef } from 'react';
|
|
4
|
-
|
|
5
|
-
import { closeIcon, styles } from './style';
|
|
6
|
-
|
|
7
|
-
interface CreateModalProps extends ModalFuncProps {
|
|
8
|
-
content: ReactNode;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
interface ModalInstance {
|
|
12
|
-
destroy: (...args: any[]) => void;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
type PropsFunc<T = undefined> = (
|
|
16
|
-
instance: MutableRefObject<ModalInstance | undefined>,
|
|
17
|
-
props?: T,
|
|
18
|
-
) => CreateModalProps;
|
|
19
|
-
|
|
20
|
-
const createModal = <T>(params: CreateModalProps | PropsFunc<T>) => {
|
|
21
|
-
const useModal = () => {
|
|
22
|
-
const { modal } = App.useApp();
|
|
23
|
-
const instanceRef = useRef<ModalInstance>(null);
|
|
24
|
-
|
|
25
|
-
const open = (outProps?: T) => {
|
|
26
|
-
const props =
|
|
27
|
-
typeof params === 'function'
|
|
28
|
-
? params(instanceRef as RefObject<ModalInstance>, outProps)
|
|
29
|
-
: params;
|
|
30
|
-
|
|
31
|
-
instanceRef.current = modal.confirm({
|
|
32
|
-
className: styles.content,
|
|
33
|
-
closable: true,
|
|
34
|
-
closeIcon,
|
|
35
|
-
footer: false,
|
|
36
|
-
icon: null,
|
|
37
|
-
wrapClassName: styles.wrap,
|
|
38
|
-
...props,
|
|
39
|
-
});
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
return { open };
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
return useModal;
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
export { createModal };
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from './createModalHooks';
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import { Icon } from '@lobehub/ui';
|
|
2
|
-
import { createStaticStyles , responsive } from 'antd-style';
|
|
3
|
-
import { XIcon } from 'lucide-react';
|
|
4
|
-
|
|
5
|
-
const prefixCls = 'ant';
|
|
6
|
-
|
|
7
|
-
export const styles = createStaticStyles(({ css, cssVar }) => {
|
|
8
|
-
return {
|
|
9
|
-
content: css`
|
|
10
|
-
.${prefixCls}-modal-container {
|
|
11
|
-
overflow: hidden;
|
|
12
|
-
|
|
13
|
-
width: min(90vw, 450px);
|
|
14
|
-
padding: 0;
|
|
15
|
-
border: 1px solid ${cssVar.colorSplit};
|
|
16
|
-
border-radius: ${cssVar.borderRadiusLG};
|
|
17
|
-
|
|
18
|
-
background: ${cssVar.colorBgLayout};
|
|
19
|
-
|
|
20
|
-
${responsive.sm} {
|
|
21
|
-
width: unset;
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
.${prefixCls}-modal-confirm-title {
|
|
25
|
-
display: block;
|
|
26
|
-
padding-block: 16px 0;
|
|
27
|
-
padding-inline: 16px;
|
|
28
|
-
}
|
|
29
|
-
.${prefixCls}-modal-confirm-btns {
|
|
30
|
-
margin-block-start: 0;
|
|
31
|
-
padding: 16px;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
.${prefixCls}-modal-confirm-paragraph {
|
|
35
|
-
max-width: 100%;
|
|
36
|
-
}
|
|
37
|
-
`,
|
|
38
|
-
wrap: css`
|
|
39
|
-
overflow: hidden auto;
|
|
40
|
-
`,
|
|
41
|
-
};
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
export const closeIcon = <Icon icon={XIcon} size={20} />;
|
|
@@ -1,274 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
type ProgressInfo,
|
|
3
|
-
type UpdateInfo,
|
|
4
|
-
useWatchBroadcast,
|
|
5
|
-
} from '@lobechat/electron-client-ipc';
|
|
6
|
-
import { Button } from '@lobehub/ui';
|
|
7
|
-
import { App, Modal, Progress, Spin } from 'antd';
|
|
8
|
-
import React, { memo, useRef, useState } from 'react';
|
|
9
|
-
import { useTranslation } from 'react-i18next';
|
|
10
|
-
|
|
11
|
-
import { autoUpdateService } from '@/services/electron/autoUpdate';
|
|
12
|
-
import { formatSpeed } from '@/utils/format';
|
|
13
|
-
|
|
14
|
-
export const UpdateModal = memo(() => {
|
|
15
|
-
const { t } = useTranslation(['electron', 'common']);
|
|
16
|
-
|
|
17
|
-
const [isChecking, setIsChecking] = useState(false);
|
|
18
|
-
const [isDownloading, setIsDownloading] = useState(false);
|
|
19
|
-
// 仅用于手动触发的更新流程(用户从设置页点“检查更新”)
|
|
20
|
-
const manualFlowRef = useRef(false);
|
|
21
|
-
const [updateAvailableInfo, setUpdateAvailableInfo] = useState<UpdateInfo | null>(null);
|
|
22
|
-
const [downloadedInfo, setDownloadedInfo] = useState<UpdateInfo | null>(null);
|
|
23
|
-
const [progress, setProgress] = useState<ProgressInfo | null>(null);
|
|
24
|
-
const [latestVersionInfo, setLatestVersionInfo] = useState<UpdateInfo | null>(null); // State for latest version modal
|
|
25
|
-
const { modal } = App.useApp();
|
|
26
|
-
// --- Event Listeners ---
|
|
27
|
-
|
|
28
|
-
useWatchBroadcast('manualUpdateCheckStart', () => {
|
|
29
|
-
console.log('[Manual Update] Check Start');
|
|
30
|
-
manualFlowRef.current = true;
|
|
31
|
-
|
|
32
|
-
setIsChecking(true);
|
|
33
|
-
setUpdateAvailableInfo(null);
|
|
34
|
-
setDownloadedInfo(null);
|
|
35
|
-
setProgress(null);
|
|
36
|
-
setLatestVersionInfo(null); // Reset latest version info
|
|
37
|
-
// Optional: Show a brief notification that check has started
|
|
38
|
-
// notification.info({ message: t('updater.checking') });
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
useWatchBroadcast('manualUpdateAvailable', (info: UpdateInfo) => {
|
|
42
|
-
console.log('[Manual Update] Available:', info);
|
|
43
|
-
// Only react if it's part of a manual check flow (i.e., isChecking was true)
|
|
44
|
-
// No need to check isChecking here as this event is specific
|
|
45
|
-
setIsChecking(false);
|
|
46
|
-
setUpdateAvailableInfo(info);
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
useWatchBroadcast('manualUpdateNotAvailable', (info) => {
|
|
50
|
-
console.log('[Manual Update] Not Available:', info);
|
|
51
|
-
// Only react if it's part of a manual check flow
|
|
52
|
-
// No need to check isChecking here as this event is specific
|
|
53
|
-
setIsChecking(false);
|
|
54
|
-
manualFlowRef.current = false;
|
|
55
|
-
|
|
56
|
-
setLatestVersionInfo(info); // Set info for the modal
|
|
57
|
-
// notification.success({
|
|
58
|
-
// description: t('updater.isLatestVersionDesc', { version: info.version }),
|
|
59
|
-
// message: t('updater.isLatestVersion'),
|
|
60
|
-
// });
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
useWatchBroadcast('updateError', (message: string) => {
|
|
64
|
-
console.log('[Manual Update] Error:', message);
|
|
65
|
-
// Only react if it's part of a manual check/download flow
|
|
66
|
-
if (isChecking || isDownloading) {
|
|
67
|
-
setIsChecking(false);
|
|
68
|
-
setIsDownloading(false);
|
|
69
|
-
// Show error modal or notification
|
|
70
|
-
modal.error({ content: message, title: t('updater.updateError') });
|
|
71
|
-
setLatestVersionInfo(null); // Ensure other modals are closed on error
|
|
72
|
-
setUpdateAvailableInfo(null);
|
|
73
|
-
setDownloadedInfo(null);
|
|
74
|
-
manualFlowRef.current = false;
|
|
75
|
-
}
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
useWatchBroadcast('updateDownloadStart', () => {
|
|
79
|
-
console.log('[Manual Update] Download Start');
|
|
80
|
-
// This event implies a manual download was triggered (likely from the 'updateAvailable' modal)
|
|
81
|
-
manualFlowRef.current = true;
|
|
82
|
-
|
|
83
|
-
setIsDownloading(true);
|
|
84
|
-
setUpdateAvailableInfo(null); // Hide the 'download' button modal
|
|
85
|
-
setProgress({ bytesPerSecond: 0, percent: 0, total: 0, transferred: 0 }); // Reset progress
|
|
86
|
-
setLatestVersionInfo(null); // Ensure other modals are closed
|
|
87
|
-
// Optional: Show notification that download started
|
|
88
|
-
// notification.info({ message: t('updater.downloadingUpdate') });
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
useWatchBroadcast('updateDownloadProgress', (progressInfo: ProgressInfo) => {
|
|
92
|
-
console.log('[Manual Update] Progress:', progressInfo);
|
|
93
|
-
// Only update progress if we are in the manual download state
|
|
94
|
-
setProgress(progressInfo);
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
useWatchBroadcast('updateDownloaded', (info: UpdateInfo) => {
|
|
98
|
-
console.log('[Manual Update] Downloaded:', info);
|
|
99
|
-
// 仅在手动流程里展示阻塞式的“更新就绪”弹窗
|
|
100
|
-
if (manualFlowRef.current) {
|
|
101
|
-
setIsChecking(false);
|
|
102
|
-
setIsDownloading(false);
|
|
103
|
-
setDownloadedInfo(info);
|
|
104
|
-
setProgress(null); // Clear progress
|
|
105
|
-
setLatestVersionInfo(null); // Ensure other modals are closed
|
|
106
|
-
setUpdateAvailableInfo(null);
|
|
107
|
-
}
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
// --- Render Logic ---
|
|
111
|
-
|
|
112
|
-
const handleDownload = () => {
|
|
113
|
-
if (!updateAvailableInfo) return;
|
|
114
|
-
// No need to set states here, 'updateDownloadStart' will handle it
|
|
115
|
-
autoUpdateService.downloadUpdate();
|
|
116
|
-
};
|
|
117
|
-
|
|
118
|
-
const handleInstallNow = () => {
|
|
119
|
-
setDownloadedInfo(null); // Close modal immediately
|
|
120
|
-
autoUpdateService.installNow();
|
|
121
|
-
manualFlowRef.current = false;
|
|
122
|
-
};
|
|
123
|
-
|
|
124
|
-
const handleInstallLater = () => {
|
|
125
|
-
// No need to set state here, 'updateWillInstallLater' handles it
|
|
126
|
-
autoUpdateService.installLater();
|
|
127
|
-
setDownloadedInfo(null); // Close the modal after clicking
|
|
128
|
-
manualFlowRef.current = false;
|
|
129
|
-
};
|
|
130
|
-
|
|
131
|
-
const closeAvailableModal = () => setUpdateAvailableInfo(null);
|
|
132
|
-
const closeDownloadedModal = () => setDownloadedInfo(null);
|
|
133
|
-
const closeLatestVersionModal = () => setLatestVersionInfo(null);
|
|
134
|
-
|
|
135
|
-
const handleCancelCheck = () => {
|
|
136
|
-
setIsChecking(false);
|
|
137
|
-
setUpdateAvailableInfo(null);
|
|
138
|
-
setDownloadedInfo(null);
|
|
139
|
-
setProgress(null);
|
|
140
|
-
setLatestVersionInfo(null);
|
|
141
|
-
manualFlowRef.current = false;
|
|
142
|
-
};
|
|
143
|
-
|
|
144
|
-
const renderCheckingModal = () => (
|
|
145
|
-
<Modal
|
|
146
|
-
closable
|
|
147
|
-
footer={[
|
|
148
|
-
<Button key="cancel" onClick={handleCancelCheck}>
|
|
149
|
-
{t('cancel', { ns: 'common' })}
|
|
150
|
-
</Button>,
|
|
151
|
-
]}
|
|
152
|
-
onCancel={handleCancelCheck}
|
|
153
|
-
open={isChecking}
|
|
154
|
-
title={t('updater.checkingUpdate')}
|
|
155
|
-
>
|
|
156
|
-
<Spin spinning={true}>
|
|
157
|
-
<div style={{ padding: '20px', textAlign: 'center' }}>
|
|
158
|
-
{t('updater.checkingUpdateDesc')}
|
|
159
|
-
</div>
|
|
160
|
-
</Spin>
|
|
161
|
-
</Modal>
|
|
162
|
-
);
|
|
163
|
-
|
|
164
|
-
const renderAvailableModal = () => (
|
|
165
|
-
<Modal
|
|
166
|
-
footer={[
|
|
167
|
-
<Button key="cancel" onClick={closeAvailableModal}>
|
|
168
|
-
{t('cancel', { ns: 'common' })}
|
|
169
|
-
</Button>,
|
|
170
|
-
<Button key="download" onClick={handleDownload} type="primary">
|
|
171
|
-
{t('updater.downloadNewVersion')}
|
|
172
|
-
</Button>,
|
|
173
|
-
]}
|
|
174
|
-
onCancel={closeAvailableModal}
|
|
175
|
-
open={!!updateAvailableInfo}
|
|
176
|
-
title={t('updater.newVersionAvailable')}
|
|
177
|
-
>
|
|
178
|
-
<h4>{t('updater.newVersionAvailableDesc', { version: updateAvailableInfo?.version })}</h4>
|
|
179
|
-
{updateAvailableInfo?.releaseNotes && (
|
|
180
|
-
<div
|
|
181
|
-
dangerouslySetInnerHTML={{ __html: updateAvailableInfo.releaseNotes as string }}
|
|
182
|
-
style={{
|
|
183
|
-
// background:theme
|
|
184
|
-
borderRadius: 4,
|
|
185
|
-
marginTop: 8,
|
|
186
|
-
maxHeight: 300,
|
|
187
|
-
overflow: 'auto',
|
|
188
|
-
padding: '8px 12px',
|
|
189
|
-
}}
|
|
190
|
-
/>
|
|
191
|
-
)}
|
|
192
|
-
</Modal>
|
|
193
|
-
);
|
|
194
|
-
|
|
195
|
-
const renderDownloadingModal = () => {
|
|
196
|
-
const percent = progress ? Math.round(progress.percent) : 0;
|
|
197
|
-
return (
|
|
198
|
-
<Modal
|
|
199
|
-
closable={false}
|
|
200
|
-
footer={null}
|
|
201
|
-
maskClosable={false}
|
|
202
|
-
open={isDownloading && !downloadedInfo}
|
|
203
|
-
title={t('updater.downloadingUpdate')}
|
|
204
|
-
>
|
|
205
|
-
<div style={{ padding: '20px 0' }}>
|
|
206
|
-
<Progress percent={percent} status="active" />
|
|
207
|
-
<div style={{ fontSize: 12, marginTop: 8, textAlign: 'center' }}>
|
|
208
|
-
{t('updater.downloadingUpdateDesc', { percent })}
|
|
209
|
-
{progress && progress.bytesPerSecond > 0 && (
|
|
210
|
-
<span>{formatSpeed(progress.bytesPerSecond)}</span>
|
|
211
|
-
)}
|
|
212
|
-
</div>
|
|
213
|
-
</div>
|
|
214
|
-
</Modal>
|
|
215
|
-
);
|
|
216
|
-
};
|
|
217
|
-
|
|
218
|
-
const renderDownloadedModal = () => (
|
|
219
|
-
<Modal
|
|
220
|
-
footer={[
|
|
221
|
-
<Button key="later" onClick={handleInstallLater}>
|
|
222
|
-
{t('updater.installLater')}
|
|
223
|
-
</Button>,
|
|
224
|
-
<Button key="now" onClick={handleInstallNow} type="primary">
|
|
225
|
-
{t('updater.restartAndInstall')}
|
|
226
|
-
</Button>,
|
|
227
|
-
]}
|
|
228
|
-
onCancel={closeDownloadedModal} // Allow closing if they don't want to decide now
|
|
229
|
-
open={!!downloadedInfo}
|
|
230
|
-
title={t('updater.updateReady')}
|
|
231
|
-
>
|
|
232
|
-
<h4>{t('updater.updateReadyDesc', { version: downloadedInfo?.version })}</h4>
|
|
233
|
-
{downloadedInfo?.releaseNotes && (
|
|
234
|
-
<div
|
|
235
|
-
dangerouslySetInnerHTML={{ __html: downloadedInfo.releaseNotes as string }}
|
|
236
|
-
style={{
|
|
237
|
-
borderRadius: 4,
|
|
238
|
-
marginTop: 8,
|
|
239
|
-
maxHeight: 300,
|
|
240
|
-
overflow: 'auto',
|
|
241
|
-
padding: '8px 12px',
|
|
242
|
-
}}
|
|
243
|
-
/>
|
|
244
|
-
)}
|
|
245
|
-
</Modal>
|
|
246
|
-
);
|
|
247
|
-
|
|
248
|
-
// New modal for "latest version"
|
|
249
|
-
const renderLatestVersionModal = () => (
|
|
250
|
-
<Modal
|
|
251
|
-
footer={[
|
|
252
|
-
<Button key="ok" onClick={closeLatestVersionModal} type="primary">
|
|
253
|
-
{t('ok', { ns: 'common' })}
|
|
254
|
-
</Button>,
|
|
255
|
-
]}
|
|
256
|
-
onCancel={closeLatestVersionModal}
|
|
257
|
-
open={!!latestVersionInfo}
|
|
258
|
-
title={t('updater.isLatestVersion')}
|
|
259
|
-
>
|
|
260
|
-
<p>{t('updater.isLatestVersionDesc', { version: latestVersionInfo?.version })}</p>
|
|
261
|
-
</Modal>
|
|
262
|
-
);
|
|
263
|
-
|
|
264
|
-
return (
|
|
265
|
-
<>
|
|
266
|
-
{renderCheckingModal()}
|
|
267
|
-
{renderAvailableModal()}
|
|
268
|
-
{renderDownloadingModal()}
|
|
269
|
-
{renderDownloadedModal()}
|
|
270
|
-
{renderLatestVersionModal()}
|
|
271
|
-
{/* Error state is handled by Modal.error currently */}
|
|
272
|
-
</>
|
|
273
|
-
);
|
|
274
|
-
});
|
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
// const useStyles = createStyles(({ css, cx, token }) => {
|
|
2
|
-
// const icon = css`
|
|
3
|
-
// display: flex;
|
|
4
|
-
// align-items: center;
|
|
5
|
-
// justify-content: center;
|
|
6
|
-
//
|
|
7
|
-
// width: ${TITLE_BAR_HEIGHT * 1.2}px;
|
|
8
|
-
// min-height: ${TITLE_BAR_HEIGHT}px;
|
|
9
|
-
//
|
|
10
|
-
// color: ${token.colorTextSecondary};
|
|
11
|
-
//
|
|
12
|
-
// transition: all ease-in-out 100ms;
|
|
13
|
-
//
|
|
14
|
-
// -webkit-app-region: no-drag;
|
|
15
|
-
//
|
|
16
|
-
// &:hover {
|
|
17
|
-
// color: ${token.colorText};
|
|
18
|
-
// background: ${token.colorFillTertiary};
|
|
19
|
-
// }
|
|
20
|
-
//
|
|
21
|
-
// &:active {
|
|
22
|
-
// color: ${token.colorText};
|
|
23
|
-
// background: ${token.colorFillSecondary};
|
|
24
|
-
// }
|
|
25
|
-
// `;
|
|
26
|
-
// return {
|
|
27
|
-
// close: cx(
|
|
28
|
-
// icon,
|
|
29
|
-
// css`
|
|
30
|
-
// padding-inline-end: 2px;
|
|
31
|
-
//
|
|
32
|
-
// &:hover {
|
|
33
|
-
// color: ${token.colorTextLightSolid};
|
|
34
|
-
//
|
|
35
|
-
// /* win11 的色值,亮暗色均不变 */
|
|
36
|
-
// background: #d33328;
|
|
37
|
-
// }
|
|
38
|
-
//
|
|
39
|
-
// &:active {
|
|
40
|
-
// color: ${token.colorTextLightSolid};
|
|
41
|
-
//
|
|
42
|
-
// /* win11 的色值 */
|
|
43
|
-
// background: #8b2b25;
|
|
44
|
-
// }
|
|
45
|
-
// `,
|
|
46
|
-
// ),
|
|
47
|
-
// container: css`
|
|
48
|
-
// cursor: pointer;
|
|
49
|
-
// display: flex;
|
|
50
|
-
// `,
|
|
51
|
-
// icon,
|
|
52
|
-
// };
|
|
53
|
-
// });
|
|
54
|
-
|
|
55
|
-
const WinControl = () => {
|
|
56
|
-
return <div style={{ width: 132 }} />;
|
|
57
|
-
|
|
58
|
-
// const { styles } = useStyles();
|
|
59
|
-
//
|
|
60
|
-
// return (
|
|
61
|
-
// <div className={styles.container}>
|
|
62
|
-
// <div
|
|
63
|
-
// className={styles.icon}
|
|
64
|
-
// onClick={() => {
|
|
65
|
-
// electronSystemService.minimizeWindow();
|
|
66
|
-
// }}
|
|
67
|
-
// >
|
|
68
|
-
// <Minus absoluteStrokeWidth size={14} strokeWidth={1.2} />
|
|
69
|
-
// </div>
|
|
70
|
-
// <div
|
|
71
|
-
// className={styles.icon}
|
|
72
|
-
// onClick={() => {
|
|
73
|
-
// electronSystemService.maximizeWindow();
|
|
74
|
-
// }}
|
|
75
|
-
// >
|
|
76
|
-
// <Square absoluteStrokeWidth size={10} strokeWidth={1.2} />
|
|
77
|
-
// </div>
|
|
78
|
-
// <div
|
|
79
|
-
// className={styles.close}
|
|
80
|
-
// onClick={() => {
|
|
81
|
-
// electronSystemService.closeWindow();
|
|
82
|
-
// }}
|
|
83
|
-
// >
|
|
84
|
-
// <XIcon absoluteStrokeWidth size={14} strokeWidth={1.2} />
|
|
85
|
-
// </div>
|
|
86
|
-
// </div>
|
|
87
|
-
// );
|
|
88
|
-
};
|
|
89
|
-
|
|
90
|
-
export default WinControl;
|
/package/src/features/{ElectronTitlebar/Connection/index.tsx → Electron/connection/Connection.tsx}
RENAMED
|
File without changes
|
/package/src/features/{ElectronTitlebar/Connection → Electron/connection}/ConnectionMode.tsx
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|