@@ -8,13 +8,14 @@ import { ResourceTreeDataProvider, TreeNode } from '../shared/treeview/resourceT
88import { Command , Commands } from '../shared/vscode/commands2'
99import { getIcon } from '../shared/icons'
1010import { contextKey , setContext } from '../shared/vscode/setContext'
11- import { NotificationType , ToolkitNotification } from './types'
11+ import { NotificationType , ToolkitNotification , getNotificationTelemetryId } from './types'
1212import { ToolkitError } from '../shared/errors'
1313import { isAmazonQ } from '../shared/extensionUtilities'
1414import { getLogger } from '../shared/logger/logger'
1515import { registerToolView } from '../awsexplorer/activationShared'
1616import { readonlyDocument } from '../shared/utilities/textDocumentUtilities'
1717import { openUrl } from '../shared/utilities/vsCodeUtils'
18+ import { telemetry } from '../shared/telemetry/telemetry'
1819
1920/**
2021 * Controls the "Notifications" side panel/tree in each extension. It takes purely UX actions
@@ -27,25 +28,25 @@ export class NotificationsNode implements TreeNode {
2728 public startUpNotifications : ToolkitNotification [ ] = [ ]
2829 public emergencyNotifications : ToolkitNotification [ ] = [ ]
2930
31+ /** Command executed when a notification item is clicked on in the panel. */
3032 private readonly openNotificationCmd : Command
3133 private readonly focusCmdStr : string
3234 private readonly showContextStr : contextKey
3335 private readonly startUpNodeContext : string
3436 private readonly emergencyNodeContext : string
3537
36- private readonly onDidChangeTreeItemEmitter = new vscode . EventEmitter < void > ( )
37- private readonly onDidChangeChildrenEmitter = new vscode . EventEmitter < void > ( )
38- private readonly onDidChangeVisibilityEmitter = new vscode . EventEmitter < void > ( )
39- public readonly onDidChangeTreeItem = this . onDidChangeTreeItemEmitter . event
40- public readonly onDidChangeChildren = this . onDidChangeChildrenEmitter . event
41- public readonly onDidChangeVisibility = this . onDidChangeVisibilityEmitter . event
42-
4338 static #instance: NotificationsNode
4439
4540 private constructor ( ) {
4641 this . openNotificationCmd = Commands . register (
4742 isAmazonQ ( ) ? '_aws.amazonq.notifications.open' : '_aws.toolkit.notifications.open' ,
48- async ( n : ToolkitNotification ) => this . openNotification ( n )
43+ ( n : ToolkitNotification ) => {
44+ telemetry . ui_click . emit ( {
45+ elementId : getNotificationTelemetryId ( n ) ,
46+ result : 'Succeeded' ,
47+ } )
48+ return this . openNotification ( n )
49+ }
4950 )
5051
5152 if ( isAmazonQ ( ) ) {
@@ -73,12 +74,6 @@ export class NotificationsNode implements TreeNode {
7374 const hasNotifications = this . startUpNotifications . length > 0 || this . emergencyNotifications . length > 0
7475 void setContext ( this . showContextStr , hasNotifications )
7576
76- this . onDidChangeChildrenEmitter . fire ( )
77- this . provider ?. refresh ( )
78- }
79-
80- public refreshRootNode ( ) {
81- this . onDidChangeTreeItemEmitter . fire ( )
8277 this . provider ?. refresh ( )
8378 }
8479
@@ -129,28 +124,34 @@ export class NotificationsNode implements TreeNode {
129124 * Fired when a notification is clicked on in the panel. It will run any rendering
130125 * instructions included in the notification. See {@link ToolkitNotification.uiRenderInstructions}.
131126 */
132- public async openNotification ( notification : ToolkitNotification ) {
127+ private async openNotification ( notification : ToolkitNotification ) {
133128 switch ( notification . uiRenderInstructions . onClick . type ) {
134129 case 'modal' :
135130 // Render blocking modal
136131 getLogger ( 'notifications' ) . verbose ( `rendering modal for notificaiton: ${ notification . id } ...` )
137- await this . showInformationWindow ( notification , 'modal' )
132+ await this . showInformationWindow ( notification , 'modal' , false )
138133 break
139134 case 'openUrl' :
135+ // Show open url option
140136 if ( ! notification . uiRenderInstructions . onClick . url ) {
141137 throw new ToolkitError ( 'No url provided for onclick open url' )
142138 }
143- // Show open url option
144139 getLogger ( 'notifications' ) . verbose ( `opening url for notification: ${ notification . id } ...` )
145- await openUrl ( vscode . Uri . parse ( notification . uiRenderInstructions . onClick . url ) )
140+ await openUrl (
141+ vscode . Uri . parse ( notification . uiRenderInstructions . onClick . url ) ,
142+ getNotificationTelemetryId ( notification )
143+ )
146144 break
147145 case 'openTextDocument' :
148146 // Display read-only txt document
149147 getLogger ( 'notifications' ) . verbose ( `showing txt document for notification: ${ notification . id } ...` )
150- await readonlyDocument . show (
151- notification . uiRenderInstructions . content [ 'en-US' ] . description ,
152- `Notification: ${ notification . id } `
153- )
148+ await telemetry . toolkit_invokeAction . run ( async ( ) => {
149+ telemetry . record ( { source : getNotificationTelemetryId ( notification ) , action : 'openTxt' } )
150+ await readonlyDocument . show (
151+ notification . uiRenderInstructions . content [ 'en-US' ] . description ,
152+ `Notification: ${ notification . id } `
153+ )
154+ } )
154155 break
155156 }
156157 }
@@ -160,57 +161,65 @@ export class NotificationsNode implements TreeNode {
160161 * Can be either a blocking modal or a bottom-right corner toast
161162 * Handles the button click actions based on the button type.
162163 */
163- public async showInformationWindow ( notification : ToolkitNotification , type : string = 'toast' ) {
164+ private showInformationWindow ( notification : ToolkitNotification , type : string = 'toast' , passive : boolean = false ) {
164165 const isModal = type === 'modal'
165166
166- // modal has to have defined actions(buttons)
167+ // modal has to have defined actions (buttons)
167168 const buttons = notification . uiRenderInstructions . actions ?? [ ]
168169 const buttonLabels = buttons . map ( ( actions ) => actions . displayText [ 'en-US' ] )
169170 const detail = notification . uiRenderInstructions . content [ 'en-US' ] . description
170171
171- // we use toastPreview to display as titlefor toast, since detail won't be shown
172+ // we use toastPreview to display as title for toast, since detail won't be shown
172173 const title = isModal
173174 ? notification . uiRenderInstructions . content [ 'en-US' ] . title
174175 : ( notification . uiRenderInstructions . content [ 'en-US' ] . toastPreview ??
175176 notification . uiRenderInstructions . content [ 'en-US' ] . title )
176177
177- const selectedText = await vscode . window . showInformationMessage (
178- title ,
179- { modal : isModal , detail } ,
180- ...buttonLabels
181- )
178+ telemetry . toolkit_showNotification . emit ( {
179+ id : getNotificationTelemetryId ( notification ) ,
180+ passive,
181+ component : 'editor' ,
182+ result : 'Succeeded' ,
183+ } )
182184
183- if ( selectedText ) {
184- const selectedButton = buttons . find ( ( actions ) => actions . displayText [ 'en-US' ] === selectedText )
185- // Different button options
186- if ( selectedButton ) {
187- switch ( selectedButton . type ) {
188- case 'openTxt' :
189- await readonlyDocument . show (
190- notification . uiRenderInstructions . content [ 'en-US' ] . description ,
191- `Notification: ${ notification . id } `
192- )
193- break
194- case 'updateAndReload' :
195- await this . updateAndReload ( notification . displayIf . extensionId )
196- break
197- case 'openUrl' :
198- if ( selectedButton . url ) {
199- await openUrl ( vscode . Uri . parse ( selectedButton . url ) )
200- } else {
201- throw new ToolkitError ( 'url not provided' )
185+ return vscode . window
186+ . showInformationMessage ( title , { modal : isModal , detail } , ...buttonLabels )
187+ . then ( ( response ) => {
188+ return telemetry . toolkit_invokeAction . run ( async ( span ) => {
189+ span . record ( { source : getNotificationTelemetryId ( notification ) , action : response ?? 'OK' } )
190+ if ( response ) {
191+ const selectedButton = buttons . find ( ( actions ) => actions . displayText [ 'en-US' ] === response )
192+ // Different button options
193+ if ( selectedButton ) {
194+ switch ( selectedButton . type ) {
195+ case 'openTxt' :
196+ await readonlyDocument . show (
197+ notification . uiRenderInstructions . content [ 'en-US' ] . description ,
198+ `Notification: ${ notification . id } `
199+ )
200+ break
201+ case 'updateAndReload' :
202+ await this . updateAndReload ( notification . displayIf . extensionId )
203+ break
204+ case 'openUrl' :
205+ if ( selectedButton . url ) {
206+ await openUrl ( vscode . Uri . parse ( selectedButton . url ) )
207+ } else {
208+ throw new ToolkitError ( 'url not provided' )
209+ }
210+ break
211+ default :
212+ throw new ToolkitError ( 'button action not defined' )
213+ }
202214 }
203- break
204- default :
205- throw new ToolkitError ( 'button action not defined' )
206- }
207- }
208- }
215+ }
216+ } )
217+ } )
209218 }
210219
211220 public async onReceiveNotifications ( notifications : ToolkitNotification [ ] ) {
212221 for ( const notification of notifications ) {
213- void this . showInformationWindow ( notification , notification . uiRenderInstructions . onRecieve )
222+ void this . showInformationWindow ( notification , notification . uiRenderInstructions . onRecieve , true )
214223 }
215224 }
216225
0 commit comments