Show most errors using toast

- does not automatically dismiss
- shows the error to the user
This commit is contained in:
Mattias Granlund 2024-04-11 20:01:58 +02:00
parent 4bb52ac831
commit 150acb0abf
17 changed files with 77 additions and 68 deletions

View File

@ -1,4 +1,5 @@
import { invoke } from '$lib/backend/ipc';
import { showError } from '$lib/notifications/toasts';
import { persisted } from '$lib/persisted/persisted';
import { observableToStore } from '$lib/rxjs/store';
import * as toasts from '$lib/utils/toasts';
@ -115,7 +116,7 @@ export class ProjectService {
// linkProjectModal?.show(project.id);
goto(`/${project.id}/board`);
})
.catch((e: any) => toasts.error(e.message));
.catch((e: any) => showError('There was a problem', e.message));
}
getLastOpenedProject() {

View File

@ -21,12 +21,12 @@
DraggableRemoteCommit
} from '$lib/dragging/draggables';
import { dropzone } from '$lib/dragging/dropzone';
import { showError } from '$lib/notifications/toasts';
import { persisted } from '$lib/persisted/persisted';
import { SETTINGS, type Settings } from '$lib/settings/userSettings';
import { User } from '$lib/stores/user';
import { getContext, getContextStore, getContextStoreBySymbol } from '$lib/utils/context';
import { computeAddedRemovedByFiles } from '$lib/utils/metrics';
import * as toasts from '$lib/utils/toasts';
import { BranchController } from '$lib/vbranches/branchController';
import { FileIdSelection } from '$lib/vbranches/fileIdSelection';
import { filesToOwnership } from '$lib/vbranches/ownership';
@ -84,7 +84,7 @@
}
} catch (e) {
console.error(e);
toasts.error('Failed to generate branch name');
showError('Failed to generate branch name', e);
}
}

View File

@ -7,11 +7,10 @@
import { clickOutside } from '$lib/clickOutside';
import Button from '$lib/components/Button.svelte';
import Icon from '$lib/components/Icon.svelte';
import { showError } from '$lib/notifications/toasts';
import { getContext, getContextStore } from '$lib/utils/context';
import * as toasts from '$lib/utils/toasts';
import { BranchController } from '$lib/vbranches/branchController';
import { Branch } from '$lib/vbranches/types';
import toast from 'svelte-french-toast';
import type { Persisted } from '$lib/persisted/persisted';
import { goto } from '$app/navigation';
@ -157,10 +156,9 @@
try {
await branchController.deleteBranch(branch.id);
goto(`/${project.id}/board`);
} catch (e) {
const err = 'Failed to delete branch';
toasts.error(err);
console.error(err, e);
} catch (err) {
showError('Failed to delete branch', err);
console.error(err);
} finally {
isDeleting = false;
}
@ -179,10 +177,9 @@
try {
await branchController.applyBranch(branch.id);
goto(`/${project.id}/board`);
} catch (e) {
const err = 'Failed to apply branch';
toast.error(err);
console.error(err, e);
} catch (err) {
showError('Failed to apply branch', err);
console.error(err);
} finally {
isApplying = false;
}

View File

@ -14,10 +14,10 @@
projectRunCommitHooks,
persistedCommitMessage
} from '$lib/config/config';
import { showError } from '$lib/notifications/toasts';
import { User } from '$lib/stores/user';
import { splitMessage } from '$lib/utils/commitMessage';
import { getContext, getContextStore } from '$lib/utils/context';
import * as toasts from '$lib/utils/toasts';
import { tooltip } from '$lib/utils/tooltip';
import { setAutoHeight } from '$lib/utils/useAutoHeight';
import { useResize } from '$lib/utils/useResize';
@ -113,10 +113,10 @@
if (generatedMessage) {
$commitMessage = generatedMessage;
} else {
toasts.error('Failed to generate commit message');
throw new Error('Prompt generated no response');
}
} catch {
toasts.error('Failed to generate commit message');
} catch (e: any) {
showError('Failed to generate commit message', e);
} finally {
aiLoading = false;
}

View File

@ -9,9 +9,9 @@
import Button from '$lib/components/Button.svelte';
import Link from '$lib/components/Link.svelte';
import Section from '$lib/components/settings/Section.svelte';
import { showError } from '$lib/notifications/toasts';
import { copyToClipboard } from '$lib/utils/clipboard';
import { getContext, getContextStore } from '$lib/utils/context';
import * as toasts from '$lib/utils/toasts';
import { openExternalUrl } from '$lib/utils/url';
import { BaseBranch } from '$lib/vbranches/types';
import { onMount } from 'svelte';
@ -51,7 +51,7 @@
try {
projectService.updateProject({ ...project, ...detail });
} catch (err: any) {
toasts.error(err.message);
showError('Failed to update key', err);
}
}

