Skip to content

Commit 5d2ddad

Browse files
committed
feat(amazonq): Add UI Update for Progress bar and New button for Cancelling Code Generation
1 parent 0a40071 commit 5d2ddad

File tree

7 files changed

+76
-15
lines changed

7 files changed

+76
-15
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"type": "Feature",
3+
"description": "Add Progress Bar UI changes and new button for cancelling code generation to /dev"
4+
}

packages/core/src/amazonq/webview/ui/apps/featureDevChatConnector.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* SPDX-License-Identifier: Apache-2.0
44
*/
55

6-
import { ChatItem, ChatItemType, FeedbackPayload } from '@aws/mynah-ui'
6+
import { ChatItem, ChatItemType, FeedbackPayload, ProgressField } from '@aws/mynah-ui'
77
import { TabType } from '../storages/tabsStorage'
88
import { getActions } from '../diffTree/actions'
99
import { DiffTreeFileInfo } from '../diffTree/types'
@@ -31,6 +31,9 @@ export interface ConnectorProps extends BaseConnectorProps {
3131
onChatInputEnabled: (tabID: string, enabled: boolean) => void
3232
onUpdateAuthentication: (featureDevEnabled: boolean, authenticatingTabIDs: string[]) => void
3333
onNewTab: (tabType: TabType) => void
34+
onUpdatePromptProgress: (tabID: string, progressField: ProgressField | null) => void;
35+
onCustomFormAction?: (tabID: string, action: any) => void
36+
3437
}
3538

