From dca1e8a2515af10238a1bc78e92c0fd2491c2ee3 Mon Sep 17 00:00:00 2001 From: Syngnat Date: Wed, 8 Jul 2026 20:30:05 +0800 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20feat(updater):=20=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E5=85=B3=E4=BA=8E=E9=A1=B5=E6=9B=B4=E6=96=B0=E4=BF=A1=E6=81=AF?= =?UTF-8?q?=E5=B1=95=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 关于页直接进入 GoNavi 内容详情,减少二次点击 - 将更新通道改为分段选择器并优化描述布局 - 保留后端发布发布时间元数据并在版本信息中展示 --- frontend/src/App.css | 60 ++++++++++++++++ frontend/src/App.settings-center.test.ts | 15 ++++ frontend/src/App.tsx | 72 ++++++++++++------- .../src/hooks/useAppUpdateManager.test.tsx | 24 +++++++ frontend/src/hooks/useAppUpdateManager.ts | 1 + frontend/src/main.browserMock.test.ts | 31 ++++++++ frontend/src/main.tsx | 26 +++---- internal/app/methods_update.go | 70 +++++++++--------- internal/app/methods_update_test.go | 17 +++-- 9 files changed, 238 insertions(+), 78 deletions(-) diff --git a/frontend/src/App.css b/frontend/src/App.css index ae9b9451..31b0b55b 100644 --- a/frontend/src/App.css +++ b/frontend/src/App.css @@ -743,3 +743,63 @@ body[data-ui-version="legacy"] .ant-layout-sider { min-width: 232px !important; max-width: min(960px, calc(100vw - 360px)) !important; } + +body .gonavi-about-update-channel.ant-segmented.ant-segmented { + height: 42px !important; + padding: 4px !important; + border: 1px solid rgba(15, 23, 42, 0.10) !important; + border-radius: 12px !important; + background: rgba(15, 23, 42, 0.035) !important; + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.72) !important; +} + +body .gonavi-about-update-channel .ant-segmented-group { + gap: 3px; +} + +body .gonavi-about-update-channel .ant-segmented-item { + border-radius: 9px !important; +} + +body .gonavi-about-update-channel .ant-segmented-item-label { + min-height: 32px !important; + padding: 0 14px !important; + color: rgba(15, 23, 42, 0.62) !important; + font-size: 14px !important; + font-weight: 700 !important; + line-height: 32px !important; +} + +body .gonavi-about-update-channel .ant-segmented-item-selected, +body .gonavi-about-update-channel .ant-segmented-thumb { + background: rgba(255, 255, 255, 0.98) !important; + box-shadow: 0 8px 18px rgba(15, 23, 42, 0.12) !important; +} + +body .gonavi-about-update-channel .ant-segmented-item-selected .ant-segmented-item-label { + color: #0f172a !important; +} + +body .gonavi-about-update-channel.ant-segmented-disabled { + opacity: 0.58; +} + +body[data-theme='dark'] .gonavi-about-update-channel.ant-segmented.ant-segmented { + border-color: rgba(148, 163, 184, 0.22) !important; + background: rgba(15, 23, 42, 0.55) !important; + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.08) !important; +} + +body[data-theme='dark'] .gonavi-about-update-channel .ant-segmented-item-label { + color: rgba(226, 232, 240, 0.62) !important; +} + +body[data-theme='dark'] .gonavi-about-update-channel .ant-segmented-item-selected, +body[data-theme='dark'] .gonavi-about-update-channel .ant-segmented-thumb { + background: rgba(30, 41, 59, 0.98) !important; + box-shadow: 0 8px 18px rgba(0, 0, 0, 0.26) !important; +} + +body[data-theme='dark'] .gonavi-about-update-channel .ant-segmented-item-selected .ant-segmented-item-label { + color: #f8fafc !important; +} diff --git a/frontend/src/App.settings-center.test.ts b/frontend/src/App.settings-center.test.ts index 743a4bc7..320d68b8 100644 --- a/frontend/src/App.settings-center.test.ts +++ b/frontend/src/App.settings-center.test.ts @@ -87,6 +87,13 @@ describe('settings center layout', () => { expect(appSource).toContain('renderSettingsCenterAboutPane()'); }); + it('opens the about group directly instead of showing a one-item list', () => { + expect(appSource).toContain('const resolveSettingsCenterGroupInitialPane = (group: SettingsCenterGroupKey): SettingsCenterPaneState | null => ('); + expect(appSource).toContain("group === 'about' ? { key: 'about-go-navi', group: 'about' } : null"); + expect(appSource).toContain('setActiveSettingsCenterPane(resolveSettingsCenterGroupInitialPane(group));'); + expect(appSource).toContain('setActiveSettingsCenterPane(resolveSettingsCenterGroupInitialPane(group.key));'); + }); + it('renders the settings center about page with the reference card layout', () => { expect(appSource).toContain('const renderSettingsCenterAboutPane = () => {'); expect(appSource).toContain('const renderSettingsCenterAboutProjectEntry = ({'); @@ -94,6 +101,14 @@ describe('settings center layout', () => { expect(appSource).toContain('width: 64'); expect(appSource).toContain('height: 64'); expect(appSource).toContain('minWidth: 260'); + expect(appSource).toContain('const releaseTimeText = formatAboutReleaseTime(lastUpdateInfo?.releasePublishedAt);'); + expect(appSource).toContain("[t('app.about.version.release_time'), releaseTimeText]"); + expect(appSource).toContain("gridTemplateColumns: 'minmax(0, 1fr) minmax(220px, 260px)'"); + expect(appSource).toContain('className="gonavi-about-update-channel"'); + expect(appSource).toContain(' ( + group === 'about' ? { key: 'about-go-navi', group: 'about' } : null +); + const DEFAULT_GLOBAL_PROXY_TEST_URL = 'https://api.github.com/'; type GlobalProxyTestResultState = { @@ -271,6 +275,18 @@ const formatAboutCheckedAt = (value: Date): string => { return `${value.getFullYear()}-${pad(value.getMonth() + 1)}-${pad(value.getDate())} ${pad(value.getHours())}:${pad(value.getMinutes())}`; }; +const formatAboutReleaseTime = (value: string | undefined): string => { + const text = String(value || '').trim(); + if (!text) { + return '-'; + } + const date = new Date(text); + if (Number.isNaN(date.getTime())) { + return '-'; + } + return formatAboutCheckedAt(date); +}; + type ConnectionPackageDialogState = { open: boolean; mode: ConnectionPackageDialogMode; @@ -2592,7 +2608,7 @@ function App() { }, []); const handleOpenSettingsModal = useCallback((group: SettingsCenterGroupKey = 'preferences') => { setActiveSettingsCenterGroupKey(group); - setActiveSettingsCenterPane(null); + setActiveSettingsCenterPane(resolveSettingsCenterGroupInitialPane(group)); setIsSettingsModalOpen(true); }, []); const handleOpenSettingsCenterPane = useCallback((group: SettingsCenterGroupKey, key: SettingsCenterPaneKey) => { @@ -3975,6 +3991,7 @@ function App() { : (lastUpdateInfo ? t('app.about.hero.no_update') : t('app.about.update_status.not_checked')); const currentVersionText = lastUpdateInfo?.currentVersion || aboutDisplayVersion; const releaseNotesText = lastUpdateInfo?.releaseName || (hasUpdate ? t('app.about.release_notes.fallback') : '-'); + const releaseTimeText = formatAboutReleaseTime(lastUpdateInfo?.releasePublishedAt); const cardBorder = darkMode ? 'rgba(255,255,255,0.10)' : 'rgba(16,24,40,0.11)'; const cardBg = darkMode ? 'rgba(255,255,255,0.03)' : 'rgba(255,255,255,0.82)'; const mutedText = utilityMutedTextStyle.color; @@ -3982,7 +3999,7 @@ function App() { const versionRows = [ [t('app.about.version.current'), currentVersionText], [t('app.about.version.latest'), latestVersionText], - [t('app.about.version.release_time'), '-'], + [t('app.about.version.release_time'), releaseTimeText], [t('app.about.version.release_notes'), releaseNotesText], ]; @@ -4071,36 +4088,37 @@ function App() { {t('app.about.version_update.title')}
-
-
+
+
{t('app.about.field.update_channel')}
-
{t('app.about.version_update.channel_hint')}
+ { + void changeUpdateChannel(String(value)); + }} + disabled={ + isUpdateChannelLoading + || isUpdateChannelSaving + || updateDownloadProgress.status === 'start' + || updateDownloadProgress.status === 'downloading' + } + block + style={{ width: '100%' }} + />
-