@@ -12,7 +12,7 @@ import { ContextKeyExpr, IContextKeyService } from '../../../../platform/context
1212import { IDefaultAccountService } from '../../../../platform/defaultAccount/common/defaultAccount.js' ;
1313import { IInstantiationService , ServicesAccessor } from '../../../../platform/instantiation/common/instantiation.js' ;
1414import { IWorkbenchContribution , registerWorkbenchContribution2 , WorkbenchPhase } from '../../../../workbench/common/contributions.js' ;
15- import { appendUpdateMenuItems as registerUpdateMenuItems , CONTEXT_UPDATE_STATE } from '../../../../workbench/contrib/update/browser/update.js' ;
15+ import { appendUpdateMenuItems as registerUpdateMenuItems } from '../../../../workbench/contrib/update/browser/update.js' ;
1616import { Menus } from '../../../browser/menus.js' ;
1717import { IActionViewItemService } from '../../../../platform/actions/browser/actionViewItemService.js' ;
1818import { IContextMenuService } from '../../../../platform/contextview/browser/contextView.js' ;
@@ -23,9 +23,10 @@ import { IAction } from '../../../../base/common/actions.js';
2323import { Button } from '../../../../base/browser/ui/button/button.js' ;
2424import { defaultButtonStyles } from '../../../../platform/theme/browser/defaultStyles.js' ;
2525import { Codicon } from '../../../../base/common/codicons.js' ;
26- import { Downloading , IUpdateService , State , StateType } from '../../../../platform/update/common/update.js' ;
27- import { asCssVariable } from '../../../../platform/theme/common/colorUtils.js' ;
28- import { sessionsUpdateButtonDownloadingBackground , sessionsUpdateButtonDownloadedBackground } from '../../../common/theme.js' ;
26+ import { IUpdateService , StateType } from '../../../../platform/update/common/update.js' ;
27+ import { IHoverService } from '../../../../platform/hover/browser/hover.js' ;
28+ import { IProductService } from '../../../../platform/product/common/productService.js' ;
29+ import { UpdateHoverWidget } from './updateHoverWidget.js' ;
2930
3031// --- Account Menu Items --- //
3132const AccountMenu = new MenuId ( 'SessionsAccountMenu' ) ;
@@ -83,20 +84,26 @@ MenuRegistry.appendMenuItem(AccountMenu, {
8384// Update actions
8485registerUpdateMenuItems ( AccountMenu , '3_updates' ) ;
8586
86- class AccountWidget extends ActionViewItem {
87+ export class AccountWidget extends ActionViewItem {
8788
8889 private accountButton : Button | undefined ;
90+ private updateButton : Button | undefined ;
91+ private readonly updateHoverWidget : UpdateHoverWidget ;
8992 private readonly viewItemDisposables = this . _register ( new DisposableStore ( ) ) ;
9093
9194 constructor (
9295 action : IAction ,
9396 options : IBaseActionViewItemOptions ,
9497 @IDefaultAccountService private readonly defaultAccountService : IDefaultAccountService ,
98+ @IUpdateService private readonly updateService : IUpdateService ,
9599 @IContextMenuService private readonly contextMenuService : IContextMenuService ,
96100 @IMenuService private readonly menuService : IMenuService ,
97101 @IContextKeyService private readonly contextKeyService : IContextKeyService ,
102+ @IHoverService private readonly hoverService : IHoverService ,
103+ @IProductService private readonly productService : IProductService ,
98104 ) {
99105 super ( undefined , action , { ...options , icon : false , label : false } ) ;
106+ this . updateHoverWidget = new UpdateHoverWidget ( this . updateService , this . productService , this . hoverService ) ;
100107 }
101108
102109 protected override getTooltip ( ) : string | undefined {
@@ -121,14 +128,33 @@ class AccountWidget extends ActionViewItem {
121128 } ) ) ;
122129 this . accountButton . element . classList . add ( 'account-widget-account-button' , 'sidebar-action-button' ) ;
123130
131+ // Update button (right)
132+ const updateContainer = append ( container , $ ( '.account-widget-update' ) ) ;
133+ this . updateButton = this . viewItemDisposables . add ( new Button ( updateContainer , {
134+ ...defaultButtonStyles ,
135+ secondary : true ,
136+ title : false ,
137+ supportIcons : true ,
138+ buttonSecondaryBackground : 'transparent' ,
139+ buttonSecondaryHoverBackground : undefined ,
140+ buttonSecondaryForeground : undefined ,
141+ buttonSecondaryBorder : undefined ,
142+ } ) ) ;
143+ this . updateButton . element . classList . add ( 'account-widget-update-button' , 'sidebar-action-button' ) ;
144+ this . viewItemDisposables . add ( this . updateHoverWidget . attachTo ( this . updateButton . element ) ) ;
145+
124146 this . updateAccountButton ( ) ;
125147 this . viewItemDisposables . add ( this . defaultAccountService . onDidChangeDefaultAccount ( ( ) => this . updateAccountButton ( ) ) ) ;
148+ this . updateUpdateButton ( ) ;
149+ this . viewItemDisposables . add ( this . updateService . onStateChange ( ( ) => this . updateUpdateButton ( ) ) ) ;
126150
127151 this . viewItemDisposables . add ( this . accountButton . onDidClick ( e => {
128152 e ?. preventDefault ( ) ;
129153 e ?. stopPropagation ( ) ;
130154 this . showAccountMenu ( this . accountButton ! . element ) ;
131155 } ) ) ;
156+
157+ this . viewItemDisposables . add ( this . updateButton . onDidClick ( ( ) => this . update ( ) ) ) ;
132158 }
133159
134160 private showAccountMenu ( anchor : HTMLElement ) : void {
@@ -156,134 +182,57 @@ class AccountWidget extends ActionViewItem {
156182 : `$(${ Codicon . account . id } ) ${ localize ( 'signInLabel' , "Sign In" ) } ` ;
157183 }
158184
159-
160- override onClick ( ) : void {
161- // Handled by custom click handlers
162- }
163- }
164-
165- export class UpdateWidget extends ActionViewItem {
166-
167- private updateButton : Button | undefined ;
168- private readonly viewItemDisposables = this . _register ( new DisposableStore ( ) ) ;
169-
170- constructor (
171- action : IAction ,
172- options : IBaseActionViewItemOptions ,
173- @IUpdateService private readonly updateService : IUpdateService ,
174- ) {
175- super ( undefined , action , { ...options , icon : false , label : false } ) ;
176- }
177-
178- protected override getTooltip ( ) : string | undefined {
179- return undefined ;
180- }
181-
182- override render ( container : HTMLElement ) : void {
183- super . render ( container ) ;
184- container . classList . add ( 'update-widget' , 'sidebar-action' ) ;
185-
186- const updateContainer = append ( container , $ ( '.update-widget-action' ) ) ;
187- this . updateButton = this . viewItemDisposables . add ( new Button ( updateContainer , {
188- ...defaultButtonStyles ,
189- secondary : true ,
190- title : false ,
191- supportIcons : true ,
192- buttonSecondaryBackground : 'transparent' ,
193- buttonSecondaryHoverBackground : undefined ,
194- buttonSecondaryForeground : undefined ,
195- buttonSecondaryBorder : undefined ,
196- } ) ) ;
197- this . updateButton . element . classList . add ( 'update-widget-button' , 'sidebar-action-button' ) ;
198- this . viewItemDisposables . add ( this . updateButton . onDidClick ( ( ) => this . update ( ) ) ) ;
199-
200- this . updateUpdateButton ( ) ;
201- this . viewItemDisposables . add ( this . updateService . onStateChange ( ( ) => this . updateUpdateButton ( ) ) ) ;
202- }
203-
204- private isUpdateReady ( ) : boolean {
205- return this . updateService . state . type === StateType . Ready ;
206- }
207-
208- private isUpdatePending ( ) : boolean {
209- const type = this . updateService . state . type ;
210- return type === StateType . AvailableForDownload
211- || type === StateType . CheckingForUpdates
212- || type === StateType . Downloading
213- || type === StateType . Downloaded
214- || type === StateType . Updating
215- || type === StateType . Overwriting ;
216- }
217-
218185 private updateUpdateButton ( ) : void {
219186 if ( ! this . updateButton ) {
220187 return ;
221188 }
222189
223190 const state = this . updateService . state ;
224- if ( this . isUpdatePending ( ) && ! this . isUpdateReady ( ) ) {
225- this . updateButton . enabled = false ;
226- this . updateButton . label = `$(${ Codicon . loading . id } ~spin) ${ this . getUpdateProgressMessage ( state . type ) } ` ;
227- this . updateDownloadProgress ( state ) ;
228- } else {
229- this . updateButton . enabled = true ;
230- this . updateButton . label = `$(${ Codicon . debugRestart . id } ) ${ localize ( 'update' , "Update" ) } ` ;
231-
232- const el = this . updateButton . element ;
233- if ( state . type === StateType . Ready ) {
234- const color = asCssVariable ( sessionsUpdateButtonDownloadedBackground ) ;
235- el . style . backgroundImage = `linear-gradient(to right, ${ color } 100%, transparent 100%)` ;
236- } else {
237- // Ensure non-update states (e.g. Idle, Disabled, Uninitialized) do not look like a completed download
238- el . style . backgroundImage = '' ;
239- }
191+ if ( this . shouldHideUpdateButton ( state . type ) ) {
192+ this . clearUpdateButtonStyling ( ) ;
193+ this . updateButton . element . classList . add ( 'hidden' ) ;
194+ return ;
240195 }
241- }
242196
243- private updateDownloadProgress ( state : State ) : void {
244- if ( ! this . updateButton ) {
197+ this . updateButton . element . classList . remove ( 'hidden' ) ;
198+ this . updateButton . element . style . backgroundImage = '' ;
199+ this . updateButton . enabled = state . type === StateType . Ready ;
200+ this . updateButton . label = this . getUpdateProgressMessage ( state . type ) ;
201+
202+ if ( state . type === StateType . Ready ) {
203+ this . updateButton . element . classList . add ( 'account-widget-update-button-ready' ) ;
245204 return ;
246205 }
247206
248- const el = this . updateButton . element ;
249-
250- if ( state . type === StateType . Downloading ) {
251- const { downloadedBytes, totalBytes } = state as Downloading ;
252- if ( downloadedBytes !== undefined && totalBytes && totalBytes > 0 ) {
253- const percent = Math . min ( 100 , Math . round ( ( downloadedBytes / totalBytes ) * 100 ) ) ;
254- const color = asCssVariable ( sessionsUpdateButtonDownloadingBackground ) ;
255- el . style . backgroundImage = `linear-gradient(to right, ${ color } ${ percent } %, transparent ${ percent } %)` ;
256- } else {
257- // Indeterminate: show a subtle pulsing background
258- const color = asCssVariable ( sessionsUpdateButtonDownloadingBackground ) ;
259- el . style . backgroundImage = `linear-gradient(to right, ${ color } 0%, transparent 100%)` ;
260- }
261- } else if ( state . type === StateType . Downloaded ) {
262- const color = asCssVariable ( sessionsUpdateButtonDownloadedBackground ) ;
263- el . style . backgroundImage = `linear-gradient(to right, ${ color } 100%, transparent 100%)` ;
264- } else {
265- this . clearDownloadProgress ( ) ;
266- }
207+ this . updateButton . element . classList . remove ( 'account-widget-update-button-ready' ) ;
208+ }
209+
210+ private shouldHideUpdateButton ( type : StateType ) : boolean {
211+ return type === StateType . Uninitialized
212+ || type === StateType . Idle
213+ || type === StateType . Disabled
214+ || type === StateType . CheckingForUpdates ;
267215 }
268216
269- private clearDownloadProgress ( ) : void {
217+ private clearUpdateButtonStyling ( ) : void {
270218 if ( this . updateButton ) {
271219 this . updateButton . element . style . backgroundImage = '' ;
220+ this . updateButton . element . classList . remove ( 'account-widget-update-button-ready' ) ;
272221 }
273222 }
274223
275224 private getUpdateProgressMessage ( type : StateType ) : string {
276225 switch ( type ) {
277- case StateType . CheckingForUpdates :
278- return localize ( 'checkingForUpdates' , "Checking for Updates..." ) ;
226+ case StateType . Ready :
227+ return localize ( 'update' , "Update" ) ;
228+ case StateType . AvailableForDownload :
279229 case StateType . Downloading :
280- return localize ( 'downloadingUpdate' , "Downloading Update..." ) ;
230+ case StateType . Overwriting :
231+ return localize ( 'downloadingUpdate' , "Downloading..." ) ;
281232 case StateType . Downloaded :
282- return localize ( 'installingUpdate' , "Installing Update ..." ) ;
233+ return localize ( 'installingUpdate' , "Installing..." ) ;
283234 case StateType . Updating :
284235 return localize ( 'updatingApp' , "Updating..." ) ;
285- case StateType . Overwriting :
286- return localize ( 'overwritingUpdate' , "Downloading Update..." ) ;
287236 default :
288237 return localize ( 'updating' , "Updating..." ) ;
289238 }
@@ -293,6 +242,7 @@ export class UpdateWidget extends ActionViewItem {
293242 await this . updateService . quitAndInstall ( ) ;
294243 }
295244
245+
296246 override onClick ( ) : void {
297247 // Handled by custom click handlers
298248 }
@@ -315,11 +265,6 @@ class AccountWidgetContribution extends Disposable implements IWorkbenchContribu
315265 return instantiationService . createInstance ( AccountWidget , action , options ) ;
316266 } , undefined ) ) ;
317267
318- const sessionsUpdateWidgetAction = 'sessions.action.updateWidget' ;
319- this . _register ( actionViewItemService . register ( Menus . SidebarFooter , sessionsUpdateWidgetAction , ( action , options ) => {
320- return instantiationService . createInstance ( UpdateWidget , action , options ) ;
321- } , undefined ) ) ;
322-
323268 // Register the action with menu item after the view item provider
324269 // so the toolbar picks up the custom widget
325270 this . _register ( registerAction2 ( class extends Action2 {
@@ -339,30 +284,6 @@ class AccountWidgetContribution extends Disposable implements IWorkbenchContribu
339284 }
340285 } ) ) ;
341286
342- this . _register ( registerAction2 ( class extends Action2 {
343- constructor ( ) {
344- super ( {
345- id : sessionsUpdateWidgetAction ,
346- title : localize2 ( 'sessionsUpdateWidget' , 'Sessions Update' ) ,
347- menu : {
348- id : Menus . SidebarFooter ,
349- group : 'navigation' ,
350- order : 0 ,
351- when : ContextKeyExpr . or (
352- CONTEXT_UPDATE_STATE . isEqualTo ( StateType . Ready ) ,
353- CONTEXT_UPDATE_STATE . isEqualTo ( StateType . AvailableForDownload ) ,
354- CONTEXT_UPDATE_STATE . isEqualTo ( StateType . Downloading ) ,
355- CONTEXT_UPDATE_STATE . isEqualTo ( StateType . Downloaded ) ,
356- CONTEXT_UPDATE_STATE . isEqualTo ( StateType . Updating ) ,
357- CONTEXT_UPDATE_STATE . isEqualTo ( StateType . Overwriting ) ,
358- )
359- }
360- } ) ;
361- }
362- async run ( ) : Promise < void > {
363- // Handled by the custom view item
364- }
365- } ) ) ;
366287 }
367288}
368289
0 commit comments