diff --git a/.changeset/25762-duration-keys-carry-unit.md b/.changeset/25762-duration-keys-carry-unit.md new file mode 100644 index 0000000000..d30cf6a233 --- /dev/null +++ b/.changeset/25762-duration-keys-carry-unit.md @@ -0,0 +1,31 @@ +--- +'@object-ui/types': minor +'@object-ui/components': minor +'@object-ui/plugin-chatbot': minor +'@object-ui/plugin-report': minor +--- + +Clause-②: yes +Metadata-protocol: added + +Nine duration keys now carry their unit in their name (objectstack#25762). Each one said its unit only in its description, so `timeout: 300` read as either milliseconds or seconds. After objectui merges into objectstack, `@objectstack/spec`'s `check:duration-unit-keys` judges these schemas too, and the maintainer chose to rename the keys rather than exempt them. The renames follow objectstack's own (`…Ms` / `…Seconds`, the unit each description already stated). The value and its unit do not change, only the key name. This is breaking for a document that still writes an old name; it is marked `minor` under this repository's version policy. + +| Node / schema | FROM | TO | Unit | +|---|---|---|---| +| `carousel` (`CarouselSchema`) | `autoPlay` | `autoPlayMs` | milliseconds | +| `chatbot`, `chatbot-enhanced`, `chatbot-floating` | `autoResponseDelay` | `autoResponseDelayMs` | milliseconds | +| `ActionSchema` | `timeout` | `timeoutMs` | milliseconds | +| `ActionSchema.retry` | `delay` | `delayMs` | milliseconds | +| `toast` (`ToastSchema`) | `duration` | `durationMs` | milliseconds | +| `tooltip` (`TooltipSchema`) | `delayDuration` | `delayDurationMs` | milliseconds | +| `hover-card` (`HoverCardSchema`) | `openDelay` | `openDelayMs` | milliseconds | +| `hover-card` (`HoverCardSchema`) | `closeDelay` | `closeDelayMs` | milliseconds | +| `report` (`ReportComponentSchema`) | `refreshInterval` | `refreshIntervalSeconds` | seconds | + +What an author sees with an old name: + +- **zod (`@object-ui/types/zod`).** The old key is still declared, as a tombstone, so it is refused at its own path with code `invalid_type`. The message names the new key: "`timeout` is now `timeoutMs` … the value (milliseconds) is unchanged." Without the tombstone, `.passthrough()` would keep the value and nothing would read it. +- **TypeScript.** The old member is `?: never` with `@deprecated`, so a typed literal that writes it fails to compile. +- **Renderers.** `toast`, `tooltip`, `hover-card`, the three chatbot registrations and `ReportViewer` read the new key. Their registration `inputs` and `defaultProps` use the new name too. The `useObjectChat` hook option `autoResponseDelay` is a programmatic API, not a schema key, and keeps its name. + +objectui has no conversion registry: ADR-0087's D2 table lives in `@objectstack/spec`. The conversion is this table plus the refusal message. To migrate, rename each key as the table shows and keep the value. diff --git a/content/docs/api/schema-reference.md b/content/docs/api/schema-reference.md index deda5fe567..ecc3c5b6c0 100644 --- a/content/docs/api/schema-reference.md +++ b/content/docs/api/schema-reference.md @@ -667,7 +667,7 @@ A powerful action definition supporting API calls, confirmations, dialogs, chain "condition": "${data.items.length > 0}", "retry": { "maxAttempts": 3, - "delay": 1000 + "delayMs": 1000 } } ``` @@ -689,7 +689,7 @@ A powerful action definition supporting API calls, confirmations, dialogs, chain | `successMessage` / `errorMessage` | `string` | Toast messages on success/failure. | | `reload` | `boolean` | Reload data after action completes. | | `redirect` | `string` | URL to navigate to after action. | -| `retry` | `object` | Retry config with `maxAttempts` and `delay`. | +| `retry` | `object` | Retry config with `maxAttempts` and `delayMs` (milliseconds; renamed from `delay`, objectstack#25762). | **Related:** [DetailSchema](#detailschema), [ButtonSchema](#buttonschema) diff --git a/content/docs/components/feedback/toast.mdx b/content/docs/components/feedback/toast.mdx index 4a831d8c56..a79b8e9ce6 100644 --- a/content/docs/components/feedback/toast.mdx +++ b/content/docs/components/feedback/toast.mdx @@ -10,7 +10,7 @@ The Toast component displays brief notifications to users that appear temporaril ## Basic Usage A `toast` node renders its own trigger button. Clicking the button raises the toast the -node declares — the title, description, variant and duration are all read off the node +node declares — the title, description, variant and `durationMs` are all read off the node itself, so the whole demo is one schema node with no handler to wire up. @@ -38,7 +38,7 @@ interface ToastSchema { variant?: 'default' | 'success' | 'warning' | 'error' | 'info'; // Timing - duration?: number; // Auto-dismiss time in ms + durationMs?: number; // Auto-dismiss time in ms } ``` diff --git a/content/docs/components/overlay/hover-card.mdx b/content/docs/components/overlay/hover-card.mdx index 65a736d1ab..de233eba03 100644 --- a/content/docs/components/overlay/hover-card.mdx +++ b/content/docs/components/overlay/hover-card.mdx @@ -20,8 +20,8 @@ interface HoverCardSchema { content: SchemaNode | SchemaNode[]; // Card content side?: 'top' | 'right' | 'bottom' | 'left'; align?: 'start' | 'center' | 'end'; - openDelay?: number; // Delay before opening (ms) - closeDelay?: number; // Delay before closing (ms) + openDelayMs?: number; // Delay before opening (ms) + closeDelayMs?: number; // Delay before closing (ms) className?: string; } ``` diff --git a/content/docs/components/overlay/tooltip.mdx b/content/docs/components/overlay/tooltip.mdx index 1943f6c5c6..505783f9d3 100644 --- a/content/docs/components/overlay/tooltip.mdx +++ b/content/docs/components/overlay/tooltip.mdx @@ -19,7 +19,7 @@ interface TooltipSchema { children?: SchemaNode | SchemaNode[]; // Rich content — the fallback half side?: 'top' | 'right' | 'bottom' | 'left'; align?: 'start' | 'center' | 'end'; - delayDuration?: number; // Delay before showing (ms) + delayDurationMs?: number; // Delay before showing (ms) } ``` diff --git a/content/docs/core/enhanced-actions.mdx b/content/docs/core/enhanced-actions.mdx index e41e2786bc..039ce15183 100644 --- a/content/docs/core/enhanced-actions.mdx +++ b/content/docs/core/enhanced-actions.mdx @@ -64,8 +64,8 @@ const ajaxAction: ActionSchema = { - `method` - HTTP method (GET, POST, PUT, DELETE, PATCH) - `data` - Request body/payload - `headers` - Custom HTTP headers -- `timeout` - Request timeout in milliseconds -- `retry` - Retry configuration +- `timeoutMs` - Request timeout in milliseconds (renamed from `timeout`) +- `retry` - Retry configuration (`maxAttempts`, `delayMs`) ### Confirm Actions @@ -389,11 +389,11 @@ const retryAction: ActionSchema = { api: '/api/submit', method: 'POST', - timeout: 30000, // 30 seconds + timeoutMs: 30000, // 30 seconds retry: { maxAttempts: 3, - delay: 1000 // 1 second between retries + delayMs: 1000 // 1 second between retries } }; ``` @@ -467,10 +467,10 @@ const complexAction: ActionSchema = { }, // Retry - timeout: 60000, + timeoutMs: 60000, retry: { maxAttempts: 3, - delay: 2000 + delayMs: 2000 }, // Post-action behavior diff --git a/content/docs/core/report-schema.mdx b/content/docs/core/report-schema.mdx index 76ffa98a51..5a28e71da1 100644 --- a/content/docs/core/report-schema.mdx +++ b/content/docs/core/report-schema.mdx @@ -399,7 +399,7 @@ const comprehensiveReport: ReportComponentSchema = { showExportButtons: true, showPrintButton: true, showScheduleButton: true, - refreshInterval: 300 // Auto-refresh every 5 minutes + refreshIntervalSeconds: 300 // Auto-refresh every 5 minutes }; ``` diff --git a/content/docs/plugins/plugin-chatbot.mdx b/content/docs/plugins/plugin-chatbot.mdx index b2dc8e7b80..db3e69e386 100644 --- a/content/docs/plugins/plugin-chatbot.mdx +++ b/content/docs/plugins/plugin-chatbot.mdx @@ -98,7 +98,7 @@ const schema: ChatbotSchema = { maxHeight?: string, autoResponse?: boolean, autoResponseText?: string, - autoResponseDelay?: number, + autoResponseDelayMs?: number, onSend?: (content: string, messages: ObjectChatMessage[]) => void, className?: string, // AI / service-ai integration fields @@ -179,7 +179,7 @@ to apply. They are documented in their own table after this one, under | `maxHeight` | string | `'500px'` | **`chatbot` and `chatbot-enhanced` only** (declared on `ChatbotSchema` and `ChatbotEnhancedSchema`; `ChatbotFloatingSchema` does not declare it). Maximum height of the chat message container, as a CSS length. `chatbot-floating` does not read it: its panel is sized by `floatingConfig.panelHeight` (a **number** of pixels, default `520`), and the panel pins its inner chat to `maxHeight: '100%'` so it fills that panel - a `maxHeight` authored on a floating node would be overridden even if it were forwarded. Size a floating chatbot with `floatingConfig.panelHeight` instead | | `autoResponse` | boolean | `false` | Enable auto-response (demo mode, ignored when `api` is set) | | `autoResponseText` | string | - | Text for auto-response | -| `autoResponseDelay` | number | `1000` | Delay before auto-response (ms) | +| `autoResponseDelayMs` | number | `1000` | Delay before auto-response, in milliseconds (renamed from `autoResponseDelay`, which is now refused with a message naming this key) | | `onSend` | function | - | Callback when message is sent | | `className` | string | `''` | Additional Tailwind CSS classes | | `api` | string | - | Backend SSE endpoint (e.g., `/api/v1/ai/chat`). Enables AI streaming mode | @@ -329,7 +329,7 @@ const schema: ChatbotSchema = { messages: [], // seed with your own ChatMessage values autoResponse: true, autoResponseText: 'Thanks!', - autoResponseDelay: 1000, + autoResponseDelayMs: 1000, }; ``` @@ -554,7 +554,7 @@ const salesBot: ChatbotSchema = { userAvatarFallback: 'You', autoResponse: true, autoResponseText: 'Great choice! Let me show you some options...', - autoResponseDelay: 1200, + autoResponseDelayMs: 1200, maxHeight: '500px', className: 'border-2 border-primary rounded-xl' }; diff --git a/examples/schema-catalog/src/schemas/components-feedback-toast/success-toast.json b/examples/schema-catalog/src/schemas/components-feedback-toast/success-toast.json index 9309c6a395..56383f76fb 100644 --- a/examples/schema-catalog/src/schemas/components-feedback-toast/success-toast.json +++ b/examples/schema-catalog/src/schemas/components-feedback-toast/success-toast.json @@ -3,5 +3,5 @@ "variant": "success", "title": "Saved Successfully", "description": "Your changes have been saved.", - "duration": 3000 + "durationMs": 3000 } diff --git a/examples/schema-catalog/src/schemas/plugin-chatbot/basic-chatbot.json b/examples/schema-catalog/src/schemas/plugin-chatbot/basic-chatbot.json index 505b727c49..78df0d4dd7 100644 --- a/examples/schema-catalog/src/schemas/plugin-chatbot/basic-chatbot.json +++ b/examples/schema-catalog/src/schemas/plugin-chatbot/basic-chatbot.json @@ -11,6 +11,6 @@ "showTimestamp": false, "autoResponse": true, "autoResponseText": "Thank you for your message! This is an automated response.", - "autoResponseDelay": 1000, + "autoResponseDelayMs": 1000, "maxHeight": "400px" } diff --git a/examples/schema-catalog/src/schemas/plugin-chatbot/customer-support-chat.json b/examples/schema-catalog/src/schemas/plugin-chatbot/customer-support-chat.json index 29021302c3..e125c9511f 100644 --- a/examples/schema-catalog/src/schemas/plugin-chatbot/customer-support-chat.json +++ b/examples/schema-catalog/src/schemas/plugin-chatbot/customer-support-chat.json @@ -30,7 +30,7 @@ "assistantAvatarFallback": "SA", "showTimestamp": true, "autoResponse": true, - "autoResponseDelay": 1500, + "autoResponseDelayMs": 1500, "autoResponseText": "Let me check that for you...", "maxHeight": "500px" } diff --git a/packages/components/src/renderers/feedback/toast.tsx b/packages/components/src/renderers/feedback/toast.tsx index 0faa7aa3ce..8700271413 100644 --- a/packages/components/src/renderers/feedback/toast.tsx +++ b/packages/components/src/renderers/feedback/toast.tsx @@ -22,7 +22,7 @@ ComponentRegistry.register('toast', toastFn(schema.title || 'Notification', { description: schema.description, - duration: schema.duration, + duration: schema.durationMs, }); }; @@ -42,7 +42,7 @@ ComponentRegistry.register('toast', name: 'variant', type: 'enum', enum: ['default', 'success', 'warning', 'error', 'info'] }, - { name: 'duration', type: 'number' }, + { name: 'durationMs', type: 'number' }, { name: 'buttonLabel', type: 'string' }, { name: 'buttonVariant', @@ -57,7 +57,7 @@ ComponentRegistry.register('toast', title: 'Notification', buttonLabel: 'Show Toast', variant: 'default', - duration: 5000 + durationMs: 5000 } } ); diff --git a/packages/components/src/renderers/overlay/hover-card.tsx b/packages/components/src/renderers/overlay/hover-card.tsx index 0132ba7e2c..10219696fc 100644 --- a/packages/components/src/renderers/overlay/hover-card.tsx +++ b/packages/components/src/renderers/overlay/hover-card.tsx @@ -17,7 +17,7 @@ import { renderChildren, renderTriggerSlot } from '../../lib/utils'; ComponentRegistry.register('hover-card', ({ schema, className, ...props }: { schema: HoverCardSchema; className?: string; [key: string]: any }) => ( - + {renderTriggerSlot(HoverCardTrigger, schema.trigger)} {renderChildren(schema.content)} @@ -28,8 +28,8 @@ ComponentRegistry.register('hover-card', namespace: 'ui', label: 'Hover Card', inputs: [ - { name: 'openDelay', type: 'number' }, - { name: 'closeDelay', type: 'number' }, + { name: 'openDelayMs', type: 'number' }, + { name: 'closeDelayMs', type: 'number' }, { name: 'side', type: 'enum', enum: ['top', 'right', 'bottom', 'left'] }, { name: 'align', type: 'enum', enum: ['start', 'center', 'end'] }, { diff --git a/packages/components/src/renderers/overlay/tooltip.tsx b/packages/components/src/renderers/overlay/tooltip.tsx index 79283a2b9b..1f9cbec8c4 100644 --- a/packages/components/src/renderers/overlay/tooltip.tsx +++ b/packages/components/src/renderers/overlay/tooltip.tsx @@ -22,7 +22,7 @@ import { renderChildren, renderTriggerSlot } from '../../lib/utils'; ComponentRegistry.register('tooltip', ({ schema, className, ...props }: { schema: TooltipSchema; className?: string; [key: string]: any }) => ( - + {renderTriggerSlot(TooltipTrigger, schema.trigger)} @@ -35,7 +35,7 @@ ComponentRegistry.register('tooltip', namespace: 'ui', label: 'Tooltip', inputs: [ - { name: 'delayDuration', type: 'number' }, + { name: 'delayDurationMs', type: 'number' }, { name: 'side', type: 'enum', enum: ['top', 'right', 'bottom', 'left'] }, { name: 'align', type: 'enum', enum: ['start', 'center', 'end'] }, { @@ -58,7 +58,7 @@ ComponentRegistry.register('tooltip', defaultProps: { trigger: [{ type: 'button', label: 'Hover me', variant: 'outline' }], content: 'Tooltip content', - delayDuration: 700, + delayDurationMs: 700, side: 'top' } } diff --git a/packages/plugin-chatbot/src/__tests__/renderer.floating-spread-fence-7708.test.tsx b/packages/plugin-chatbot/src/__tests__/renderer.floating-spread-fence-7708.test.tsx index ad933f5472..a0306a2ee3 100644 --- a/packages/plugin-chatbot/src/__tests__/renderer.floating-spread-fence-7708.test.tsx +++ b/packages/plugin-chatbot/src/__tests__/renderer.floating-spread-fence-7708.test.tsx @@ -108,7 +108,7 @@ describe('chatbot-floating: a sent message renders on the panel (fixed, objectui messages: [{ id: 'seed', role: 'assistant', content: 'seed-message-marker' }], autoResponse: true, autoResponseText: 'auto-reply-marker', - autoResponseDelay: 0, + autoResponseDelayMs: 0, }); // Before the fix: the raw `{...props}` spread, LAST, put the AUTHORED diff --git a/packages/plugin-chatbot/src/renderer.tsx b/packages/plugin-chatbot/src/renderer.tsx index 5707a5d860..3ac8b9bb6b 100644 --- a/packages/plugin-chatbot/src/renderer.tsx +++ b/packages/plugin-chatbot/src/renderer.tsx @@ -29,7 +29,7 @@ import { toRuntimeMessages } from './chatMessageAdapter'; * * **Legacy Mode** (when `api` is not set): * - Local auto-response for demo/playground use - * - Schema fields: autoResponse, autoResponseText, autoResponseDelay + * - Schema fields: autoResponse, autoResponseText, autoResponseDelayMs * * Both modes support the `onSend` callback: * - Signature: `onSend(content: string, messages: ObjectChatMessage[]): void` @@ -93,7 +93,7 @@ ComponentRegistry.register('chatbot', showTimestamp: schema.showTimestamp, autoResponse: schema.autoResponse, autoResponseText: schema.autoResponseText, - autoResponseDelay: schema.autoResponseDelay, + autoResponseDelay: schema.autoResponseDelayMs, onSend: schema.onSend, }); @@ -214,7 +214,7 @@ ComponentRegistry.register('chatbot', name: 'autoResponseText', type: 'string' }, { - name: 'autoResponseDelay', + name: 'autoResponseDelayMs', type: 'number' }, { name: 'className', @@ -236,7 +236,7 @@ ComponentRegistry.register('chatbot', maxHeight: '500px', autoResponse: true, autoResponseText: 'Thank you for your message! This is an automated response.', - autoResponseDelay: 1000, + autoResponseDelayMs: 1000, className: 'w-full max-w-2xl' } } @@ -281,7 +281,7 @@ ComponentRegistry.register('chatbot-enhanced', showTimestamp: schema.showTimestamp, autoResponse: schema.autoResponse, autoResponseText: schema.autoResponseText, - autoResponseDelay: schema.autoResponseDelay, + autoResponseDelay: schema.autoResponseDelayMs, onSend: schema.onSend, }); @@ -352,7 +352,7 @@ ComponentRegistry.register('chatbot-enhanced', { name: 'streamingEnabled', type: 'boolean' }, { name: 'autoResponse', type: 'boolean' }, { name: 'autoResponseText', type: 'string' }, - { name: 'autoResponseDelay', type: 'number' }, + { name: 'autoResponseDelayMs', type: 'number' }, { name: 'className', type: 'string' } ], defaultProps: { @@ -373,7 +373,7 @@ ComponentRegistry.register('chatbot-enhanced', maxHeight: '500px', autoResponse: true, autoResponseText: 'Thank you for your message! This is an automated response.', - autoResponseDelay: 1000, + autoResponseDelayMs: 1000, className: 'w-full max-w-2xl' } } @@ -418,7 +418,7 @@ ComponentRegistry.register('chatbot-floating', showTimestamp: schema.showTimestamp, autoResponse: schema.autoResponse, autoResponseText: schema.autoResponseText, - autoResponseDelay: schema.autoResponseDelay, + autoResponseDelay: schema.autoResponseDelayMs, onSend: schema.onSend, }); @@ -504,7 +504,7 @@ ComponentRegistry.register('chatbot-floating', { name: 'streamingEnabled', type: 'boolean' }, { name: 'autoResponse', type: 'boolean' }, { name: 'autoResponseText', type: 'string' }, - { name: 'autoResponseDelay', type: 'number' }, + { name: 'autoResponseDelayMs', type: 'number' }, { name: 'className', type: 'string' }, ], defaultProps: { @@ -528,7 +528,7 @@ ComponentRegistry.register('chatbot-floating', enableFileUpload: false, autoResponse: true, autoResponseText: 'Thank you for your message! This is an automated response.', - autoResponseDelay: 1000, + autoResponseDelayMs: 1000, } } ); diff --git a/packages/plugin-report/src/ReportViewer.tsx b/packages/plugin-report/src/ReportViewer.tsx index 62f11debf3..7dc60a507b 100644 --- a/packages/plugin-report/src/ReportViewer.tsx +++ b/packages/plugin-report/src/ReportViewer.tsx @@ -241,7 +241,7 @@ export const ReportViewer: React.FC = ({ schema, onRefresh }) rule itself lives in the shared print sheet (`@object-ui/app-shell/styles.css`, objectui#4462). */}
- {report.refreshInterval && ( + {report.refreshIntervalSeconds && (