Skip to content

Commit

Permalink
Feat/error handling (#496)
Browse files Browse the repository at this point in the history
* throw app errors

* show dialog on native fs error

* fix

* lock

* handle worker errors
  • Loading branch information
kepta committed Dec 9, 2023
1 parent d6963c7 commit 523ed4e
Show file tree
Hide file tree
Showing 33 changed files with 477 additions and 127 deletions.
46 changes: 27 additions & 19 deletions packages/app-window/app/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import { StoreProvider, useStore, useTrack } from '@nalanda/react';
import React, { useEffect } from 'react';

import { Activitybar } from '@bangle.io/activitybar';
import { appErrorHandler } from '@bangle.io/app-error-handler';
import { Router } from '@bangle.io/app-routing';
import { BaseError } from '@bangle.io/base-error';
import { COLOR_SCHEME } from '@bangle.io/constants';
import { DialogArea } from '@bangle.io/dialogs';
import { LeftAside } from '@bangle.io/left-aside';
Expand All @@ -19,6 +19,7 @@ import { DhanchaSmallscreen, DhanchaWidescreen } from '@bangle.io/ui';
import { createWindowStore } from '@bangle.io/window-store';

import { ToastArea } from './components/ToastArea';
import { logger } from './logger';

let store: ReturnType<typeof createWindowStore>;

Expand Down Expand Up @@ -58,26 +59,33 @@ function Main() {
const store = useStore();

useEffect(() => {
const handleRejection = (error: PromiseRejectionEvent | ErrorEvent) => {
let label = 'Encountered an error';

if ('reason' in error) {
if (error.reason instanceof BaseError) {
label = error.reason.message;
} else if (error.reason instanceof Error) {
label = error.reason.message;
const handleRejection = (event: PromiseRejectionEvent | ErrorEvent) => {
const handle = (error: unknown) => {
return appErrorHandler(
error,
(dialog) => {
store.dispatch(
sliceUI.actions.showDialog(dialog.name, dialog.payload),
);
},
(toast) => {
queueToast(store, toast);
},
);
};

if ('reason' in event) {
let error = event.reason;
if (handle(error)) {
logger.debug('Handled rejection', error);
event.preventDefault();
}
} else {
label = error.error.message;
}

try {
queueToast(store, {
label,
type: 'negative',
});
} catch (error) {
console.error(error);
let error = event.error;
if (handle(error)) {
logger.debug('Handled error', error);
event.preventDefault();
}
}
};

Expand Down
4 changes: 2 additions & 2 deletions packages/app-window/app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@
"@react-spectrum/toast": "^3.0.0-beta.7",
"@bangle.io/logger": "workspace:*",
"@bangle.io/app-routing": "workspace:*",
"@bangle.io/base-error": "workspace:*",
"@bangle.io/dialogs": "workspace:*"
"@bangle.io/dialogs": "workspace:*",
"@bangle.io/app-error-handler": "workspace:*"
},
"devDependencies": {
"@testing-library/react": "^14.1.2",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
useDialogContainer,
} from '@adobe/react-spectrum';
import { useStore } from '@nalanda/react';
import React from 'react';
import React, { useEffect } from 'react';

import { APP_ERROR_NAME, throwAppError } from '@bangle.io/app-errors';
import { requestNativeBrowserFSPermission } from '@bangle.io/baby-fs';
Expand All @@ -28,6 +28,7 @@ export function WorkspaceAuthNativeFSDialog({ payload, name }: DialogProps) {
// eslint-disable-next-line @typescript-eslint/unbound-method
const { dismiss } = useDialogContainer();
const store = useStore();

const { eternalVars } = getWindowStoreConfig(store);
const { workspaceName } = payload;
const getPermission = async () => {
Expand Down Expand Up @@ -61,15 +62,24 @@ export function WorkspaceAuthNativeFSDialog({ payload, name }: DialogProps) {
);

if (granted) {
dismiss();
store.dispatch(
slicePage.actions.goTo((location) =>
locationHelpers.goToWorkspaceHome(location, wsInfo.name),
),
);
dismiss();
}
};

useEffect(() => {
// this exists so we can rerender workspace home page after grant
store.dispatch(
slicePage.actions.goTo((location) =>
locationHelpers.goToWorkspaceSelection(location),
),
);
}, [store]);

return (
<Dialog>
<Heading>Grant permission?</Heading>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import { locationHelpers } from '@bangle.io/ws-path';

export function PageWorkspaceNativeFsAuth() {
const store = useStore();
const { wsName } = useTrack(slicePage);

return (
<IllustratedMessage>
Expand All @@ -23,7 +22,6 @@ export function PageWorkspaceNativeFsAuth() {
<Content>
<Flex direction="column" gap="size-100">
Bangle.io needs access to {'"'}
{wsName}
<Flex direction="row" gap="size-100">
<Button
style="fill"
Expand Down
13 changes: 13 additions & 0 deletions packages/app-window/window-store/sync-with-worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,19 @@ key.effect((store) => {
}
queueToast(store, options.toastRequest);
},

queueDialog: async (options) => {
if (destroyed) {
return;
}
store.dispatch(
sliceUI.actions.showDialog(
options.dialogRequest.name,
options.dialogRequest.payload,
),
);
},

pageBlockPageReload: async ({ block }) => {
if (destroyed) {
return;
Expand Down
60 changes: 39 additions & 21 deletions packages/app-worker/naukar/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { applyPatches, enablePatches, produce } from 'immer';

import { appErrorHandler } from '@bangle.io/app-error-handler';
import { BaseError } from '@bangle.io/base-error';
import { Emitter } from '@bangle.io/emitter';
import { getWindowActionsRef } from '@bangle.io/naukar-common';
Expand All @@ -13,7 +14,6 @@ import type {
NaukarBare,
WindowActions,
} from '@bangle.io/shared-types';

enablePatches();

import { logger } from './logger';
Expand Down Expand Up @@ -72,30 +72,48 @@ export class Naukar implements NaukarBare {

getWindowActionsRef(this.store).current = this.windowActionProxy.proxy;

const handleRejection = (error: PromiseRejectionEvent | ErrorEvent) => {
let label = 'Worker error';
const handleRejection = (event: PromiseRejectionEvent | ErrorEvent) => {
const handle = (error: unknown) => {
return appErrorHandler(
error,
(dialog) => {
void getWindowActionsRef(this.store)
.current?.queueDialog({
dialogRequest: dialog,
})
.catch((error) => {
// we swallow this error as we don't want to throw from here
// as it can cause infinite loop
logger.error('queueToast error', error);
});
},
(toast) => {
void getWindowActionsRef(this.store)
.current?.queueToast({
toastRequest: toast,
})
.catch((error) => {
// we swallow this error as we don't want to throw from here
// as it can cause infinite loop
logger.error('queueToast error', error);
});
},
);
};

if ('reason' in error) {
if (error.reason instanceof BaseError) {
label = error.reason.message;
} else if (error.reason instanceof Error) {
label = error.reason.message;
if ('reason' in event) {
let error = event.reason;
if (handle(error)) {
logger.debug('Handled rejection', error);
event.preventDefault();
}
} else {
label = error.error.message;
let error = event.error;
if (handle(error)) {
logger.debug('Handled error', error);
event.preventDefault();
}
}
getWindowActionsRef(this.store)
.current?.queueToast({
toastRequest: {
label,
type: 'negative',
},
})
.catch((error) => {
// we swallow this error as we don't want to throw from here
// as it can cause infinite loop
logger.error('queueToast error', error);
});
};

globalThis.addEventListener?.('unhandledrejection', handleRejection);
Expand Down
3 changes: 2 additions & 1 deletion packages/app-worker/naukar/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@
"@bangle.io/nsm-3": "workspace:*",
"@bangle.io/naukar-common": "workspace:*",
"@bangle.io/emitter": "workspace:*",
"@bangle.io/base-error": "workspace:*"
"@bangle.io/base-error": "workspace:*",
"@bangle.io/app-error-handler": "workspace:*"
},
"devDependencies": {
"@bangle.io/constants": "workspace:*"
Expand Down
19 changes: 11 additions & 8 deletions packages/lib/app-database-indexeddb/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { AppDatabaseErrorCode } from '@bangle.io/app-database';
import { BaseError } from '@bangle.io/base-error';
import { APP_ERROR_NAME, throwAppError } from '@bangle.io/app-errors';
import { makeDbRecord } from '@bangle.io/db-key-val';
import type {
BaseAppDatabase,
Expand All @@ -19,12 +18,16 @@ export class AppDatabaseIndexedDB implements BaseAppDatabase {
name = 'AppDatabaseIndexedDB';

private throwUnknownError(error: any): never {
logger.error(error);
throw new BaseError({
message: `Error writing to Indexeddb`,
code: AppDatabaseErrorCode.UNKNOWN_ERROR,
cause: this.name,
});
if (error instanceof Error) {
throwAppError(
APP_ERROR_NAME.appDatabaseIndexedDB,
`Error writing to IndexedDB`,
{
error,
},
);
}
throw error;
}

async getAllEntries({ tableName }: DatabaseQueryOptions): Promise<unknown[]> {
Expand Down
3 changes: 1 addition & 2 deletions packages/lib/app-database-indexeddb/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@
"@bangle.io/shared-types": "workspace:*",
"@bangle.io/db-key-val": "workspace:*",
"@bangle.io/logger": "workspace:*",
"@bangle.io/app-database": "workspace:*",
"@bangle.io/base-error": "workspace:*"
"@bangle.io/app-errors": "workspace:*"
}
}
4 changes: 2 additions & 2 deletions packages/lib/app-database/__tests__/app-database.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ describe('workspace creation', () => {
// Attempt to create the same workspace again
await expect(
appDatabase.createWorkspaceInfo(workspaceInfo),
).rejects.toThrow('Workspace with name Existing Workspace already exists');
).rejects.toThrow('Cannot create workspace as it already exists');

expect(mockDatabase.updateEntry).toHaveBeenCalledTimes(2);
expect(mockDatabase.updateEntry).toHaveBeenNthCalledWith(
Expand Down Expand Up @@ -292,7 +292,7 @@ describe('workspace metadata', () => {

await expect(
appDatabase.updateWorkspaceInfo(workspaceName, metadataUpdateFunction),
).rejects.toThrow('Workspace with name Test Workspace does not exist');
).rejects.toThrow('Cannot update workspace as it does not exist');

expect(workspaceTable.size).toBe(0);
});
Expand Down
Loading

0 comments on commit 523ed4e

Please sign in to comment.