Skip to content

Commit a8c9849

Browse files
committed
Add loading states to split-branches right-click actions
Enhance the file context menu experience for split-off branches feature: - Add loading, success, and error states to right-click actions related to branch splitting, auto-commit, and absorbing changes. - Replace legacy toasts with loading states via toasts.promise for async file actions. - Refactor UI feedback for branch/split/absorb to improve clarity during async automation. - Update onclick handlers to remove async/await in favor of internal promise handling and reactive isLoading controls. All improvements target a more responsive and informative workflow for file-level automations related to branch manipulation.
1 parent f434341 commit a8c9849

File tree

1 file changed

+86
-75
lines changed

1 file changed

+86
-75
lines changed

apps/desktop/src/components/v3/FileContextMenu.svelte

Lines changed: 86 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
import { changesToDiffSpec } from '$lib/commits/utils';
77
import { projectAiExperimentalFeaturesEnabled, projectAiGenEnabled } from '$lib/config/config';
88
import { isTreeChange, type TreeChange } from '$lib/hunks/change';
9-
import { showToast } from '$lib/notifications/toasts';
109
import { vscodePath } from '$lib/project/project';
1110
import { ProjectsService } from '$lib/project/projectsService';
1211
import { IdSelection } from '$lib/selection/idSelection.svelte';
@@ -168,19 +167,19 @@
168167
return;
169168
}
170169
171-
showToast({
172-
style: 'neutral',
173-
title: 'Figuring out where to commit the changes',
174-
message: 'This may take a few seconds.'
175-
});
176-
177-
await autoCommit({ projectId, changes });
178-
179-
showToast({
180-
style: 'success',
181-
title: 'And... done!',
182-
message: `Now, you're free to continue`
183-
});
170+
await toasts.promise(
171+
(async () => {
172+
await autoCommit({
173+
projectId,
174+
changes
175+
});
176+
})(),
177+
{
178+
loading: 'Started auto commit',
179+
success: 'Auto commit succeded',
180+
error: (error: Error) => `Auto commit failed: ${error.message}`
181+
}
182+
);
184183
}
185184
186185
async function triggerBranchChanges(changes: TreeChange[]) {
@@ -189,19 +188,16 @@
189188
return;
190189
}
191190
192-
showToast({
193-
style: 'neutral',
194-
title: 'Creating a branch and committing the changes',
195-
message: 'This may take a few seconds.'
196-
});
197-
198-
await branchChanges({ projectId, changes });
199-
200-
showToast({
201-
style: 'success',
202-
title: 'And... done!',
203-
message: `Now, you're free to continue`
204-
});
191+
await toasts.promise(
192+
(async () => {
193+
await branchChanges({ projectId, changes });
194+
})(),
195+
{
196+
loading: 'Creating a branch and committing changes',
197+
success: 'Branching changes succeded',
198+
error: (error: Error) => `Branching changes failed: ${error.message}`
199+
}
200+
);
205201
}
206202
207203
async function triggerAbsorbChanges(changes: TreeChange[]) {
@@ -210,19 +206,16 @@
210206
return;
211207
}
212208
213-
showToast({
214-
style: 'neutral',
215-
title: 'Looking for the best place to absorb the changes',
216-
message: 'This may take a few seconds.'
217-
});
218-
219-
await absorbChanges({ projectId, changes });
220-
221-
showToast({
222-
style: 'success',
223-
title: 'And... done!',
224-
message: `Now, you're free to continue`
225-
});
209+
await toasts.promise(
210+
(async () => {
211+
await absorbChanges({ projectId, changes });
212+
})(),
213+
{
214+
loading: 'Looking for the best place to absorb the changes',
215+
success: 'Absorbing changes succeded',
216+
error: (error: Error) => `Absorbing changes failed: ${error.message}`
217+
}
218+
);
226219
}
227220
228221
async function split(changes: TreeChange[]) {
@@ -239,20 +232,29 @@
239232
const branchName = selectionId.branchName;
240233
241234
const fileNames = changes.map((change) => change.path);
242-
const newBranchName = await stackService.fetchNewBranchName(projectId);
243235
244-
if (!newBranchName) {
245-
toasts.error('Failed to generate a new branch name.');
246-
return;
247-
}
248-
249-
await splitOffChanges({
250-
projectId,
251-
sourceStackId: stackId,
252-
sourceBranchName: branchName,
253-
fileChangesToSplitOff: fileNames,
254-
newBranchName: newBranchName
255-
});
236+
await toasts.promise(
237+
(async () => {
238+
const newBranchName = await stackService.fetchNewBranchName(projectId);
239+
240+
if (!newBranchName) {
241+
throw new Error('Failed to generate a new branch name.');
242+
}
243+
244+
await splitOffChanges({
245+
projectId,
246+
sourceStackId: stackId,
247+
sourceBranchName: branchName,
248+
fileChangesToSplitOff: fileNames,
249+
newBranchName: newBranchName
250+
});
251+
})(),
252+
{
253+
loading: 'Splitting off changes',
254+
success: 'Changes split off into a new branch',
255+
error: (error: Error) => `Failed to split off changes: ${error.message}`
256+
}
257+
);
256258
}
257259
258260
async function splitIntoDependentBranch(changes: TreeChange[]) {
@@ -269,20 +271,29 @@
269271
const branchName = selectionId.branchName;
270272
271273
const fileNames = changes.map((change) => change.path);
272-
const newBranchName = await stackService.fetchNewBranchName(projectId);
273274
274-
if (!newBranchName) {
275-
toasts.error('Failed to generate a new branch name.');
276-
return;
277-
}
278-
279-
await splitBranchIntoDependentBranch({
280-
projectId,
281-
sourceStackId: stackId,
282-
sourceBranchName: branchName,
283-
fileChangesToSplitOff: fileNames,
284-
newBranchName: newBranchName
285-
});
275+
await toasts.promise(
276+
(async () => {
277+
const newBranchName = await stackService.fetchNewBranchName(projectId);
278+
279+
if (!newBranchName) {
280+
throw new Error('Failed to generate a new branch name.');
281+
}
282+
283+
await splitBranchIntoDependentBranch({
284+
projectId,
285+
sourceStackId: stackId,
286+
sourceBranchName: branchName,
287+
fileChangesToSplitOff: fileNames,
288+
newBranchName: newBranchName
289+
});
290+
})(),
291+
{
292+
loading: 'Splitting into dependent branch',
293+
success: 'Changes split into a dependent branch',
294+
error: (error: Error) => `Failed to split into dependent branch: ${error.message}`
295+
}
296+
);
286297
}
287298
</script>
288299

