Skip to content

Commit 57788a9

Browse files
committed
Add a spinner modal for applying changes and integrate its display using new SHOW_APPLYING_CHANGES and HIDE_APPLYING_CHANGES messages
1 parent 907fa9c commit 57788a9

8 files changed

Lines changed: 185 additions & 83 deletions

File tree

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
.spinner_container {
2+
display: flex;
3+
justify-content: center;
4+
align-items: center;
5+
}
6+
7+
.spinner {
8+
border: 4px solid var(--vscode-input-background);
9+
border-top: 4px solid var(--vscode-focusBorder);
10+
border-radius: 50%;
11+
width: 30px;
12+
height: 30px;
13+
animation: spin 1s linear infinite;
14+
}
15+
16+
@keyframes spin {
17+
0% {
18+
transform: rotate(0deg);
19+
}
20+
100% {
21+
transform: rotate(360deg);
22+
}
23+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { ApplyingChangesModal } from './ApplyingChangesModal'
2+
3+
export default {
4+
component: ApplyingChangesModal
5+
}
6+
7+
export const Default = () => {
8+
return <ApplyingChangesModal title="Applying changes..." />
9+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { useEffect, useState } from 'react'
2+
import { Modal } from '../Modal'
3+
import styles from './ApplyingChangesModal.module.scss'
4+
5+
type Props = {
6+
title: string
7+
}
8+
9+
export const ApplyingChangesModal: React.FC<Props> = (props) => {
10+
const [show_modal, set_show_modal] = useState(false)
11+
12+
useEffect(() => {
13+
const timer = setTimeout(() => {
14+
set_show_modal(true)
15+
}, 1000)
16+
17+
return () => {
18+
clearTimeout(timer)
19+
}
20+
}, [])
21+
22+
if (!show_modal) {
23+
return null
24+
}
25+
26+
return (
27+
<Modal
28+
title={props.title}
29+
content_slot={
30+
<div className={styles.spinner_container}>
31+
<div className={styles.spinner} />
32+
</div>
33+
}
34+
/>
35+
)
36+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './ApplyingChangesModal'

‎packages/vscode/src/commands/apply-chat-response-command/apply-chat-response-command.ts‎

Lines changed: 92 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -157,105 +157,114 @@ export const apply_chat_response_command = (
157157
})
158158

159159
if (changes_accepted) {
160-
const workspace_map = new Map<string, string>()
161-
vscode.workspace.workspaceFolders!.forEach((folder) => {
162-
workspace_map.set(folder.name, folder.uri.fsPath)
163-
})
164-
const default_workspace =
165-
vscode.workspace.workspaceFolders![0].uri.fsPath
160+
panel_provider.send_message({ command: 'SHOW_APPLYING_CHANGES' })
161+
try {
162+
const workspace_map = new Map<string, string>()
163+
vscode.workspace.workspaceFolders!.forEach((folder) => {
164+
workspace_map.set(folder.name, folder.uri.fsPath)
165+
})
166+
const default_workspace =
167+
vscode.workspace.workspaceFolders![0].uri.fsPath
166168

167-
const accepted_states: {
168-
file_path: string
169-
workspace_name?: string
170-
content: string
171-
is_deleted: boolean
172-
}[] = []
169+
const accepted_states: {
170+
file_path: string
171+
workspace_name?: string
172+
content: string
173+
is_deleted: boolean
174+
}[] = []
173175

174-
for (const state of review_data.original_states) {
175-
let workspace_root = default_workspace
176-
if (
177-
state.workspace_name &&
178-
workspace_map.has(state.workspace_name)
179-
) {
180-
workspace_root = workspace_map.get(state.workspace_name)!
181-
}
176+
for (const state of review_data.original_states) {
177+
let workspace_root = default_workspace
178+
if (
179+
state.workspace_name &&
180+
workspace_map.has(state.workspace_name)
181+
) {
182+
workspace_root = workspace_map.get(state.workspace_name)!
183+
}
182184

183-
const sanitized_file_path = create_safe_path(
184-
workspace_root,
185-
state.file_path
186-
)
187-
if (!sanitized_file_path) {
188-
continue
185+
const sanitized_file_path = create_safe_path(
186+
workspace_root,
187+
state.file_path
188+
)
189+
if (!sanitized_file_path) {
190+
continue
191+
}
192+
193+
const exists = fs.existsSync(sanitized_file_path)
194+
const content = exists
195+
? fs.readFileSync(sanitized_file_path, 'utf8')
196+
: ''
197+
198+
accepted_states.push({
199+
file_path: state.file_path,
200+
workspace_name: state.workspace_name,
201+
content: content,
202+
is_deleted: !exists
203+
})
189204
}
190205

191-
const exists = fs.existsSync(sanitized_file_path)
192-
const content = exists
193-
? fs.readFileSync(sanitized_file_path, 'utf8')
194-
: ''
206+
await undo_files({ original_states: review_data.original_states })
195207

196-
accepted_states.push({
197-
file_path: state.file_path,
198-
workspace_name: state.workspace_name,
199-
content: content,
200-
is_deleted: !exists
201-
})
202-
}
208+
await create_checkpoint(
209+
workspace_provider,
210+
context,
211+
'Before changes approved',
212+
args?.raw_instructions
213+
)
203214

204-
await undo_files({ original_states: review_data.original_states })
215+
for (const accepted_state of accepted_states) {
216+
let workspace_root = default_workspace
217+
if (
218+
accepted_state.workspace_name &&
219+
workspace_map.has(accepted_state.workspace_name)
220+
) {
221+
workspace_root = workspace_map.get(
222+
accepted_state.workspace_name
223+
)!
224+
}
225+
const sanitized_file_path = create_safe_path(
226+
workspace_root,
227+
accepted_state.file_path
228+
)
229+
if (!sanitized_file_path) continue
205230

206-
await create_checkpoint(
207-
workspace_provider,
208-
context,
209-
'Before changes approved',
210-
args?.raw_instructions
211-
)
231+
if (accepted_state.is_deleted) {
232+
if (fs.existsSync(sanitized_file_path)) {
233+
const tabs_to_close: vscode.Tab[] = []
234+
for (const tab_group of vscode.window.tabGroups.all) {
235+
tabs_to_close.push(
236+
...tab_group.tabs.filter((tab) => {
237+
const tab_uri = (tab.input as any)?.uri as
238+
| vscode.Uri
239+
| undefined
240+
return tab_uri && tab_uri.fsPath == sanitized_file_path
241+
})
242+
)
243+
}
212244

213-
for (const accepted_state of accepted_states) {
214-
let workspace_root = default_workspace
215-
if (
216-
accepted_state.workspace_name &&
217-
workspace_map.has(accepted_state.workspace_name)
218-
) {
219-
workspace_root = workspace_map.get(accepted_state.workspace_name)!
220-
}
221-
const sanitized_file_path = create_safe_path(
222-
workspace_root,
223-
accepted_state.file_path
224-
)
225-
if (!sanitized_file_path) continue
245+
if (tabs_to_close.length > 0) {
246+
await vscode.window.tabGroups.close(tabs_to_close)
247+
}
226248

227-
if (accepted_state.is_deleted) {
228-
if (fs.existsSync(sanitized_file_path)) {
229-
const tabs_to_close: vscode.Tab[] = []
230-
for (const tab_group of vscode.window.tabGroups.all) {
231-
tabs_to_close.push(
232-
...tab_group.tabs.filter((tab) => {
233-
const tab_uri = (tab.input as any)?.uri as
234-
| vscode.Uri
235-
| undefined
236-
return tab_uri && tab_uri.fsPath == sanitized_file_path
237-
})
249+
await vscode.workspace.fs.delete(
250+
vscode.Uri.file(sanitized_file_path)
238251
)
239252
}
240-
241-
if (tabs_to_close.length > 0) {
242-
await vscode.window.tabGroups.close(tabs_to_close)
253+
} else {
254+
const dir = path.dirname(sanitized_file_path)
255+
if (!fs.existsSync(dir)) {
256+
await vscode.workspace.fs.createDirectory(
257+
vscode.Uri.file(dir)
258+
)
243259
}
244-
245-
await vscode.workspace.fs.delete(
246-
vscode.Uri.file(sanitized_file_path)
260+
await vscode.workspace.fs.writeFile(
261+
vscode.Uri.file(sanitized_file_path),
262+
Buffer.from(accepted_state.content, 'utf8')
247263
)
248264
}
249-
} else {
250-
const dir = path.dirname(sanitized_file_path)
251-
if (!fs.existsSync(dir)) {
252-
await vscode.workspace.fs.createDirectory(vscode.Uri.file(dir))
253-
}
254-
await vscode.workspace.fs.writeFile(
255-
vscode.Uri.file(sanitized_file_path),
256-
Buffer.from(accepted_state.content, 'utf8')
257-
)
258265
}
266+
} finally {
267+
panel_provider.send_message({ command: 'HIDE_APPLYING_CHANGES' })
259268
}
260269
}
261270
}

‎packages/vscode/src/views/panel/frontend/Panel.tsx‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import { ChatInitializedModal as UiChatInitializedModal } from '@ui/components/e
1313
import { CommitMessageModal as UiCommitMessageModal } from '@ui/components/editor/panel/modals/CommitMessageModal'
1414
import { StageFilesModal as UiStageFilesModal } from '@ui/components/editor/panel/modals/StageFilesModal'
1515
import { use_panel } from './hooks/use-panel'
16+
import { ApplyingChangesModal as UiApplyingChangesModal } from '@ui/components/editor/panel/modals/ApplyingChangesModal'
1617

1718
const vscode = acquireVsCodeApi()
1819

@@ -30,6 +31,7 @@ export const Panel = () => {
3031
raw_instructions,
3132
progress_state,
3233
set_progress_state,
34+
is_applying_changes,
3335
chat_initialized_title,
3436
set_chat_initialized_title,
3537
commit_message_to_review,
@@ -315,6 +317,12 @@ export const Panel = () => {
315317
</div>
316318
)}
317319

320+
{is_applying_changes && (
321+
<div className={styles.slot}>
322+
<UiApplyingChangesModal title="Applying changes..." />
323+
</div>
324+
)}
325+
318326
{progress_state && (
319327
<div className={styles.slot}>
320328
<UiProgressModal

‎packages/vscode/src/views/panel/frontend/hooks/use-panel.ts‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ export const use_panel = (vscode: any) => {
3535
tokens_per_second?: number
3636
files?: FileProgress[]
3737
}>()
38+
const [is_applying_changes, set_is_applying_changes] = useState(false)
3839
const [chat_initialized_title, set_chat_initialized_title] = useState<
3940
string | undefined
4041
>()
@@ -212,6 +213,10 @@ export const use_panel = (vscode: any) => {
212213
})
213214
} else if (message.command == 'HIDE_PROGRESS') {
214215
set_progress_state(undefined)
216+
} else if (message.command == 'SHOW_APPLYING_CHANGES') {
217+
set_is_applying_changes(true)
218+
} else if (message.command == 'HIDE_APPLYING_CHANGES') {
219+
set_is_applying_changes(false)
215220
} else if (message.command == 'SHOW_CHAT_INITIALIZED') {
216221
set_chat_initialized_title(message.title)
217222
} else if (message.command == 'FOCUS_CHAT_INPUT') {
@@ -369,6 +374,7 @@ export const use_panel = (vscode: any) => {
369374
raw_instructions,
370375
progress_state,
371376
set_progress_state,
377+
is_applying_changes,
372378
chat_initialized_title,
373379
set_chat_initialized_title,
374380
commit_message_to_review,

‎packages/vscode/src/views/panel/types/messages.ts‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -543,6 +543,14 @@ export interface HideProgressMessage extends BaseMessage {
543543
command: 'HIDE_PROGRESS'
544544
}
545545

546+
export interface ShowApplyingChangesMessage extends BaseMessage {
547+
command: 'SHOW_APPLYING_CHANGES'
548+
}
549+
550+
export interface HideApplyingChangesMessage extends BaseMessage {
551+
command: 'HIDE_APPLYING_CHANGES'
552+
}
553+
546554
export interface ShowChatInitializedMessage extends BaseMessage {
547555
command: 'SHOW_CHAT_INITIALIZED'
548556
title: string
@@ -607,6 +615,8 @@ export type BackendMessage =
607615
| SelectedConfigurationChangedMessage
608616
| ShowProgressMessage
609617
| HideProgressMessage
618+
| ShowApplyingChangesMessage
619+
| HideApplyingChangesMessage
610620
| ShowChatInitializedMessage
611621
| UpdateFileInReviewMessage
612622
| ShowStageFilesModalMessage

0 commit comments

Comments
 (0)