View File

@ -1,8 +1,8 @@
<script lang="ts">
import Button from './Button.svelte';
import { showError } from '$lib/notifications/toasts';
import { UserService, type LoginToken } from '$lib/stores/user';
import { getContext } from '$lib/utils/context';
import * as toasts from '$lib/utils/toasts';
import { openExternalUrl } from '$lib/utils/url';
const userService = getContext(UserService);
@ -54,7 +54,7 @@
await userService.login(token);
} catch (err) {
console.error(err);
toasts.error('Could not create login token');
showError('Could not create login token', err);
} finally {
signUpOrLoginLoading = false;
}

View File

@ -7,6 +7,7 @@
import RemoveProjectButton from './RemoveProjectButton.svelte';
import derectionDoubtSvg from '$lib/assets/illustrations/direction-doubt.svg?raw';
import { ProjectService, Project } from '$lib/backend/projects';
import { showError } from '$lib/notifications/toasts';
import { getContext } from '$lib/utils/context';
import * as toasts from '$lib/utils/toasts';
import { BranchController } from '$lib/vbranches/branchController';
@ -30,9 +31,9 @@
await projectService.deleteProject(project.id);
toasts.success('Project deleted');
goto('/', { invalidateAll: true });
} catch (e) {
console.error(e);
toasts.error('Failed to delete project');
} catch (err: any) {
console.error(err);
showError('Failed to delete project', err);
} finally {
isDeleting = false;
projectService.reload();

View File

@ -2,8 +2,8 @@
import Button from './Button.svelte';
import TextBox from './TextBox.svelte';
import { PromptService, type SystemPrompt } from '$lib/backend/prompt';
import { showError } from '$lib/notifications/toasts';
import { getContext } from '$lib/utils/context';
import * as toasts from '$lib/utils/toasts';
export let prompt: SystemPrompt | undefined;
export let error: any;
@ -21,7 +21,7 @@
isSubmitting = false;
}
if (error) toasts.error(error);
if (error) showError('Something went wrong', error);
</script>
{#if prompt}

View File

@ -5,6 +5,7 @@
import loadErrorSvg from '$lib/assets/illustrations/load-error.svg?raw';
import { ProjectService, Project } from '$lib/backend/projects';
import Icon from '$lib/components/Icon.svelte';
import { showError } from '$lib/notifications/toasts';
import { getContext } from '$lib/utils/context';
import * as toasts from '$lib/utils/toasts';
import { goto } from '$app/navigation';
@ -24,9 +25,9 @@
await projectService.deleteProject(project.id);
toasts.success('Project deleted');
goto('/');
} catch (e) {
console.error(e);
toasts.error('Failed to delete project');
} catch (err: any) {
console.error(err);
showError('Failed to delete project', err);
} finally {
loading = false;
projectService.reload();

View File

@ -1,7 +1,7 @@
<script lang="ts">
import Tag from './Tag.svelte';
import { showError } from '$lib/notifications/toasts';
import { getContext } from '$lib/utils/context';
import * as toasts from '$lib/utils/toasts';
import { BranchController } from '$lib/vbranches/branchController';
const branchController = getContext(BranchController);
@ -18,8 +18,8 @@
loading = true;
try {
await branchController.updateBaseBranch();
} catch {
toasts.error('Failed update workspace');
} catch (err) {
showError('Failed update workspace', err);
} finally {
loading = false;
}

View File

@ -8,7 +8,7 @@ import {
parseGitHubCheckSuites,
type CheckSuites
} from '$lib/github/types';
import { showToast, type Toast } from '$lib/notifications/toasts';
import { showError, showToast, type Toast } from '$lib/notifications/toasts';
import { sleep } from '$lib/utils/sleep';
import * as toasts from '$lib/utils/toasts';
import { Octokit } from '@octokit/rest';
@ -97,7 +97,7 @@ export class GitHubService {
shareReplay(1),
catchError((err) => {
console.error(err);
toasts.error('Failed to load pull requests');
showError('Failed to load pull requests', err);
this.error$.next(err);
return of([]);
}),

View File

@ -21,6 +21,13 @@ export function showToast(toast: Toast) {
]);
}
export function showError(title: string, err: any) {
let message: string;
if (err.message) message = err.message;
message = `\`\`\`${err}\`\`\``; // markdown code block
showToast({ title, message, style: 'error' });
}
export function dismissToast(messageId: string | undefined) {
if (!messageId) return;
toastStore.update((items) => items.filter((m) => m.id != messageId));

View File

@ -1,6 +1,6 @@
import { invoke } from '$lib/backend/ipc';
import { showError } from '$lib/notifications/toasts';
import { observableToStore } from '$lib/rxjs/store';
import * as toasts from '$lib/utils/toasts';
import { RemoteBranch, RemoteBranchData } from '$lib/vbranches/types';
import { plainToInstance } from 'class-transformer';
import {
@ -32,7 +32,7 @@ export class RemoteBranchService {
shareReplay(1),
catchError((e) => {
console.error(e);
toasts.error(`Failed load remote branches`);
showError('Failed load remote branches', e);
throw e;
})
);

View File

@ -1,7 +1,7 @@
import { BaseBranch } from './types';
import { Code, invoke } from '$lib/backend/ipc';
import { showError } from '$lib/notifications/toasts';
import { observableToStore } from '$lib/rxjs/store';
import * as toasts from '$lib/utils/toasts';
import { plainToInstance } from 'class-transformer';
import {
switchMap,
@ -77,9 +77,9 @@ export class BaseBranchService {
// Swallow this error since user should be taken to project setup page
return;
} else if (err.code === Code.ProjectsGitAuth) {
toasts.error('Failed to authenticate. Did you setup GitButler ssh keys?');
showError('Failed to authenticate', err);
} else {
toasts.error(`${err.message}`);
showError('Failed to fetch', err);
}
console.error(err);
} finally {

View File

@ -1,5 +1,5 @@
import { invoke } from '$lib/backend/ipc';
import { showToast } from '$lib/notifications/toasts';
import { showError, showToast } from '$lib/notifications/toasts';
import * as toasts from '$lib/utils/toasts';
import posthog from 'posthog-js';
import type { RemoteBranchService } from '$lib/stores/remoteBranches';
@ -19,8 +19,8 @@ export class BranchController {
try {
await this.targetBranchService.setTarget(branch);
// TODO: Reloading seems to trigger 4 invocations of `list_virtual_branches`
} catch (err) {
toasts.error('Failed to set base branch');
} catch (err: any) {
showError('Failed to set base branch', err);
} finally {
this.targetBranchService.reload();
this.vbranchService.reload();
@ -35,7 +35,7 @@ export class BranchController {
targetCommitOid
});
} catch (err) {
toasts.error('Failed to reset branch');
showError('Failed to reset branch', err);
}
}
@ -43,7 +43,7 @@ export class BranchController {
try {
await invoke<void>('create_virtual_branch', { projectId: this.projectId, branch });
} catch (err) {
toasts.error('Failed to create branch');
showError('Failed to create branch', err);
}
}
@ -63,7 +63,7 @@ export class BranchController {
});
posthog.capture('Commit Successful');
} catch (err: any) {
toasts.error('Failed to commit changes');
showError('Failed to commit changes', err);
posthog.capture('Commit Failed', err);
throw err;
}
@ -76,7 +76,7 @@ export class BranchController {
branch
});
} catch (err) {
toasts.error('Failed to merge upstream branch');
showError('Failed to merge upstream branch', err);
}
}
@ -87,7 +87,7 @@ export class BranchController {
branch: { id: branchId, name }
});
} catch (err) {
toasts.error('Failed to update branch name');
showError('Failed to update branch name', err);
}
}
@ -98,7 +98,7 @@ export class BranchController {
branch: { id: branchId, upstream }
});
} catch (err) {
toasts.error('Failed to update branch remote name');
showError('Failed to update remote name', err);
}
}
@ -109,7 +109,7 @@ export class BranchController {
branch: { id: branchId, notes }
});
} catch (err) {
toasts.error('Failed to update branch notes');
showError('Failed to update branch notes', err);
}
}
@ -120,7 +120,7 @@ export class BranchController {
branch: { id: branchId, selected_for_changes: true }
});
} catch (err) {
toasts.error('Failed to set as target');
showError('Failed make default target', err);
}
}
@ -131,7 +131,7 @@ export class BranchController {
branch: { id: branchId, order }
});
} catch (err) {
toasts.error('Failed to update branch order');
showError('Failed to update branch order', err);
}
}
@ -140,7 +140,7 @@ export class BranchController {
// TODO: make this optimistic again.
await invoke<void>('apply_branch', { projectId: this.projectId, branch: branchId });
} catch (err) {
toasts.error('Failed to apply branch');
showError('Failed to apply branch', err);
}
}
@ -149,7 +149,7 @@ export class BranchController {
try {
await invoke<void>('unapply_ownership', { projectId: this.projectId, ownership });
} catch (err) {
toasts.error('Failed to unapply hunk');
showError('Failed to unapply hunk', err);
}
}
@ -160,7 +160,7 @@ export class BranchController {
files: files.flatMap((f) => f.path).join('\n')
});
} catch (err) {
toasts.error('Failed to unapply file changes');
showError('Failed to unapply file changes', err);
}
}
@ -169,7 +169,7 @@ export class BranchController {
// TODO: make this optimistic again.
await invoke<void>('unapply_branch', { projectId: this.projectId, branch: branchId });
} catch (err) {
toasts.error('Failed to unapply branch');
showError('Failed to unapply branch', err);
}
}
@ -180,7 +180,7 @@ export class BranchController {
branch: { id: branchId, ownership }
});
} catch (err) {
toasts.error('Failed to update branch ownership');
showError('Failed to update hunk ownership', err);
}
}
@ -233,7 +233,7 @@ export class BranchController {
await invoke<void>('delete_virtual_branch', { projectId: this.projectId, branchId });
toasts.success('Branch deleted successfully');
} catch (err) {
toasts.error('Failed to delete branch');
showError('Failed to delete branch', err);
} finally {
this.remoteBranchService.reload();
}
@ -254,7 +254,7 @@ export class BranchController {
branch
});
} catch (err) {
toasts.error('Failed to create virtual branch from branch');
showError('Failed to create virtual branch', err);
} finally {
this.remoteBranchService.reload();
this.targetBranchService.reload();
@ -269,7 +269,7 @@ export class BranchController {
targetCommitOid
});
} catch (err: any) {
toasts.error(`Failed to cherry-pick commit: ${err.message}`);
showError('Failed to cherry-pick commit', err);
} finally {
this.targetBranchService.reload();
}
@ -279,7 +279,7 @@ export class BranchController {
try {
await invoke<void>('mark_resolved', { projectId: this.projectId, path });
} catch (err) {
toasts.error(`Failed to mark file resolved`);
showError('Failed to mark file resolved', err);
}
}
@ -291,7 +291,7 @@ export class BranchController {
targetCommitOid
});
} catch (err: any) {
toasts.error(`Failed to squash commit: ${err.message}`);
showError('Failed to squash commit', err);
}
}
@ -303,7 +303,7 @@ export class BranchController {
ownership
});
} catch (err: any) {
toasts.error(`Failed to amend commit: ${err.message}`);
showError('Failed to amend commit', err);
}
}
@ -315,7 +315,7 @@ export class BranchController {
commitOid
});
} catch (err: any) {
toasts.error(`Failed to move commit: ${err.message}`);
showError('Failed to move commit', err);
}
}
}