@@ -372,15 +383,15 @@
372383
{#if isBranchFiles && isAdmin}
373384
<ContextMenuItem
374385
label="Split off changes"
375-
onclick={async () => {
376-
await split(changes);
386+
onclick={() => {
387+
split(changes);
377388
contextMenu.close();
378389
}}
379390
/>
380391
<ContextMenuItem
381392
label="Split into dependent branch"
382-
onclick={async () => {
383-
await splitIntoDependentBranch(changes);
393+
onclick={() => {
394+
splitIntoDependentBranch(changes);
384395
contextMenu.close();
385396
}}
386397
/>
@@ -394,25 +405,25 @@
394405
tooltip="Try to figure out where to commit the changes. Can create new branches too."
395406
onclick={async () => {
396407
contextMenu.close();
397-
await triggerAutoCommit(item.changes);
408+
triggerAutoCommit(item.changes);
398409
}}
399410
disabled={autoCommitting.current.isLoading}
400411
/>
401412
<ContextMenuItem
402413
label="Branch changes 🧪"
403414
tooltip="Create a new branch and commit the changes into it."
404-
onclick={async () => {
415+
onclick={() => {
405416
contextMenu.close();
406-
await triggerBranchChanges(item.changes);
417+
triggerBranchChanges(item.changes);
407418
}}
408419
disabled={branchingChanges.current.isLoading}
409420
/>
410421
<ContextMenuItem
411422
label="Absorb changes 🧪"
412423
tooltip="Try to find the best place to absorb the changes into."
413-
onclick={async () => {
424+
onclick={() => {
414425
contextMenu.close();
415-
await triggerAbsorbChanges(item.changes);
426+
triggerAbsorbChanges(item.changes);
416427
}}
417428
disabled={absorbingChanges.current.isLoading}
418429
/>

0 commit comments

Comments
 (0)