From 3b7addb8640822401de662f3ea9c58cc550e5122 Mon Sep 17 00:00:00 2001 From: Jacob Mischka Date: Fri, 28 Apr 2023 12:25:59 -0500 Subject: [PATCH] Catch and log errors in metadata prop Promises --- src/classes/IOClient.ts | 2 +- src/components/displayMetadata.ts | 349 +++++++++++++++++------------- src/examples/basic/index.ts | 6 + 3 files changed, 204 insertions(+), 153 deletions(-) diff --git a/src/classes/IOClient.ts b/src/classes/IOClient.ts index fe571cb..83cbd0b 100644 --- a/src/classes/IOClient.ts +++ b/src/classes/IOClient.ts @@ -1034,7 +1034,7 @@ export class IOClient { * ``` */ metadata: this.createIOMethod('DISPLAY_METADATA', { - componentDef: displayMetadata, + componentDef: displayMetadata(this.logger), propsRequired: true, }), /** diff --git a/src/components/displayMetadata.ts b/src/components/displayMetadata.ts index 87f09c3..e1fec5e 100644 --- a/src/components/displayMetadata.ts +++ b/src/components/displayMetadata.ts @@ -1,4 +1,5 @@ import type { Evt } from 'evt' +import Logger from '../classes/Logger' import { T_IO_PROPS, Serializable, @@ -18,185 +19,229 @@ export interface EventualMetaItem { params?: EventualValue } -export default function displayMetadata( - props: Pick, 'layout'> & { - data: EventualMetaItem[] - }, - onPropsUpdate?: Evt> -): { props: T_IO_PROPS<'DISPLAY_METADATA'> } { - const layout = props.layout - const metaItems: EventualMetaItem[] = [] - const data: T_IO_PROPS<'DISPLAY_METADATA'>['data'] = props.data.map( - metaItem => { - metaItem = { ...metaItem } - - const initialItem: T_IO_PROPS<'DISPLAY_METADATA'>['data'][0] = { - label: metaItem.label, - } - - // Currently doing all of this repetitive work separately to leverage - // static type checking, but could be done more dynamically in a loop as well +export default function displaymetadata(logger: Logger) { + return function displayMetadata( + props: Pick, 'layout'> & { + data: EventualMetaItem[] + }, + onPropsUpdate?: Evt> + ): { props: T_IO_PROPS<'DISPLAY_METADATA'> } { + const layout = props.layout + const metaItems: EventualMetaItem[] = [] + const data: T_IO_PROPS<'DISPLAY_METADATA'>['data'] = props.data.map( + metaItem => { + metaItem = { ...metaItem } - if ('value' in metaItem && metaItem.value !== undefined) { - if (typeof metaItem.value === 'function') { - metaItem.value = metaItem.value() + const initialItem: T_IO_PROPS<'DISPLAY_METADATA'>['data'][0] = { + label: metaItem.label, } - if (!(metaItem.value instanceof Promise)) { - initialItem.value = metaItem.value - } else { - initialItem.value = undefined - } - } + // Currently doing all of this repetitive work separately to leverage + // static type checking, but could be done more dynamically in a loop as well - if ('url' in metaItem && metaItem.url !== undefined) { - if (typeof metaItem.url === 'function') { - metaItem.url = metaItem.url() - } + if ('value' in metaItem && metaItem.value !== undefined) { + if (typeof metaItem.value === 'function') { + metaItem.value = metaItem.value() + } - if (!(metaItem.url instanceof Promise)) { - initialItem.url = metaItem.url - } else { - initialItem.url = undefined + if (!(metaItem.value instanceof Promise)) { + initialItem.value = metaItem.value + } else { + initialItem.value = undefined + } } - } - if ('image' in metaItem && metaItem.image !== undefined) { - if (typeof metaItem.image === 'function') { - metaItem.image = metaItem.image() - } + if ('url' in metaItem && metaItem.url !== undefined) { + if (typeof metaItem.url === 'function') { + metaItem.url = metaItem.url() + } - if (!(metaItem.image instanceof Promise)) { - initialItem.image = metaItem.image - } else { - initialItem.image = undefined - } - } - - if ('route' in metaItem && metaItem.route !== undefined) { - if (typeof metaItem.route === 'function') { - metaItem.route = metaItem.route() + if (!(metaItem.url instanceof Promise)) { + initialItem.url = metaItem.url + } else { + initialItem.url = undefined + } } - if (!(metaItem.route instanceof Promise)) { - initialItem.route = metaItem.route - } else { - initialItem.route = undefined - } - } - - if ('action' in metaItem && metaItem.action !== undefined) { - if (typeof metaItem.action === 'function') { - metaItem.action = metaItem.action() - } + if ('image' in metaItem && metaItem.image !== undefined) { + if (typeof metaItem.image === 'function') { + metaItem.image = metaItem.image() + } - if (!(metaItem.action instanceof Promise)) { - initialItem.action = metaItem.action - } else { - initialItem.action = undefined + if (!(metaItem.image instanceof Promise)) { + initialItem.image = metaItem.image + } else { + initialItem.image = undefined + } } - } - if ('params' in metaItem && metaItem.params !== undefined) { - if (typeof metaItem.params === 'function') { - metaItem.params = metaItem.params() - } + if ('route' in metaItem && metaItem.route !== undefined) { + if (typeof metaItem.route === 'function') { + metaItem.route = metaItem.route() + } - if (!(metaItem.params instanceof Promise)) { - initialItem.params = metaItem.params - } else { - initialItem.params = undefined + if (!(metaItem.route instanceof Promise)) { + initialItem.route = metaItem.route + } else { + initialItem.route = undefined + } } - } - metaItems.push(metaItem) + if ('action' in metaItem && metaItem.action !== undefined) { + if (typeof metaItem.action === 'function') { + metaItem.action = metaItem.action() + } - return initialItem - } - ) - - if (onPropsUpdate) { - for (let i = 0; i < metaItems.length; i++) { - const metaItem = metaItems[i] - - if ('value' in metaItem) { - if (metaItem.value instanceof Promise) { - metaItem.value.then(resolvedValue => { - data[i].value = resolvedValue - onPropsUpdate?.post({ - layout, - data, - }) - }) + if (!(metaItem.action instanceof Promise)) { + initialItem.action = metaItem.action + } else { + initialItem.action = undefined + } } - } - if ('url' in metaItem) { - if (metaItem.url instanceof Promise) { - metaItem.url.then(resolvedurl => { - data[i].url = resolvedurl - onPropsUpdate?.post({ - layout, - data, - }) - }) - } - } + if ('params' in metaItem && metaItem.params !== undefined) { + if (typeof metaItem.params === 'function') { + metaItem.params = metaItem.params() + } - if ('image' in metaItem) { - if (metaItem.image instanceof Promise) { - metaItem.image.then(resolvedimage => { - data[i].image = resolvedimage - onPropsUpdate?.post({ - layout, - data, - }) - }) + if (!(metaItem.params instanceof Promise)) { + initialItem.params = metaItem.params + } else { + initialItem.params = undefined + } } - } - if ('route' in metaItem) { - if (metaItem.route instanceof Promise) { - metaItem.route.then(resolvedroute => { - data[i].route = resolvedroute - onPropsUpdate?.post({ - layout, - data, - }) - }) - } - } + metaItems.push(metaItem) - if ('action' in metaItem) { - if (metaItem.action instanceof Promise) { - metaItem.action.then(resolvedaction => { - data[i].action = resolvedaction - onPropsUpdate?.post({ - layout, - data, - }) - }) - } + return initialItem } - - if ('params' in metaItem) { - if (metaItem.params instanceof Promise) { - metaItem.params.then(resolvedparams => { - data[i].params = resolvedparams - onPropsUpdate?.post({ - layout, - data, - }) - }) + ) + + if (onPropsUpdate) { + for (let i = 0; i < metaItems.length; i++) { + const metaItem = metaItems[i] + + if ('value' in metaItem) { + if (metaItem.value instanceof Promise) { + metaItem.value + .then(resolvedValue => { + data[i].value = resolvedValue + onPropsUpdate?.post({ + layout, + data, + }) + }) + .catch(err => { + logger.error( + 'Error updating metadata field "value" with result from Promise:', + err + ) + }) + } + } + + if ('url' in metaItem) { + if (metaItem.url instanceof Promise) { + metaItem.url + .then(resolvedurl => { + data[i].url = resolvedurl + onPropsUpdate?.post({ + layout, + data, + }) + }) + .catch(err => { + logger.error( + 'Error updating metadata field "url" with result from Promise:', + err + ) + }) + } + } + + if ('image' in metaItem) { + if (metaItem.image instanceof Promise) { + metaItem.image + .then(resolvedimage => { + data[i].image = resolvedimage + onPropsUpdate?.post({ + layout, + data, + }) + }) + .catch(err => { + logger.error( + 'Error updating metadata field "image" with result from Promise:', + err + ) + }) + } + } + + if ('route' in metaItem) { + if (metaItem.route instanceof Promise) { + metaItem.route + .then(resolvedroute => { + data[i].route = resolvedroute + onPropsUpdate?.post({ + layout, + data, + }) + }) + .catch(err => { + logger.error( + 'Error updating metadata field "route" with result from Promise:', + err + ) + }) + } + } + + if ('action' in metaItem) { + if (metaItem.action instanceof Promise) { + metaItem.action + .then(resolvedaction => { + data[i].action = resolvedaction + onPropsUpdate?.post({ + layout, + data, + }) + }) + .catch(err => { + logger.error( + 'Error updating metadata field "action" with result from Promise:', + err + ) + }) + } + } + + if ('params' in metaItem) { + if (metaItem.params instanceof Promise) { + metaItem.params + .then(resolvedparams => { + data[i].params = resolvedparams + onPropsUpdate?.post({ + layout, + data, + }) + }) + .catch(err => { + logger.error( + 'Error updating metadata field "params" with result from Promise:', + err + ) + }) + } } } } - } - return { - props: { - data, - layout, - }, + return { + props: { + data, + layout, + }, + } } } diff --git a/src/examples/basic/index.ts b/src/examples/basic/index.ts index 41c8047..b76a91d 100644 --- a/src/examples/basic/index.ts +++ b/src/examples/basic/index.ts @@ -1086,6 +1086,12 @@ const interval = new Interval({ resolve('Done!') }), }, + { + label: 'Throws an error', + value: new Promise(() => { + throw new Error('Oops!') + }), + }, { label: 'Is a function', value: () => 'Called it',