diff --git a/src/classes/IOClient.ts b/src/classes/IOClient.ts index bee18d3..523ddbd 100644 --- a/src/classes/IOClient.ts +++ b/src/classes/IOClient.ts @@ -1047,7 +1047,7 @@ export class IOClient { /** * Displays data in a grid layout. * - * Grid items can include a title, description, image, and options menu, and can optionally link to another page, action, or external URL. + * Grid items can include a label, description, image, and options menu, and can optionally link to another page, action, or external URL. * * Grid item size can be controlled using the idealColumnWidth property. Interval will calculate a column width that is as close as possible to that number while factoring in gutter size and window width. * @@ -1082,7 +1082,7 @@ export class IOClient { * }, * ], * renderItem: row => ({ - * title: row.album, + * label: row.album, * description: row.artist, * image: { * url: row.imageUrl, diff --git a/src/classes/TransactionLoadingState.ts b/src/classes/TransactionLoadingState.ts index 8970e6f..1d49645 100644 --- a/src/classes/TransactionLoadingState.ts +++ b/src/classes/TransactionLoadingState.ts @@ -1,15 +1,18 @@ -import { LoadingOptions, LoadingState } from '../internalRpcSchema' +import { + BackwardCompatibleLoadingOptions, + BackwardCompatibleLoadingState, +} from '../internalRpcSchema' import Logger from './Logger' export interface TransactionLoadingStateConfig { logger: Logger - send: (loadingState: LoadingState) => Promise + send: (loadingState: BackwardCompatibleLoadingState) => Promise } export default class TransactionLoadingState { #logger: Logger #sender: TransactionLoadingStateConfig['send'] - #state: LoadingState | undefined + #state: BackwardCompatibleLoadingState | undefined #sendTimeout: NodeJS.Timeout | null = null #sendTimeoutMs = 100 @@ -37,21 +40,21 @@ export default class TransactionLoadingState { } /** - * Kicks off a loading spinner to provide context during any long-running action work. Can also be called with a single string argument as the title, or with no arguments to display only a spinner. + * Kicks off a loading spinner to provide context during any long-running action work. Can also be called with a single string argument as the label, or with no arguments to display only a spinner. * * **Usage:** * *```typescript * await ctx.loading.start({ - * title: "Reticulating splines...", + * label: "Reticulating splines...", * }); * - * await ctx.loading.start("Title only shorthand"); + * await ctx.loading.start("Label only shorthand"); *``` */ - async start(options?: string | LoadingOptions) { + async start(options?: string | BackwardCompatibleLoadingOptions) { if (typeof options === 'string') { - options = { title: options } + options = { label: options } } else if (options === undefined) { options = {} } @@ -71,24 +74,24 @@ export default class TransactionLoadingState { * *```typescript * await ctx.loading.start({ - * title: "Something is loading", + * label: "Something is loading", * description: "Mapping all the things", * }); * * await ctx.loading.update({ - * title: "Something is loading", + * label: "Something is loading", * description: "Now reducing all the things", * }); *``` */ - async update(options?: string | LoadingOptions) { + async update(options?: string | BackwardCompatibleLoadingOptions) { if (!this.#state) { this.#logger.warn('Please call `loading.start` before `loading.update`') return this.start(options) } if (typeof options === 'string') { - options = { title: options } + options = { label: options } } else if (options === undefined) { options = {} } @@ -109,7 +112,7 @@ export default class TransactionLoadingState { * *```typescript * await ctx.loading.start({ - * title: "Migrating users", + * label: "Migrating users", * description: "Enabling edit button for selected users", * itemsInQueue: 100, * }); diff --git a/src/components/displayGrid.ts b/src/components/displayGrid.ts index a0a379f..ac78f7d 100644 --- a/src/components/displayGrid.ts +++ b/src/components/displayGrid.ts @@ -6,7 +6,10 @@ type PublicProps = Omit< T_IO_PROPS<'DISPLAY_GRID'>, 'data' | 'totalRecords' | 'isAsync' > & { - renderItem: (row: Row) => GridItem + renderItem: (row: Row) => GridItem & { + /** @deprecated Please use `label` instead. */ + title?: string | null + } } & ( | { data: Row[] diff --git a/src/examples/basic/grid.ts b/src/examples/basic/grid.ts index b817bc9..66e634d 100644 --- a/src/examples/basic/grid.ts +++ b/src/examples/basic/grid.ts @@ -24,7 +24,7 @@ export const dogs = new Action({ data, idealColumnWidth: 200, renderItem: row => ({ - title: row.name, + label: row.name, description: row.description, route: 'tables/display_table', image: { @@ -49,7 +49,7 @@ export const tiktoks = new Action({ .fill(null) .map((_, i) => ({ id: i, - title: `video from ${faker.internet.userName()}`, + label: `video from ${faker.internet.userName()}`, description: faker.date.past().toLocaleString(), image: faker.image.animals(1080 / 4, 1920 / 4, true), })) @@ -58,7 +58,7 @@ export const tiktoks = new Action({ data, idealColumnWidth: 220, renderItem: row => ({ - title: row.title, + label: row.label, description: row.description, image: { url: row.image, @@ -86,7 +86,7 @@ export const no_images: IntervalActionHandler = async io => { .fill(null) .map((_, i) => ({ id: i, - title: faker.commerce.productName(), + label: faker.commerce.productName(), description: faker.commerce.price(100, 200, 0, '$'), })) @@ -156,7 +156,7 @@ export const music = new Action({ data, idealColumnWidth: 240, renderItem: row => ({ - title: row.name, + label: row.name, description: row.artists, image: { url: row.image, @@ -206,7 +206,7 @@ export const long_descriptions = new Action({ data, idealColumnWidth: 300, renderItem: row => ({ - title: row.name, + label: row.name, description: row.description, image: { url: row.image, @@ -231,7 +231,7 @@ export const empty_state = new Action({ data: data.slice(0, 0), idealColumnWidth: 300, renderItem: row => ({ - title: row.name, + label: row.name, }), }) }, @@ -248,9 +248,9 @@ export const async_grid: IntervalActionHandler = async io => { image: i % 5 === 0 ? null : faker.image.imageUrl(600, 300, 'dog', true), })) - await io.display.grid('Display users', { + await io.display.grid<(typeof allData)[0]>('Display users', { renderItem: row => ({ - title: row.name, + label: row.name, description: row.description, image: { url: row.image, diff --git a/src/examples/basic/index.ts b/src/examples/basic/index.ts index 1a25293..572ce4b 100644 --- a/src/examples/basic/index.ts +++ b/src/examples/basic/index.ts @@ -391,7 +391,7 @@ const interval = new Interval({ handler: async () => { await io.display.heading('Hello from display') await ctx.loading.start({ - title: 'Waiting for external system', + label: 'Waiting for external system', }) await sleep(2000) @@ -1134,7 +1134,7 @@ const interval = new Interval({ } await ctx.loading.start({ - title: 'Fetching users...', + label: 'Fetching users...', description: 'This may take a while...', }) await sleep(1500) @@ -1483,7 +1483,7 @@ const interval = new Interval({ } await ctx.loading.start({ - title: 'Updating users', + label: 'Updating users', itemsInQueue: users.length, }) for (const _ of users) { @@ -1499,7 +1499,7 @@ const interval = new Interval({ loading_dos: async () => { const itemsInQueue = 100_000 await ctx.loading.start({ - title: 'Migrating users', + label: 'Migrating users', description: 'There are a lot, but they are very fast', itemsInQueue, }) diff --git a/src/internalRpcSchema.ts b/src/internalRpcSchema.ts index a3060dc..55cfafe 100644 --- a/src/internalRpcSchema.ts +++ b/src/internalRpcSchema.ts @@ -37,18 +37,25 @@ export const actionEnvironment = z.enum(['live', 'development']) export type ActionEnvironment = z.infer export const LOADING_OPTIONS = z.object({ - title: z.string().optional(), + label: z.string().optional(), description: z.string().optional(), itemsInQueue: z.number().int().optional(), }) const LOADING_STATE = z.object({ - title: z.string().optional(), + label: z.string().optional(), description: z.string().optional(), itemsInQueue: z.number().int().optional(), itemsCompleted: z.number().int().optional(), }) +const BACKWARD_COMPATIBLE_LOADING_STATE = LOADING_STATE.merge( + z.object({ + /** @deprecated in favor of `label` (for real this time) */ + title: z.string().optional(), + }) +) + const SDK_ALERT = z.object({ minSdkVersion: z.string(), severity: z.enum(['INFO', 'WARNING', 'ERROR']), @@ -58,7 +65,14 @@ const SDK_ALERT = z.object({ export type SdkAlert = z.infer export type LoadingOptions = z.input +export type BackwardCompatibleLoadingOptions = LoadingOptions & { + /** @deprecated Please use `label` instead. */ + title?: string +} export type LoadingState = z.input +export type BackwardCompatibleLoadingState = z.input< + typeof BACKWARD_COMPATIBLE_LOADING_STATE +> export const ACCESS_CONTROL_DEFINITION = z.union([ z.literal('entire-organization'), @@ -308,10 +322,9 @@ export const wsServerSchema = { }, SEND_LOADING_CALL: { inputs: z.intersection( - LOADING_STATE, + BACKWARD_COMPATIBLE_LOADING_STATE, z.object({ transactionId: z.string(), - label: z.string().optional(), skipClientCall: z.boolean().optional(), }) ), @@ -480,7 +493,7 @@ export const clientSchema = { .object({ transactionId: z.string(), }) - .merge(LOADING_STATE), + .merge(BACKWARD_COMPATIBLE_LOADING_STATE), returns: z.boolean(), }, LOG: { diff --git a/src/ioSchema.ts b/src/ioSchema.ts index 9a28da3..877e703 100644 --- a/src/ioSchema.ts +++ b/src/ioSchema.ts @@ -312,7 +312,7 @@ export const internalTableColumn = z.object({ }) export const gridItem = z.object({ - title: z.string().nullable().optional(), + label: z.string().nullable().optional(), description: z.string().nullable().optional(), image: z .object({ @@ -329,13 +329,23 @@ export const gridItem = z.object({ params: serializableRecord.optional(), }) +export const backwardCompatibleGridItem = gridItem.merge( + z.object({ + // @deprecated in favor of label + title: z.string().nullable().optional(), + }) +) + export const internalGridItem = z.object({ - data: gridItem, + data: backwardCompatibleGridItem, key: z.string(), filterValue: z.string().optional(), }) -export type GridItem = z.infer +export type GridItem = z.input +export type BackwardCompatibleGridItem = z.input< + typeof backwardCompatibleGridItem +> export type InternalGridItem = z.infer const searchResult = z.object({