From 9e0435dee4a4c99aecafb59c1ea36b19a245cca5 Mon Sep 17 00:00:00 2001 From: Eileen Li Date: Thu, 12 Jun 2025 10:07:45 -0700 Subject: [PATCH 1/2] fix: change ws to an optional field in form and question --- .../dynamicForm/dynamicForm.stories.tsx | 28 ++++++++++++++++++ src/components/dynamicForm/uniformsForm.tsx | 4 +-- .../promptBuilder/promptBuilder.stories.tsx | 2 +- src/components/question/question.stories.tsx | 15 ++++++++-- src/components/question/question.tsx | 6 ++-- src/components/sharedDescription.ts | 12 ++++++-- src/components/types.ts | 29 +++++++++++++++---- 7 files changed, 79 insertions(+), 17 deletions(-) diff --git a/src/components/dynamicForm/dynamicForm.stories.tsx b/src/components/dynamicForm/dynamicForm.stories.tsx index 74c40be1..a771a6dc 100644 --- a/src/components/dynamicForm/dynamicForm.stories.tsx +++ b/src/components/dynamicForm/dynamicForm.stories.tsx @@ -1,3 +1,4 @@ +import { optionalWsDescription } from '../sharedDescription' import UniformsForm from './uniformsForm' export default { @@ -7,6 +8,9 @@ export default { parameters: { layout: 'centered', }, + argTypes: { + ws: optionalWsDescription, + }, } export const Default = { @@ -23,6 +27,7 @@ export const Default = { }, required: ['street', 'zip', 'state'], }, + ws: { send: () => {} }, }, } @@ -42,5 +47,28 @@ export const Meeting = { sunday: { type: 'boolean' }, }, }, + ws: { send: () => {} }, + }, +} + +export const ReadOnly = { + args: { + title: 'Choose the days', + schema: { + title: 'Meeting Days', + type: 'object', + properties: { + monday: { type: 'boolean' }, + tuesday: { type: 'boolean' }, + wednesday: { type: 'boolean' }, + thursday: { type: 'boolean' }, + friday: { type: 'boolean' }, + saturday: { type: 'boolean' }, + sunday: { type: 'boolean' }, + }, + }, + data: { + thursday: true, + }, }, } diff --git a/src/components/dynamicForm/uniformsForm.tsx b/src/components/dynamicForm/uniformsForm.tsx index 1db034d4..053eb1c9 100644 --- a/src/components/dynamicForm/uniformsForm.tsx +++ b/src/components/dynamicForm/uniformsForm.tsx @@ -62,7 +62,7 @@ export default function UniformsForm(props: DynamicFormProps) { data: { data: model, inReplyTo: props.messageId }, } setData(model) - props.ws.send(formattedMessage) + props.ws?.send(formattedMessage) } return ( @@ -73,7 +73,7 @@ export default function UniformsForm(props: DynamicFormProps) { schema={bridge} onSubmit={(model) => handleSubmit(model)} model={data} - disabled={!!data} + disabled={!!data || !props.ws} /> ) diff --git a/src/components/promptBuilder/promptBuilder.stories.tsx b/src/components/promptBuilder/promptBuilder.stories.tsx index eb2e1c24..f5a73de6 100644 --- a/src/components/promptBuilder/promptBuilder.stories.tsx +++ b/src/components/promptBuilder/promptBuilder.stories.tsx @@ -175,7 +175,7 @@ function CustomTextInput(props: Omit) { inReplyTo: props.messageId, } - props.ws.send(formattedMessage) + props.ws?.send(formattedMessage) setIsSubmitted(true) } diff --git a/src/components/question/question.stories.tsx b/src/components/question/question.stories.tsx index a03c15d9..5f1eecf7 100644 --- a/src/components/question/question.stories.tsx +++ b/src/components/question/question.stories.tsx @@ -4,7 +4,7 @@ import React, { useState } from 'react' import Icon from '../icon/icon' import MessageCanvas from '../messageCanvas/messageCanvas' -import { senderDescription, wsDescription } from '../sharedDescription' +import { optionalWsDescription, senderDescription } from '../sharedDescription' import Text from '../text/text' import type { Message } from '../types' import Question from './question' @@ -28,7 +28,7 @@ const meta: Meta> = { } meta.argTypes = { - ws: wsDescription, + ws: optionalWsDescription, sender: senderDescription, } @@ -128,3 +128,14 @@ export const InMessageSpace = { }, ], } + +export const ReadOnly = { + args: { + sender: agent, + conversationId: '2', + messageId: '1', + title: 'What do you think?', + description: 'Choose either of the options below.', + options, + }, +} diff --git a/src/components/question/question.tsx b/src/components/question/question.tsx index a5010acf..e9d6e28c 100644 --- a/src/components/question/question.tsx +++ b/src/components/question/question.tsx @@ -43,7 +43,7 @@ export default function Question(props: QuestionProps) { inReplyTo: props.messageId, } - props.ws.send(formattedMessage) + props.ws?.send(formattedMessage) } const buttonList = props.options.map((option, index) => { @@ -61,8 +61,8 @@ export default function Question(props: QuestionProps) { size="small" sx={selectedOption === option ? selectedStyles : {}} className="rustic-option" - disabled={!!selectedOption} - aria-disabled={!!selectedOption} + disabled={!!selectedOption || !props.ws} + aria-disabled={!!selectedOption || !props.ws} label={option} > ) diff --git a/src/components/sharedDescription.ts b/src/components/sharedDescription.ts index 3d126eb8..d43c83fb 100644 --- a/src/components/sharedDescription.ts +++ b/src/components/sharedDescription.ts @@ -27,9 +27,9 @@ export const senderDescription: InputType = { }, } -export const wsDescription: InputType = { +export const optionalWsDescription: InputType = { description: - 'WebSocket connection to send and receive messages to and from a backend. The onReceive prop will override the default handler once it is set. If you need to use the WebSocket for purposes other than chat, you will need to create a separate WebSocket connection.', + 'WebSocket connection to send and receive messages to and from a backend. This value will be set automatically if the component is rendered with `ElementRenderer` or `MessageSpace`. If not provided, the component may not be able to send or receive messages.', type: { name: 'object', value: { @@ -38,7 +38,6 @@ export const wsDescription: InputType = { reconnect: { name: 'function', required: true }, onReceive: { name: 'function', required: false }, }, - required: true, }, table: { type: { @@ -53,6 +52,13 @@ export const wsDescription: InputType = { }, } +export const wsDescription: InputType = { + ...optionalWsDescription, + description: + 'WebSocket connection to send and receive messages to and from a backend. The onReceive prop will override the default handler once it is set. If you need to use the WebSocket for purposes other than chat, you will need to create a separate WebSocket connection.', + required: true, +} + export const participantDetail = 'Each Participant has the following fields:\n' + ' id: String representing the unique identifier for a participant\n' + diff --git a/src/components/types.ts b/src/components/types.ts index 78e4243c..a6d6c496 100644 --- a/src/components/types.ts +++ b/src/components/types.ts @@ -362,9 +362,9 @@ export type MultimodalInputProps = TextInputProps & | 'errorMessagesContainer' > -export interface ConversationProps { - /** WebSocket connection to send and receive messages to and from a backend. This value will be set automatically if the component is rendered with `ElementRenderer` or `MessageSpace`. */ - ws: WebSocketClient +export interface ConversationBaseProps { + /** WebSocket connection to send and receive messages to and from a backend. This value will be set automatically if the component is rendered with `ElementRenderer` or `MessageSpace`. If not provided, the component may not be able to send or receive messages. */ + ws?: WebSocketClient /** Current user. This value will be set automatically if the component is rendered with `ElementRenderer` or `MessageSpace`. */ sender: Sender /** Id of the current conversation. This value will be set automatically if the component is rendered with `ElementRenderer` or `MessageSpace`. */ @@ -373,12 +373,25 @@ export interface ConversationProps { messageId: string } +export interface ConversationPropsWithOptionalWs extends ConversationBaseProps { + /** WebSocket connection to send and receive messages to and from a backend. This value will be set automatically if the component is rendered with `ElementRenderer` or `MessageSpace`. If not provided, the component will not be able to send or receive messages. */ + ws?: WebSocketClient +} + +export interface ConversationPropsWithMandatoryWs + extends ConversationBaseProps { + /** WebSocket connection to send and receive messages to and from a backend. This value will be set automatically if the component is rendered with `ElementRenderer` or `MessageSpace`. */ + ws: WebSocketClient +} + export interface QuestionFormat extends DataFormat { /** Array of options to choose from. */ options: (string | number)[] } -export interface QuestionProps extends QuestionFormat, ConversationProps {} +export interface QuestionProps + extends QuestionFormat, + ConversationPropsWithOptionalWs {} export interface PromptsFormat { /** A list of prompt strings for users to select from. These prompts will be displayed as interactive elements in the UI. */ @@ -386,7 +399,9 @@ export interface PromptsFormat { position?: 'inConversation' | 'hoverOverInput' } -export interface PromptsProps extends PromptsFormat, ConversationProps { +export interface PromptsProps + extends PromptsFormat, + ConversationPropsWithMandatoryWs { /** An optional className to apply to the prompts container. */ className?: string } @@ -446,7 +461,9 @@ export interface FormFormat extends DataFormat { data?: any } -export interface DynamicFormProps extends FormFormat, ConversationProps {} +export interface DynamicFormProps + extends FormFormat, + ConversationPropsWithOptionalWs {} interface ContentBase { type: 'text' | 'image_url' | 'input_audio' | 'file_url' From d3836f547c8e8b73b38407a9796c728744c9351c Mon Sep 17 00:00:00 2001 From: Eileen Li Date: Thu, 12 Jun 2025 10:32:15 -0700 Subject: [PATCH 2/2] docs: update description --- src/components/sharedDescription.ts | 2 +- src/components/types.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/sharedDescription.ts b/src/components/sharedDescription.ts index d43c83fb..e81c66b3 100644 --- a/src/components/sharedDescription.ts +++ b/src/components/sharedDescription.ts @@ -29,7 +29,7 @@ export const senderDescription: InputType = { export const optionalWsDescription: InputType = { description: - 'WebSocket connection to send and receive messages to and from a backend. This value will be set automatically if the component is rendered with `ElementRenderer` or `MessageSpace`. If not provided, the component may not be able to send or receive messages.', + 'WebSocket connection to send response messages to a backend. This value will be set automatically if the component is rendered with `ElementRenderer` or `MessageSpace`. If not provided, the component will not be interactive.', type: { name: 'object', value: { diff --git a/src/components/types.ts b/src/components/types.ts index a6d6c496..a3fa592b 100644 --- a/src/components/types.ts +++ b/src/components/types.ts @@ -374,7 +374,7 @@ export interface ConversationBaseProps { } export interface ConversationPropsWithOptionalWs extends ConversationBaseProps { - /** WebSocket connection to send and receive messages to and from a backend. This value will be set automatically if the component is rendered with `ElementRenderer` or `MessageSpace`. If not provided, the component will not be able to send or receive messages. */ + /** WebSocket connection to send response messages to a backend. This value will be set automatically if the component is rendered with `ElementRenderer` or `MessageSpace`. If not provided, the component will not be interactive. */ ws?: WebSocketClient }