@@ -83,6 +83,10 @@ export function App() {
8383 updateStatus ?. releaseUrl || 'https://github.com/webrenew/agent-observer/releases/latest'
8484 ) , [ updateStatus ?. releaseUrl ] )
8585
86+ const openUpdateDownloadPage = useCallback ( ( ) => {
87+ window . open ( updateDownloadUrl , '_blank' , 'noopener,noreferrer' )
88+ } , [ updateDownloadUrl ] )
89+
8690 const handleInstallUpdate = useCallback ( ( ) => {
8791 if ( installingUpdate ) return
8892 setInstallingUpdate ( true )
@@ -91,15 +95,36 @@ export function App() {
9195 const accepted = await window . electronAPI . updates . installAndRestart ( )
9296 if ( ! accepted ) {
9397 setInstallingUpdate ( false )
94- window . open ( updateDownloadUrl , '_blank' , 'noopener,noreferrer' )
98+ openUpdateDownloadPage ( )
9599 }
96100 } catch ( err ) {
97101 setInstallingUpdate ( false )
98102 console . warn ( '[App] install update failed:' , err )
99- window . open ( updateDownloadUrl , '_blank' , 'noopener,noreferrer' )
103+ openUpdateDownloadPage ( )
100104 }
101105 } ) ( )
102- } , [ installingUpdate , updateDownloadUrl ] )
106+ } , [ installingUpdate , openUpdateDownloadPage ] )
107+
108+ const normalizedLatestVersion = updateStatus ?. latestVersion
109+ ? updateStatus . latestVersion . replace ( / ^ v / i, '' )
110+ : null
111+
112+ const updateBannerMessage = useMemo ( ( ) => {
113+ if ( ! updateStatus ) return null
114+ const versionSuffix = normalizedLatestVersion ? ` (v${ normalizedLatestVersion } )` : ''
115+ if ( updateStatus . canInstall ) return `Update ready${ versionSuffix } .`
116+ if ( ! updateStatus . updateAvailable ) return null
117+
118+ if ( updateStatus . phase === 'downloading' ) {
119+ const progress = updateStatus . downloadPercent
120+ const progressText = typeof progress === 'number' && Number . isFinite ( progress )
121+ ? ` ${ Math . round ( progress ) } %`
122+ : ''
123+ return `Update available${ versionSuffix } . Downloading…${ progressText } `
124+ }
125+
126+ return `Update available${ versionSuffix } . Downloading…`
127+ } , [ normalizedLatestVersion , updateStatus ] )
103128
104129 return (
105130 < div className = "w-full h-full" style = { { display : 'flex' , flexDirection : 'column' } } >
@@ -108,7 +133,7 @@ export function App() {
108133 < WorkspaceLayout />
109134 </ ErrorBoundary >
110135 </ div >
111- { updateStatus ?. canInstall ? (
136+ { updateBannerMessage ? (
112137 < div
113138 style = { {
114139 position : 'fixed' ,
@@ -127,27 +152,44 @@ export function App() {
127152 fontSize : 12 ,
128153 } }
129154 >
130- < span >
131- Update ready{ updateStatus . latestVersion ? ` (v${ updateStatus . latestVersion . replace ( / ^ v / i, '' ) } )` : '' } .
132- </ span >
133- < button
134- type = "button"
135- onClick = { handleInstallUpdate }
136- disabled = { installingUpdate }
137- style = { {
138- border : '1px solid rgba(84, 140, 90, 0.6)' ,
139- background : installingUpdate ? '#2a2f2a' : '#1E2920' ,
140- color : installingUpdate ? '#9A9692' : '#d8dfd3' ,
141- borderRadius : 6 ,
142- fontSize : 11 ,
143- fontWeight : 600 ,
144- padding : '6px 10px' ,
145- cursor : installingUpdate ? 'default' : 'pointer' ,
146- opacity : installingUpdate ? 0.75 : 1 ,
147- } }
148- >
149- { installingUpdate ? 'Restarting…' : 'Install update and restart' }
150- </ button >
155+ < span > { updateBannerMessage } </ span >
156+ { updateStatus ?. canInstall ? (
157+ < button
158+ type = "button"
159+ onClick = { handleInstallUpdate }
160+ disabled = { installingUpdate }
161+ style = { {
162+ border : '1px solid rgba(84, 140, 90, 0.6)' ,
163+ background : installingUpdate ? '#2a2f2a' : '#1E2920' ,
164+ color : installingUpdate ? '#9A9692' : '#d8dfd3' ,
165+ borderRadius : 6 ,
166+ fontSize : 11 ,
167+ fontWeight : 600 ,
168+ padding : '6px 10px' ,
169+ cursor : installingUpdate ? 'default' : 'pointer' ,
170+ opacity : installingUpdate ? 0.75 : 1 ,
171+ } }
172+ >
173+ { installingUpdate ? 'Restarting…' : 'Install update and restart' }
174+ </ button >
175+ ) : (
176+ < button
177+ type = "button"
178+ onClick = { openUpdateDownloadPage }
179+ style = { {
180+ border : '1px solid rgba(84, 140, 90, 0.6)' ,
181+ background : '#1E2920' ,
182+ color : '#d8dfd3' ,
183+ borderRadius : 6 ,
184+ fontSize : 11 ,
185+ fontWeight : 600 ,
186+ padding : '6px 10px' ,
187+ cursor : 'pointer' ,
188+ } }
189+ >
190+ Open release
191+ </ button >
192+ ) }
151193 </ div >
152194 ) : null }
153195 { isSettingsOpen ? (
0 commit comments