View File

@ -8,6 +8,7 @@
import SectionCard from '$lib/components/SectionCard.svelte';
import Spacer from '$lib/components/Spacer.svelte';
import ContentWrapper from '$lib/components/settings/ContentWrapper.svelte';
import { showError } from '$lib/notifications/toasts';
import { UserService } from '$lib/stores/user';
import { getContext } from '$lib/utils/context';
import * as toasts from '$lib/utils/toasts';
@ -39,7 +40,7 @@
toasts.success('Project deleted');
} catch (err: any) {
console.error(err);
toasts.error('Failed to delete project');
showError('Failed to delete project', err);
} finally {
isDeleting = false;
}

View File

@ -10,6 +10,7 @@
import Toggle from '$lib/components/Toggle.svelte';
import WelcomeSigninAction from '$lib/components/WelcomeSigninAction.svelte';
import ContentWrapper from '$lib/components/settings/ContentWrapper.svelte';
import { showError } from '$lib/notifications/toasts';
import { SETTINGS, type Settings } from '$lib/settings/userSettings';
import { UserService } from '$lib/stores/user';
import { getContext, getContextStoreBySymbol } from '$lib/utils/context';
@ -58,9 +59,9 @@
updatedUser.github_access_token = $user?.github_access_token; // prevent overwriting with null
userService.setUser(updatedUser);
toasts.success('Profile updated');
} catch (e) {
console.error(e);
toasts.error('Failed to update user');
} catch (err: any) {
console.error(err);
showError('Failed to update user', err);
}
saving = false;
}
@ -87,7 +88,7 @@
goto('/', { replaceState: true, invalidateAll: true });
} catch (err: any) {
console.error(err);
toasts.error('Failed to delete project');
showError('Failed to delete project', err);
} finally {
deleteConfirmationModal.close();
isDeleting = false;