3639
export class Connector extends BaseConnector {
@@ -41,6 +44,8 @@ export class Connector extends BaseConnector {
4144
private readonly chatInputEnabled
4245
private readonly onUpdateAuthentication
4346
private readonly onNewTab
47+
private readonly onUpdatePromptProgress
48+
4449

4550
override getTabType(): TabType {
4651
return 'featuredev'
@@ -55,6 +60,12 @@ export class Connector extends BaseConnector {
5560
this.onUpdateAuthentication = props.onUpdateAuthentication
5661
this.onNewTab = props.onNewTab
5762
this.onChatAnswerUpdated = props.onChatAnswerUpdated
63+
this.onUpdatePromptProgress = props.onUpdatePromptProgress;
64+
}
65+
66+
sendProgressUpdate(tabID: string, progressField: ProgressField | null): void {
67+
this.onUpdatePromptProgress(tabID, progressField);
68+
5869
}
5970

6071
onOpenDiff = (tabID: string, filePath: string, deleted: boolean, messageId?: string): void => {
@@ -199,6 +210,10 @@ export class Connector extends BaseConnector {
199210
this.onNewTab('featuredev')
200211
return
201212
}
213+
if (messageData.type === 'updatePromptProgress') {
214+
this.sendProgressUpdate(messageData.tabID, messageData.progressField);
215+
return;
216+
}
202217

203218
// For other message types, call the base class handleMessageReceive
204219
await this.baseHandleMessageReceive(messageData)

packages/core/src/amazonq/webview/ui/connector.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ export interface ConnectorProps {
8080
disableFileActions: boolean
8181
) => void
8282
onUpdatePlaceholder: (tabID: string, newPlaceholder: string) => void
83-
onUpdatePromptProgress: (tabID: string, progressField: ProgressField) => void
83+
onUpdatePromptProgress: (tabID: string, progressField: ProgressField | null) => void;
8484
onChatInputEnabled: (tabID: string, enabled: boolean) => void
8585
onUpdateAuthentication: (featureDevEnabled: boolean, authenticatingTabIDs: string[]) => void
8686
onNewTab: (tabType: TabType) => void
@@ -129,8 +129,7 @@ export class Connector {
129129
this.cwChatConnector.onSourceLinkClick(tabID, messageId, link)
130130
break
131131
}
132-
}
133-
132+
}
134133
onResponseBodyLinkClick = (tabID: string, messageId: string, link: string): void => {
135134
switch (this.tabsStorage.getTab(tabID)?.type) {
136135
case 'cwc':
@@ -625,6 +624,11 @@ export class Connector {
625624
eventId: string | undefined = undefined
626625
): void | undefined => {
627626
switch (this.tabsStorage.getTab(tabId)?.type) {
627+
case 'featuredev':
628+
if (action.id === 'cancel-running-task') {
629+
this.onStopChatResponse(tabId);
630+
}
631+
break
628632
case 'gumby':
629633
this.gumbyChatConnector.onCustomFormAction(tabId, action)
630634
break

packages/core/src/amazonq/webview/ui/main.ts

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,7 @@ export const createMynahUI = (
250250
promptInputDisabledState: tabsStorage.isTabDead(tabID) || !enabled,
251251
})
252252
},
253-
onUpdatePromptProgress(tabID: string, progressField: ProgressField) {
253+
onUpdatePromptProgress(tabID: string, progressField: ProgressField | null) {
254254
mynahUI.updateStore(tabID, {
255255
promptInputProgress: progressField,
256256
})
@@ -266,7 +266,6 @@ export const createMynahUI = (
266266
mynahUI.updateStore(tabID, {
267267
loadingChat: true,
268268
promptInputDisabledState: true,
269-
cancelButtonWhenLoading: enableStopAction,
270269
})
271270

272271
if (message && messageId) {
@@ -364,7 +363,6 @@ export const createMynahUI = (
364363
) {
365364
mynahUI.updateStore(tabID, {
366365
loadingChat: true,
367-
cancelButtonWhenLoading: false,
368366
promptInputDisabledState: true,
369367
})
370368

@@ -672,11 +670,10 @@ export const createMynahUI = (
672670
}
673671
}
674672
},
675-
onCustomFormAction: (tabId, action, eventId) => {
676-
connector.onCustomFormAction(tabId, undefined, action, eventId)
677-
},
678673
onChatPromptProgressActionButtonClicked: (tabID, action) => {
679-
connector.onCustomFormAction(tabID, undefined, action)
674+
if (action.id === 'cancel-running-task') {
675+
connector.onStopChatResponse(tabID);
676+
}
680677
},
681678
onSendFeedback: (tabId, feedbackPayload) => {
682679
connector.sendFeedback(tabId, feedbackPayload)

packages/core/src/amazonqFeatureDev/app.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ export function init(appContext: AmazonQAppInitContext) {
3535
insertCodeAtPositionClicked: new vscode.EventEmitter<any>(),
3636
fileClicked: new vscode.EventEmitter<any>(),
3737
storeCodeResultMessageId: new vscode.EventEmitter<any>(),
38+
processCustomFormAction: new vscode.EventEmitter<any>(),
3839
}
3940

4041
const messenger = new Messenger(

packages/core/src/amazonqFeatureDev/controllers/chat/controller.ts

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* SPDX-License-Identifier: Apache-2.0
44
*/
55

6-
import { MynahIcons } from '@aws/mynah-ui'
6+
import { MynahIcons, ProgressField } from '@aws/mynah-ui'
77
import * as path from 'path'
88
import * as vscode from 'vscode'
99
import { EventEmitter } from 'vscode'
@@ -65,6 +65,8 @@ export interface ChatControllerEventEmitters {
6565
readonly insertCodeAtPositionClicked: EventEmitter<any>
6666
readonly fileClicked: EventEmitter<any>
6767
readonly storeCodeResultMessageId: EventEmitter<any>
68+
readonly processCustomFormAction: EventEmitter<any>
69+
6870
}
6971

7072
type OpenDiffMessage = {
@@ -116,7 +118,12 @@ export class FeatureDevController {
116118
onDidChangeAmazonQVisibility((visible) => {
117119
this.isAmazonQVisible = visible
118120
})
119-
121+
this.chatControllerMessageListeners.processCustomFormAction.event((data) => {
122+
if (data.action?.id === 'cancel-running-task') {
123+
this.stopResponse({ tabID: data.tabID });
124+
}
125+
});
126+
120127
this.chatControllerMessageListeners.processHumanChatMessage.event((data) => {
121128
this.processUserChatMessage(data).catch((e) => {
122129
getLogger().error('processUserChatMessage failed: %s', (e as Error).message)
@@ -396,7 +403,23 @@ export class FeatureDevController {
396403
* Handle a regular incoming message when a user is in the code generation phase
397404
*/
398405
private async onCodeGeneration(session: Session, message: string, tabID: string) {
399-
// lock the UI/show loading bubbles
406+
407+
const updateProgress = (text: string) => {
408+
const progressField: ProgressField = {
409+
status: 'default',
410+
text: text,
411+
value: -1,
412+
actions: [{
413+
id: 'cancel-running-task',
414+
text: 'Cancel',
415+
icon: 'cancel' as MynahIcons,
416+
disabled: false,
417+
}]
418+
};
419+
this.messenger.sendUpdatePromptProgress(tabID, progressField);
420+
this.messenger.sendAsyncEventProgress(tabID, true, text);
421+
};
422+
400423
this.messenger.sendAsyncEventProgress(
401424
tabID,
402425
true,
@@ -405,13 +428,21 @@ export class FeatureDevController {
405428
: i18n('AWS.amazonq.featureDev.pillText.awaitMessageRetry')
406429
)
407430

431+
updateProgress(session.retries === codeGenRetryLimit
432+
? i18n('AWS.amazonq.featureDev.pillText.awaitMessage')
433+
: i18n('AWS.amazonq.featureDev.pillText.awaitMessageRetry'));
434+
408435
try {
436+
437+
updateProgress(i18n('AWS.amazonq.featureDev.pillText.requestingChanges'));
409438
this.messenger.sendAnswer({
410439
message: i18n('AWS.amazonq.featureDev.pillText.requestingChanges'),
411440
type: 'answer-stream',
412441
tabID,
413442
canBeVoted: true,
414443
})
444+
445+
updateProgress(i18n('AWS.amazonq.featureDev.pillText.generatingCode'));
415446
this.messenger.sendUpdatePlaceholder(tabID, i18n('AWS.amazonq.featureDev.pillText.generatingCode'))
416447
await session.send(message)
417448
const filePaths = session.state.filePaths ?? []
@@ -447,6 +478,7 @@ export class FeatureDevController {
447478
return
448479
}
449480

481+
updateProgress(i18n('AWS.amazonq.featureDev.pillText.processingChanges'));
450482
this.messenger.sendCodeResult(
451483
filePaths,
452484
deletedFiles,
@@ -487,7 +519,7 @@ export class FeatureDevController {
487519
}
488520
this.messenger.sendUpdatePlaceholder(tabID, i18n('AWS.amazonq.featureDev.pillText.selectOption'))
489521
} finally {
490-
// Finish processing the event
522+
this.hideProgress(tabID);
491523

492524
if (session?.state?.tokenSource?.token.isCancellationRequested) {
493525
this.workOnNewTask(
@@ -849,6 +881,7 @@ export class FeatureDevController {
849881
i18n('AWS.amazonq.featureDev.pillText.stoppingCodeGeneration')
850882
)
851883
this.messenger.sendChatInputEnabled(message.tabID, false)
884+
this.hideProgress(message.tabID);
852885

853886
const session = await this.sessionStorage.getSession(message.tabID)
854887
if (session.state?.tokenSource) {
@@ -940,6 +973,11 @@ export class FeatureDevController {
940973
})
941974
}
942975

976+
private hideProgress(tabID: string) {
977+
this.messenger.sendUpdatePromptProgress(tabID, null);
978+
this.messenger.sendAsyncEventProgress(tabID, false, undefined);
979+
}
980+
943981
private sendFeedback() {
944982
void submitFeedback(placeholder, 'Amazon Q')
945983
}

packages/core/src/test/amazonqFeatureDev/utils.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ export function createMockChatEmitters(): ChatControllerEventEmitters {
4141
insertCodeAtPositionClicked: new vscode.EventEmitter<any>(),
4242
fileClicked: new vscode.EventEmitter<any>(),
4343
storeCodeResultMessageId: new vscode.EventEmitter<any>(),
44+
processCustomFormAction: new vscode.EventEmitter<any>(),
45+
4446
}
4547
}
4648

0 commit comments

Comments
 (0)