From 06e816c4e20e75ae924fe13e8d345732551237b0 Mon Sep 17 00:00:00 2001 From: Jacob Mischka Date: Mon, 10 Oct 2022 12:14:04 -0500 Subject: [PATCH 01/11] Add missing display methods to union type Adds: - DISPLAY_CODE - DISPLAY_IMAGE - DISPLAY_VIDEO Close T-146 --- src/ioSchema.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/ioSchema.ts b/src/ioSchema.ts index 942a1d9..f1f4f39 100644 --- a/src/ioSchema.ts +++ b/src/ioSchema.ts @@ -266,6 +266,9 @@ export function resolvesImmediately(methodName: T_IO_METHOD_NAMES): boolean { return 'immediate' in ioSchema[methodName] } +/** + * IMPORTANT: When adding any new DISPLAY methods, be sure to also add their method names to T_IO_DISPLAY_METHOD_NAMES below. + */ export const ioSchema = { INPUT_TEXT: { props: z.object({ @@ -607,11 +610,14 @@ export type T_IO_Schema = typeof ioSchema export type T_IO_METHOD_NAMES = keyof T_IO_Schema export type T_IO_DISPLAY_METHOD_NAMES = + | 'DISPLAY_CODE' | 'DISPLAY_HEADING' | 'DISPLAY_MARKDOWN' | 'DISPLAY_LINK' | 'DISPLAY_OBJECT' | 'DISPLAY_TABLE' + | 'DISPLAY_IMAGE' + | 'DISPLAY_VIDEO' export type T_IO_INPUT_METHOD_NAMES = Exclude< T_IO_METHOD_NAMES, From 382a5e90da9ff98632d9e80b32d6a41c40888a55 Mon Sep 17 00:00:00 2001 From: Dan Philibin Date: Tue, 11 Oct 2022 00:56:26 +0000 Subject: [PATCH 02/11] add 'primary' and 'secondary' as button theme options --- src/classes/IntervalClient.ts | 3 ++- src/classes/Layout.ts | 18 ++++++++++++------ src/ioSchema.ts | 26 +++++++++++++++++++++++++- src/types.ts | 16 +++++++++++----- 4 files changed, 50 insertions(+), 13 deletions(-) diff --git a/src/classes/IntervalClient.ts b/src/classes/IntervalClient.ts index 423f99f..1bf3c59 100644 --- a/src/classes/IntervalClient.ts +++ b/src/classes/IntervalClient.ts @@ -38,6 +38,7 @@ import type { IntervalActionStore, IntervalPageStore, InternalMenuItem, + InternalButtonItem, } from '../types' import TransactionLoadingState from '../classes/TransactionLoadingState' import localConfig from '../localConfig' @@ -646,7 +647,7 @@ export default class IntervalClient { } let page: Layout - let menuItems: InternalMenuItem[] | undefined = undefined + let menuItems: InternalButtonItem[] | undefined = undefined let renderInstruction: T_IO_RENDER_INPUT | undefined = undefined const MAX_PAGE_RETRIES = 5 diff --git a/src/classes/Layout.ts b/src/classes/Layout.ts index 2d1e0dc..d82a391 100644 --- a/src/classes/Layout.ts +++ b/src/classes/Layout.ts @@ -1,6 +1,12 @@ import { z } from 'zod' -import { primitiveValue, Literal, IO_RENDER, menuItem } from '../ioSchema' -import { AnyDisplayIOPromise, MenuItem } from '../types' +import { + primitiveValue, + Literal, + IO_RENDER, + menuItem, + buttonItem, +} from '../ioSchema' +import { AnyDisplayIOPromise, ButtonItem } from '../types' type EventualString = | string @@ -12,7 +18,7 @@ interface BasicLayoutConfig { title?: EventualString description?: EventualString children?: AnyDisplayIOPromise[] - menuItems?: MenuItem[] + menuItems?: ButtonItem[] metadata?: MetaItem[] } @@ -20,7 +26,7 @@ export interface Layout { title?: EventualString description?: EventualString children?: AnyDisplayIOPromise[] - menuItems?: MenuItem[] + menuItems?: ButtonItem[] } // Base class @@ -28,7 +34,7 @@ export class Basic implements Layout { title?: EventualString description?: EventualString children?: AnyDisplayIOPromise[] - menuItems?: MenuItem[] + menuItems?: ButtonItem[] metadata?: MetaItem[] constructor(config: BasicLayoutConfig) { @@ -72,7 +78,7 @@ export const BASIC_LAYOUT_SCHEMA = z.object({ description: z.string().nullish(), children: IO_RENDER.optional(), metadata: META_ITEMS_SCHEMA.optional(), - menuItems: z.array(menuItem).optional(), + menuItems: z.array(buttonItem).optional(), }) // To be extended with z.discriminatedUnion when adding different pages diff --git a/src/ioSchema.ts b/src/ioSchema.ts index f1f4f39..e9deddf 100644 --- a/src/ioSchema.ts +++ b/src/ioSchema.ts @@ -29,7 +29,10 @@ export const DISPLAY_RENDER = z.object({ kind: z.literal('RENDER'), }) -const buttonTheme = z.enum(['default', 'danger']).default('default').optional() +const buttonTheme = z + .enum(['default', 'primary', 'secondary', 'danger']) + .default('primary') + .optional() export type ButtonTheme = z.infer export const IO_RENDER = z.object({ @@ -186,6 +189,27 @@ export const tableRow = z .or(z.record(z.any())) export const menuItem = z.intersection( + z.object({ + label: z.string(), + theme: z.enum(['default', 'danger']).optional(), + }), + z.union([ + z.object({ + action: z.string(), + params: serializableRecord.optional(), + disabled: z.boolean().optional(), + }), + z.object({ + url: z.string(), + disabled: z.boolean().optional(), + }), + z.object({ + disabled: z.literal(true), + }), + ]) +) + +export const buttonItem = z.intersection( z.object({ label: z.string(), theme: buttonTheme, diff --git a/src/types.ts b/src/types.ts index 593ef79..a46950a 100644 --- a/src/types.ts +++ b/src/types.ts @@ -12,6 +12,7 @@ import type { T_IO_INPUT_METHOD_NAMES, LinkProps, menuItem, + buttonItem, ButtonTheme, serializableRecord, ImageSize, @@ -182,11 +183,13 @@ export type ComponentsRenderer< components: Components, validator?: IOClientRenderValidator, continueButton?: ButtonConfig -) => Promise<{ - [Idx in keyof Components]: Components[Idx] extends AnyIOComponent - ? z.infer | undefined - : Components[Idx] -}> +) => Promise< + { + [Idx in keyof Components]: Components[Idx] extends AnyIOComponent + ? z.infer | undefined + : Components[Idx] + } +> export type IORenderSender = (ioToRender: T_IO_RENDER_INPUT) => Promise @@ -285,6 +288,9 @@ export type IOComponentDefinition< export type InternalMenuItem = z.input export type MenuItem = InternalMenuItem + +export type InternalButtonItem = z.input +export type ButtonItem = InternalButtonItem // | { // label: InternalMenuItem['label'] // theme?: InternalMenuItem['theme'] From a8007f085cb47fb94eb3c9dc5ffc8d3a967f2d85 Mon Sep 17 00:00:00 2001 From: Dan Philibin Date: Tue, 11 Oct 2022 18:41:37 +0000 Subject: [PATCH 03/11] deprecate 'default' button theme --- src/components/displayTable.ts | 4 ++-- src/components/selectTable.ts | 4 ++-- src/ioSchema.ts | 4 +++- src/types.ts | 12 ++++++++++-- 4 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/components/displayTable.ts b/src/components/displayTable.ts index 3e2c451..232ed59 100644 --- a/src/components/displayTable.ts +++ b/src/components/displayTable.ts @@ -1,7 +1,7 @@ import { z } from 'zod' import Logger from '../classes/Logger' import { tableRow, T_IO_PROPS, menuItem, T_IO_STATE } from '../ioSchema' -import { TableColumn } from '../types' +import { InternalMenuItem, MenuItem, TableColumn } from '../types' import { columnsBuilder, tableRowSerializer, @@ -17,7 +17,7 @@ type PublicProps = Omit< > & { data: Row[] columns?: (TableColumn | string)[] - rowMenuItems?: (row: Row) => z.infer[] + rowMenuItems?: (row: Row) => MenuItem[] } export default function displayTable(logger: Logger) { diff --git a/src/components/selectTable.ts b/src/components/selectTable.ts index ccde96d..1f168a8 100644 --- a/src/components/selectTable.ts +++ b/src/components/selectTable.ts @@ -7,7 +7,7 @@ import { T_IO_RETURNS, T_IO_STATE, } from '../ioSchema' -import { TableColumn } from '../types' +import { MenuItem, TableColumn } from '../types' import { columnsBuilder, filterRows, @@ -20,7 +20,7 @@ import { type PublicProps = Omit, 'data' | 'columns'> & { data: Row[] columns?: (TableColumn | string)[] - rowMenuItems?: (row: Row) => z.infer[] + rowMenuItems?: (row: Row) => MenuItem[] } export default function selectTable(logger: Logger) { diff --git a/src/ioSchema.ts b/src/ioSchema.ts index e9deddf..9e38051 100644 --- a/src/ioSchema.ts +++ b/src/ioSchema.ts @@ -29,11 +29,12 @@ export const DISPLAY_RENDER = z.object({ kind: z.literal('RENDER'), }) +// `default` deprecated in 0.31.0 const buttonTheme = z .enum(['default', 'primary', 'secondary', 'danger']) .default('primary') .optional() -export type ButtonTheme = z.infer +export type ButtonTheme = 'primary' | 'secondary' | 'danger' export const IO_RENDER = z.object({ id: z.string(), @@ -191,6 +192,7 @@ export const tableRow = z export const menuItem = z.intersection( z.object({ label: z.string(), + // `default` deprecated in 0.31.0 theme: z.enum(['default', 'danger']).optional(), }), z.union([ diff --git a/src/types.ts b/src/types.ts index a46950a..b5fd0b6 100644 --- a/src/types.ts +++ b/src/types.ts @@ -286,11 +286,19 @@ export type IOComponentDefinition< ) => Promise> } +type DistributiveOmit = T extends any + ? Omit + : never + export type InternalMenuItem = z.input -export type MenuItem = InternalMenuItem +export type MenuItem = DistributiveOmit & { + theme?: 'danger' +} export type InternalButtonItem = z.input -export type ButtonItem = InternalButtonItem +export type ButtonItem = DistributiveOmit & { + theme?: 'primary' | 'secondary' | 'danger' +} // | { // label: InternalMenuItem['label'] // theme?: InternalMenuItem['theme'] From 4274748df7da73e6920bfc65b471224b8d1cf1cf Mon Sep 17 00:00:00 2001 From: Jacob Mischka Date: Tue, 11 Oct 2022 13:35:03 -0500 Subject: [PATCH 04/11] Add useSubnavState hook to cache structure for current page This doesn't affect the top-level nav, because it relies on subnav probably not intentionally changing much so long as the slug stays the same. Close T-144 --- src/examples/app/index.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/examples/app/index.ts b/src/examples/app/index.ts index bad5e4a..9c284a7 100644 --- a/src/examples/app/index.ts +++ b/src/examples/app/index.ts @@ -23,6 +23,14 @@ const hello_app = new Router({ { label: 'Promise', value: sleep(2000).then(() => 2000) }, ], menuItems: [ + { + label: 'Hello world', + action: 'hello_world', + }, + { + label: 'Add user', + action: 'users/create', + }, { label: 'Action link', action: 'hello_app/hello_world', From 3e6a67062c65b1d6b70fe3c928e87dfb2db2273b Mon Sep 17 00:00:00 2001 From: Jacob Mischka Date: Wed, 12 Oct 2022 13:28:34 -0500 Subject: [PATCH 05/11] Actually display router description in the app Close T-183 --- src/examples/app/index.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/examples/app/index.ts b/src/examples/app/index.ts index 9c284a7..9078b35 100644 --- a/src/examples/app/index.ts +++ b/src/examples/app/index.ts @@ -4,6 +4,7 @@ import * as db from './db' const hello_app = new Router({ name: 'App', + description: 'This should have a description', index: async () => { return new Layout.Basic({ title: sleep(1000).then(() => 'Resource'), @@ -202,6 +203,7 @@ const interval = new Interval({ }), hello_world: { name: 'Hello world', + description: 'This should have a description too', handler: async () => { await io.display.markdown('Hello, world!') }, From e3299295a1fdd691f5565f0483d54d16092f1b4f Mon Sep 17 00:00:00 2001 From: Jacob Mischka Date: Wed, 12 Oct 2022 13:42:25 -0500 Subject: [PATCH 06/11] Display io.display.code label as figure legend Close T-185 --- src/examples/basic/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/examples/basic/index.ts b/src/examples/basic/index.ts index ef469d8..78b0a06 100644 --- a/src/examples/basic/index.ts +++ b/src/examples/basic/index.ts @@ -334,6 +334,7 @@ const interval = new Interval({ }, code: async () => { await io.group([ + io.input.text('Text input'), io.display.code('Code from string', { code: 'console.log("Hello, world!")', language: 'typescript', From a8a1aba8c4b27094299580a2df4be2454afea13a Mon Sep 17 00:00:00 2001 From: Ryan Coppolo Date: Mon, 10 Oct 2022 10:48:38 -0400 Subject: [PATCH 07/11] Pass page handler errors to display in dashboard --- src/classes/IntervalClient.ts | 189 +++++++++++++++++++++++----------- src/classes/Layout.ts | 20 +++- src/examples/app/index.ts | 1 + src/types.ts | 7 ++ 4 files changed, 155 insertions(+), 62 deletions(-) diff --git a/src/classes/IntervalClient.ts b/src/classes/IntervalClient.ts index 1bf3c59..a2c0695 100644 --- a/src/classes/IntervalClient.ts +++ b/src/classes/IntervalClient.ts @@ -39,6 +39,7 @@ import type { IntervalPageStore, InternalMenuItem, InternalButtonItem, + PageError, } from '../types' import TransactionLoadingState from '../classes/TransactionLoadingState' import localConfig from '../localConfig' @@ -50,6 +51,7 @@ import { LayoutSchemaInput, MetaItemSchema, MetaItemsSchema, + BasicLayoutConfig, } from './Layout' export const DEFAULT_WEBSOCKET_ENDPOINT = 'wss://interval.com/websocket' @@ -649,6 +651,7 @@ export default class IntervalClient { let page: Layout let menuItems: InternalButtonItem[] | undefined = undefined let renderInstruction: T_IO_RENDER_INPUT | undefined = undefined + let errors: PageError[] = [] const MAX_PAGE_RETRIES = 5 @@ -670,6 +673,7 @@ export default class IntervalClient { : null, menuItems, children: renderInstruction, + errors, } if (page.metadata) { @@ -775,82 +779,147 @@ export default class IntervalClient { this.#pageIOClients.set(pageKey, client) this.#ioResponseHandlers.set(pageKey, client.onResponse.bind(client)) - pageLocalStorage.run({ display, ctx }, () => { - appHandler(display, ctx).then(res => { - page = res - - if (typeof page.title === 'function') { - page.title = page.title() + const pageError = ( + error: unknown, + layoutKey?: keyof BasicLayoutConfig + ) => { + if (error instanceof Error) { + return { + layoutKey, + error: error.name, + message: error.message, } - - if (page.title instanceof Promise) { - page.title.then(title => { - page.title = title - scheduleSendPage() - }) + } else { + return { + layoutKey, + error: 'Unknown error', + message: String(error), } + } + } - if (page.description) { - if (typeof page.description === 'function') { - page.description = page.description() + pageLocalStorage.run({ display, ctx }, () => { + appHandler(display, ctx) + .then(res => { + page = res + + if (typeof page.title === 'function') { + try { + page.title = page.title() + } catch (err) { + this.#logger.error(err) + errors.push(pageError(err, 'title')) + } } - if (page.description instanceof Promise) { - page.description.then(description => { - page.description = description - scheduleSendPage() - }) + if (page.title instanceof Promise) { + page.title + .then(title => { + page.title = title + scheduleSendPage() + }) + .catch(err => { + this.#logger.error(err) + errors.push(pageError(err, 'title')) + scheduleSendPage() + }) } - } - - if (page.menuItems) { - menuItems = page.menuItems.map(menuItem => { - // if ( - // 'action' in menuItem && - // typeof menuItem['action'] === 'function' - // ) { - // const inlineAction = client.addInlineAction(menuItem.action) - // return { - // ...menuItem, - // inlineAction, - // } - // } - - return menuItem - }) - } - if (page instanceof Basic) { - const { metadata } = page - if (metadata) { - for (let i = 0; i < metadata.length; i++) { - let { value } = metadata[i] - if (typeof value === 'function') { - value = value() - metadata[i].value = value + if (page.description) { + if (typeof page.description === 'function') { + try { + page.description = page.description() + } catch (err) { + this.#logger.error(err) + errors.push(pageError(err, 'description')) } + } - if (value instanceof Promise) { - value.then(resolved => { - metadata[i].value = resolved + if (page.description instanceof Promise) { + page.description + .then(description => { + page.description = description scheduleSendPage() }) + .catch(err => { + this.#logger.error(err) + errors.push(pageError(err, 'description')) + scheduleSendPage() + }) + } + } + + if (page.menuItems) { + menuItems = page.menuItems.map(menuItem => { + // if ( + // 'action' in menuItem && + // typeof menuItem['action'] === 'function' + // ) { + // const inlineAction = client.addInlineAction(menuItem.action) + // return { + // ...menuItem, + // inlineAction, + // } + // } + + return menuItem + }) + } + + if (page instanceof Basic) { + const { metadata } = page + if (metadata) { + for (let i = 0; i < metadata.length; i++) { + let { value } = metadata[i] + if (typeof value === 'function') { + try { + value = value() + metadata[i].value = value + } catch (err) { + this.#logger.error(err) + errors.push(pageError(err, 'metadata')) + } + } + + if (value instanceof Promise) { + value + .then(resolved => { + metadata[i].value = resolved + scheduleSendPage() + }) + .catch(err => { + this.#logger.error(err) + errors.push(pageError(err, 'metadata')) + scheduleSendPage() + }) + } } } } - } - if (page.children) { - group(page.children).then(() => { - this.#logger.debug( - 'Initial children render complete for pageKey', - pageKey - ) + if (page.children) { + group(page.children).then(() => { + this.#logger.debug( + 'Initial children render complete for pageKey', + pageKey + ) + }) + } else { + scheduleSendPage() + } + }) + .catch(async err => { + this.#logger.error(err) + errors.push(pageError(err)) + const pageLayout: LayoutSchemaInput = { + kind: 'BASIC', + errors, + } + await this.#send('SEND_PAGE', { + pageKey, + page: JSON.stringify(pageLayout), }) - } else { - scheduleSendPage() - } - }) + }) }) return { diff --git a/src/classes/Layout.ts b/src/classes/Layout.ts index d82a391..0608e25 100644 --- a/src/classes/Layout.ts +++ b/src/classes/Layout.ts @@ -6,7 +6,7 @@ import { menuItem, buttonItem, } from '../ioSchema' -import { AnyDisplayIOPromise, ButtonItem } from '../types' +import { AnyDisplayIOPromise, ButtonItem, PageError } from '../types' type EventualString = | string @@ -14,7 +14,7 @@ type EventualString = | (() => string) | (() => Promise) -interface BasicLayoutConfig { +export interface BasicLayoutConfig { title?: EventualString description?: EventualString children?: AnyDisplayIOPromise[] @@ -27,6 +27,7 @@ export interface Layout { description?: EventualString children?: AnyDisplayIOPromise[] menuItems?: ButtonItem[] + errors?: PageError[] } // Base class @@ -36,6 +37,7 @@ export class Basic implements Layout { children?: AnyDisplayIOPromise[] menuItems?: ButtonItem[] metadata?: MetaItem[] + errors?: PageError[] constructor(config: BasicLayoutConfig) { this.title = config.title @@ -43,6 +45,7 @@ export class Basic implements Layout { this.children = config.children this.menuItems = config.menuItems this.metadata = config.metadata + this.errors = [] } } @@ -78,7 +81,20 @@ export const BASIC_LAYOUT_SCHEMA = z.object({ description: z.string().nullish(), children: IO_RENDER.optional(), metadata: META_ITEMS_SCHEMA.optional(), +<<<<<<< HEAD menuItems: z.array(buttonItem).optional(), +======= + menuItems: z.array(menuItem).optional(), + errors: z + .array( + z.object({ + layoutKey: z.string().optional(), + error: z.string(), + message: z.string(), + }) + ) + .optional(), +>>>>>>> b53b9d00 (Pass page handler errors to display in dashboard) }) // To be extended with z.discriminatedUnion when adding different pages diff --git a/src/examples/app/index.ts b/src/examples/app/index.ts index 9078b35..3784f4e 100644 --- a/src/examples/app/index.ts +++ b/src/examples/app/index.ts @@ -18,6 +18,7 @@ const hello_app = new Router({ label: 'Async function', value: async () => { await sleep(1000) + throw new Error('Metadata error in an async function') return '1 second' }, }, diff --git a/src/types.ts b/src/types.ts index b5fd0b6..f607e4a 100644 --- a/src/types.ts +++ b/src/types.ts @@ -34,6 +34,7 @@ import type { import type IOError from './classes/IOError' import type TransactionLoadingState from './classes/TransactionLoadingState' import type { Router } from './experimental' +import { BasicLayoutConfig } from './classes/Layout' export type ActionCtx = Pick< z.infer, @@ -337,3 +338,9 @@ export interface TableColumn { label: string renderCell: (row: Row) => TableColumnResult } + +export type PageError = { + error: string + message: string + layoutKey?: keyof BasicLayoutConfig +} From 01a1d291a6da5225d1b8838303baad1895a965ca Mon Sep 17 00:00:00 2001 From: Ryan Coppolo Date: Mon, 10 Oct 2022 14:26:29 -0400 Subject: [PATCH 08/11] Update metadata card with error too --- src/classes/IntervalClient.ts | 16 ++++++++++++---- src/classes/Layout.ts | 2 ++ 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/classes/IntervalClient.ts b/src/classes/IntervalClient.ts index a2c0695..044bba6 100644 --- a/src/classes/IntervalClient.ts +++ b/src/classes/IntervalClient.ts @@ -679,11 +679,13 @@ export default class IntervalClient { if (page.metadata) { const items: MetaItemSchema[] = [] for (const pageItem of page.metadata) { - let { label, value } = pageItem + let { label, value, error } = pageItem if (typeof value === 'function' || value instanceof Promise) { items.push({ label }) } else { - items.push({ label, value }) + items.push( + error ? { label, value, error } : { label, value } + ) } } @@ -877,7 +879,10 @@ export default class IntervalClient { metadata[i].value = value } catch (err) { this.#logger.error(err) - errors.push(pageError(err, 'metadata')) + const error = pageError(err) + errors.push(error) + metadata[i].value = null + metadata[i].error = error.message } } @@ -889,7 +894,10 @@ export default class IntervalClient { }) .catch(err => { this.#logger.error(err) - errors.push(pageError(err, 'metadata')) + const error = pageError(err) + errors.push(error) + metadata[i].value = null + metadata[i].error = error.message scheduleSendPage() }) } diff --git a/src/classes/Layout.ts b/src/classes/Layout.ts index 0608e25..2e4a2c4 100644 --- a/src/classes/Layout.ts +++ b/src/classes/Layout.ts @@ -58,11 +58,13 @@ export interface MetaItem { | Promise | (() => MetaItemValue) | (() => Promise) + error?: string } export const META_ITEM_SCHEMA = z.object({ label: z.string(), value: primitiveValue.or(z.bigint()).nullish(), + error: z.string().optional(), }) export type MetaItemSchema = z.infer From cdde9af7a25c4b2e89b1ab52b113c290c7cb59d7 Mon Sep 17 00:00:00 2001 From: Ryan Coppolo Date: Wed, 12 Oct 2022 14:01:17 -0400 Subject: [PATCH 09/11] Communicate errors in more granular locations --- src/classes/IntervalClient.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/classes/IntervalClient.ts b/src/classes/IntervalClient.ts index 044bba6..d6b9da3 100644 --- a/src/classes/IntervalClient.ts +++ b/src/classes/IntervalClient.ts @@ -879,7 +879,7 @@ export default class IntervalClient { metadata[i].value = value } catch (err) { this.#logger.error(err) - const error = pageError(err) + const error = pageError(err, 'metadata') errors.push(error) metadata[i].value = null metadata[i].error = error.message @@ -894,7 +894,7 @@ export default class IntervalClient { }) .catch(err => { this.#logger.error(err) - const error = pageError(err) + const error = pageError(err, 'metadata') errors.push(error) metadata[i].value = null metadata[i].error = error.message From c8a706e1a5a648c317b35b184ec3c1fd01dfc537 Mon Sep 17 00:00:00 2001 From: Ryan Coppolo Date: Wed, 12 Oct 2022 14:06:50 -0400 Subject: [PATCH 10/11] Fix rebase miss --- src/classes/Layout.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/classes/Layout.ts b/src/classes/Layout.ts index 2e4a2c4..8ee687c 100644 --- a/src/classes/Layout.ts +++ b/src/classes/Layout.ts @@ -83,10 +83,7 @@ export const BASIC_LAYOUT_SCHEMA = z.object({ description: z.string().nullish(), children: IO_RENDER.optional(), metadata: META_ITEMS_SCHEMA.optional(), -<<<<<<< HEAD menuItems: z.array(buttonItem).optional(), -======= - menuItems: z.array(menuItem).optional(), errors: z .array( z.object({ @@ -96,7 +93,6 @@ export const BASIC_LAYOUT_SCHEMA = z.object({ }) ) .optional(), ->>>>>>> b53b9d00 (Pass page handler errors to display in dashboard) }) // To be extended with z.discriminatedUnion when adding different pages From a28a0eeb3b1f27d1c2c4db1438a8ef818ac56dad Mon Sep 17 00:00:00 2001 From: Ryan Coppolo Date: Thu, 13 Oct 2022 09:59:59 -0400 Subject: [PATCH 11/11] Avoid ternary --- src/classes/IntervalClient.ts | 4 +--- src/classes/Layout.ts | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/classes/IntervalClient.ts b/src/classes/IntervalClient.ts index d6b9da3..4fff6b6 100644 --- a/src/classes/IntervalClient.ts +++ b/src/classes/IntervalClient.ts @@ -683,9 +683,7 @@ export default class IntervalClient { if (typeof value === 'function' || value instanceof Promise) { items.push({ label }) } else { - items.push( - error ? { label, value, error } : { label, value } - ) + items.push({ label, value, error }) } } diff --git a/src/classes/Layout.ts b/src/classes/Layout.ts index 8ee687c..78ae2d2 100644 --- a/src/classes/Layout.ts +++ b/src/classes/Layout.ts @@ -64,7 +64,7 @@ export interface MetaItem { export const META_ITEM_SCHEMA = z.object({ label: z.string(), value: primitiveValue.or(z.bigint()).nullish(), - error: z.string().optional(), + error: z.string().nullish(), }) export type MetaItemSchema = z.infer