Skip to content

fix: change ws to an optional field in form and question #368

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jun 12, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions src/components/dynamicForm/dynamicForm.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { optionalWsDescription } from '../sharedDescription'
import UniformsForm from './uniformsForm'

export default {
Expand All @@ -7,6 +8,9 @@ export default {
parameters: {
layout: 'centered',
},
argTypes: {
ws: optionalWsDescription,
},
}

export const Default = {
Expand All @@ -23,6 +27,7 @@ export const Default = {
},
required: ['street', 'zip', 'state'],
},
ws: { send: () => {} },
},
}

Expand All @@ -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,
},
},
}
4 changes: 2 additions & 2 deletions src/components/dynamicForm/uniformsForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
Expand All @@ -73,7 +73,7 @@ export default function UniformsForm(props: DynamicFormProps) {
schema={bridge}
onSubmit={(model) => handleSubmit(model)}
model={data}
disabled={!!data}
disabled={!!data || !props.ws}
/>
</Box>
)
Expand Down
2 changes: 1 addition & 1 deletion src/components/promptBuilder/promptBuilder.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ function CustomTextInput(props: Omit<QuestionProps, 'options'>) {
inReplyTo: props.messageId,
}

props.ws.send(formattedMessage)
props.ws?.send(formattedMessage)
setIsSubmitted(true)
}

Expand Down
15 changes: 13 additions & 2 deletions src/components/question/question.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand All @@ -28,7 +28,7 @@ const meta: Meta<React.ComponentProps<typeof Question>> = {
}

meta.argTypes = {
ws: wsDescription,
ws: optionalWsDescription,
sender: senderDescription,
}

Expand Down Expand Up @@ -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,
},
}
6 changes: 3 additions & 3 deletions src/components/question/question.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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) => {
Expand All @@ -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}
></Chip>
)
Expand Down
12 changes: 9 additions & 3 deletions src/components/sharedDescription.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 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: {
Expand All @@ -38,7 +38,6 @@ export const wsDescription: InputType = {
reconnect: { name: 'function', required: true },
onReceive: { name: 'function', required: false },
},
required: true,
},
table: {
type: {
Expand All @@ -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' +
Expand Down
29 changes: 23 additions & 6 deletions src/components/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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`. */
Expand All @@ -373,20 +373,35 @@ export interface ConversationProps {
messageId: string
}

export interface ConversationPropsWithOptionalWs extends ConversationBaseProps {
/** 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
}

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. */
prompts: string[]
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
}
Expand Down Expand Up @@ -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'
Expand Down