From b8442532e8f649b7e1fd8d0285a14b1f2ad5fa89 Mon Sep 17 00:00:00 2001 From: Tom Hacohen Date: Sat, 8 Aug 2020 11:47:51 +0300 Subject: [PATCH] Improve error handling: failing to parse items/collections + syncmanager --- src/Calendars/Main.tsx | 2 -- src/Collections/CollectionChangeEntries.tsx | 1 - src/Collections/CollectionMembers.tsx | 16 +++++++++--- src/Contacts/Main.tsx | 18 ++++++------- src/Pim/helpers.tsx | 28 +++++++++++++-------- src/Tasks/Main.tsx | 18 ++++++------- src/store/actions.ts | 2 +- src/sync/SyncManager.ts | 4 +-- 8 files changed, 52 insertions(+), 37 deletions(-) diff --git a/src/Calendars/Main.tsx b/src/Calendars/Main.tsx index a49f982..c902a59 100644 --- a/src/Calendars/Main.tsx +++ b/src/Calendars/Main.tsx @@ -46,10 +46,8 @@ export default function CalendarsMain() { } (async () => { const colEntries = await decryptCollections(collections); - // FIXME: handle failure to decrypt collections const entries = await decryptItems(items); - // FIXME: handle failure to decrypt items for (const collection of colEntries) { const items = entries.get(collection.collection.uid)!; diff --git a/src/Collections/CollectionChangeEntries.tsx b/src/Collections/CollectionChangeEntries.tsx index 10dd51f..39c636a 100644 --- a/src/Collections/CollectionChangeEntries.tsx +++ b/src/Collections/CollectionChangeEntries.tsx @@ -66,7 +66,6 @@ export default function CollectionChangeEntries(props: PropsType) { if (items) { decryptItems(items) .then((entries) => setEntries(entries.get(collection.uid))); - // FIXME: handle failure to decrypt items } }, [items]); diff --git a/src/Collections/CollectionMembers.tsx b/src/Collections/CollectionMembers.tsx index 3e46207..735c43f 100644 --- a/src/Collections/CollectionMembers.tsx +++ b/src/Collections/CollectionMembers.tsx @@ -20,6 +20,7 @@ import { getCollectionManager } from "../etebase-helpers"; import { CachedCollection } from "../Pim/helpers"; import CollectionMemberAddDialog from "./CollectionMemberAddDialog"; +import Alert from "@material-ui/lab/Alert"; interface PropsType { collection: CachedCollection; @@ -30,15 +31,19 @@ export default function CollectionMembers(props: PropsType) { const [members_, setMembers] = React.useState(); const [revokeUser, setRevokeUser] = React.useState(null); const [addMemberOpen, setAddMemberOpen] = React.useState(false); - // FIXME: add error handling + const [error, setError] = React.useState(); const { collection, metadata } = props.collection; async function fetchMembers() { const colMgr = getCollectionManager(etebase); const memberManager = colMgr.getMemberManager(collection); - const members = await memberManager.list(); - setMembers(members.data); + try { + const members = await memberManager.list(); + setMembers(members.data); + } catch (e) { + setError(e); + } } React.useEffect(() => { @@ -70,6 +75,11 @@ export default function CollectionMembers(props: PropsType) { <> + {error && ( + + {error.toString()} + + )} {members ? } onClick={() => setAddMemberOpen(true)}> diff --git a/src/Contacts/Main.tsx b/src/Contacts/Main.tsx index 7b64aae..689ceca 100644 --- a/src/Contacts/Main.tsx +++ b/src/Contacts/Main.tsx @@ -37,16 +37,16 @@ export default function ContactsMain() { const items = useItems(etebase, colType); React.useEffect(() => { - if (items) { - decryptItems(items) - .then((entries) => setEntries(entries)); - // FIXME: handle failure to decrypt items - } - if (collections) { - decryptCollections(collections) - .then((entries) => setCachedCollections(entries)); - // FIXME: handle failure to decrypt collections + if (!collections || !items) { + return; } + (async () => { + const colEntries = await decryptCollections(collections); + const entries = await decryptItems(items); + + setCachedCollections(colEntries); + setEntries(entries); + })(); }, [items, collections]); if (!entries || !cachedCollections) { diff --git a/src/Pim/helpers.tsx b/src/Pim/helpers.tsx index d4a0f0f..6d41628 100644 --- a/src/Pim/helpers.tsx +++ b/src/Pim/helpers.tsx @@ -11,8 +11,8 @@ import * as Etebase from "etebase"; import { PimType } from "../pim-types"; import { getCollectionManager } from "../etebase-helpers"; -import { asyncDispatch } from "../store"; -import { itemBatch } from "../store/actions"; +import { asyncDispatch, store } from "../store"; +import { itemBatch, appendError } from "../store/actions"; export const defaultColor = "#8BC34A"; @@ -32,10 +32,14 @@ export function getDecryptCollectionsFunction(_colType?: string) { const entries: CachedCollection[] = []; if (collections) { for (const collection of collections) { - entries.push({ - collection, - metadata: await collection.getMeta(), - }); + try { + entries.push({ + collection, + metadata: await collection.getMeta(), + }); + } catch (e) { + store.dispatch(appendError(e)); + } } } @@ -54,10 +58,14 @@ export function getDecryptItemsFunction(_colType: string, par const cur = new Map(); entries.set(colUid, cur); for (const item of col.values()) { - const contact = parseFunc(await item.getContent(Etebase.OutputFormat.String)); - contact.collectionUid = colUid; - contact.itemUid = item.uid; - cur.set(item.uid, contact); + try { + const contact = parseFunc(await item.getContent(Etebase.OutputFormat.String)); + contact.collectionUid = colUid; + contact.itemUid = item.uid; + cur.set(item.uid, contact); + } catch (e) { + store.dispatch(appendError(e)); + } } } } diff --git a/src/Tasks/Main.tsx b/src/Tasks/Main.tsx index 6276aec..645167f 100644 --- a/src/Tasks/Main.tsx +++ b/src/Tasks/Main.tsx @@ -37,16 +37,16 @@ export default function TasksMain() { const items = useItems(etebase, colType); React.useEffect(() => { - if (items) { - decryptItems(items) - .then((entries) => setEntries(entries)); - // FIXME: handle failure to decrypt items - } - if (collections) { - decryptCollections(collections) - .then((entries) => setCachedCollections(entries)); - // FIXME: handle failure to decrypt collections + if (!collections || !items) { + return; } + (async () => { + const colEntries = await decryptCollections(collections); + const entries = await decryptItems(items); + + setCachedCollections(colEntries); + setEntries(entries); + })(); }, [items, collections]); if (!entries || !cachedCollections) { diff --git a/src/store/actions.ts b/src/store/actions.ts index 29df131..9e2ec39 100644 --- a/src/store/actions.ts +++ b/src/store/actions.ts @@ -168,7 +168,7 @@ export const performSync = createAction( export const appendError = createAction( "APPEND_ERROR", - (_etesync: Etebase.Account, error: Error | Error[]) => { + (error: Error | Error[]) => { return Array.isArray(error) ? error : [error]; } ); diff --git a/src/sync/SyncManager.ts b/src/sync/SyncManager.ts index f1c3357..b02baab 100644 --- a/src/sync/SyncManager.ts +++ b/src/sync/SyncManager.ts @@ -6,7 +6,7 @@ import * as Etebase from "etebase"; import { store, StoreState } from "../store"; import { credentialsSelector } from "../credentials"; -import { setSyncCollection, setSyncGeneral, setCacheCollection, unsetCacheCollection, setCacheItemMulti } from "../store/actions"; +import { setSyncCollection, setSyncGeneral, setCacheCollection, unsetCacheCollection, setCacheItemMulti, appendError } from "../store/actions"; const cachedSyncManager = new Map(); export class SyncManager { @@ -105,7 +105,7 @@ export class SyncManager { case 401: // INVALID TOKEN case 403: // FORBIDDEN case 503: // UNAVAILABLE - // FIXME store.dispatch(addNonFatalError(this.etebase, e)); + store.dispatch(appendError(e)); return null; } }