1- import React , { useEffect , useMemo } from "react" ;
1+ import React , { useCallback , useEffect , useMemo } from "react" ;
22import {
33 chatDbMessageSliceActions ,
44 CMessageNode ,
55 isUserCMessageNode ,
6- UserCMessageNode ,
76} from "../../features/ChatDB/chatDbMessagesSlice" ;
87import { UserInput } from "../ChatContent/UserInput" ;
98import { AssistantInput } from "../ChatContent/AssistantInput" ;
@@ -15,7 +14,7 @@ import {
1514 isPlainTextMessage ,
1615 isUserMessage ,
1716} from "../../services/refact" ;
18- import { IconButton } from "@radix-ui/themes" ;
17+ import { Box , Flex , IconButton } from "@radix-ui/themes" ;
1918import { ArrowLeftIcon , ArrowRightIcon } from "@radix-ui/react-icons" ;
2019import { PlainText } from "../ChatContent/PlainText" ;
2120import { ContextFiles } from "../ChatContent/ContextFiles" ;
@@ -87,74 +86,93 @@ export const MessageNode: React.FC<MessageNodeProps> = ({ children }) => {
8786 ) ;
8887} ;
8988
89+ function makeDummyNode ( lastMessage ?: CMessageNode ) : CMessageNode {
90+ return {
91+ message : {
92+ cmessage_usage_model : lastMessage ?. message . cmessage_usage_model ?? "" ,
93+ cmessage_usage_prompt : lastMessage ?. message . cmessage_usage_prompt ?? 0 ,
94+ cmessage_usage_completion :
95+ lastMessage ?. message . cmessage_usage_completion ?? 0 ,
96+ cmessage_belongs_to_cthread_id :
97+ lastMessage ?. message . cmessage_belongs_to_cthread_id ?? "" ,
98+ cmessage_num : lastMessage ?. message . cmessage_num ?? 0 ,
99+
100+ cmessage_alt : ( lastMessage ?. message . cmessage_alt ?? 0 ) + 1 ,
101+ cmessage_prev_alt : lastMessage ?. message . cmessage_alt ?? 0 ,
102+ cmessage_json : {
103+ role : "user" ,
104+ content : "dummy text about making a new message" ,
105+ } , // TODO: use a different type of message
106+ } ,
107+ children : [ ] ,
108+ } ;
109+ }
110+
90111const MessageNodeChildren : React . FC < { children : CMessageNode [ ] } > = ( {
91112 children,
92113} ) => {
93- const userMessages : UserCMessageNode [ ] = children . filter ( isUserCMessageNode ) ;
114+ const [ selectedNodeIndex , setSelectedNodeIndex ] = React . useState < number > ( 0 ) ;
94115
95- if ( userMessages . length === 0 ) {
96- return children . map ( ( node , index ) => {
97- const key = ` ${ node . message . cmessage_belongs_to_cthread_id } _ ${ node . message . cmessage_num } _ ${ node . message . cmessage_alt } _ ${ index } ` ;
98- return < MessageNode key = { key } > { node } </ MessageNode > ;
116+ const goBack = useCallback ( ( ) => {
117+ setSelectedNodeIndex ( ( prev ) => {
118+ if ( prev === 0 ) return prev ;
119+ return prev - 1 ;
99120 } ) ;
100- } else {
101- return < UserMessageNode > { userMessages } </ UserMessageNode > ;
102- }
103- } ;
121+ } , [ ] ) ;
104122
105- const UserMessageNode : React . FC < { children : UserCMessageNode [ ] } > = ( {
106- children,
107- } ) => {
108- // info about the node may need to be shared with the user input
109- const dispatch = useAppDispatch ( ) ;
110- const [ selectedNodeIndex , setSelectedNodeIndex ] = React . useState < number > ( 0 ) ;
111-
112- const selectedNode = children [ selectedNodeIndex ] ;
123+ const goForward = useCallback ( ( ) => {
124+ setSelectedNodeIndex ( ( prev ) => {
125+ if ( prev === children . length ) return prev ;
126+ return prev + 1 ;
127+ } ) ;
128+ } , [ children . length ] ) ;
113129
114- useEffect ( ( ) => {
115- if ( selectedNode . children . length === 0 ) {
116- const action = chatDbMessageSliceActions . setEnd ( {
117- number : selectedNode . message . cmessage_num ,
118- alt : selectedNode . message . cmessage_alt ,
119- } ) ;
120- dispatch ( action ) ;
130+ const canBranch = useMemo ( ( ) => {
131+ if ( children . length > 1 ) return true ;
132+ if ( selectedNodeIndex >= children . length && selectedNodeIndex > 0 ) {
133+ return true ;
121134 }
122- } , [
123- selectedNode . children . length ,
124- selectedNode . message . cmessage_num ,
125- selectedNode . message . cmessage_alt ,
126- dispatch ,
127- ] ) ;
135+ if (
136+ children [ selectedNodeIndex ] &&
137+ isUserCMessageNode ( children [ selectedNodeIndex ] )
138+ ) {
139+ return true ;
140+ }
141+ return false ;
142+ } , [ children , selectedNodeIndex ] ) ;
143+
144+ const nodeToRender = useMemo ( ( ) => {
145+ return (
146+ children [ selectedNodeIndex ] ??
147+ makeDummyNode ( children [ children . length - 1 ] )
148+ ) ;
149+ } , [ children , selectedNodeIndex ] ) ;
150+
151+ if ( ! canBranch ) {
152+ return < MessageNode > { children [ selectedNodeIndex ] } </ MessageNode > ;
153+ }
154+
128155 return (
129- < >
130- < IconButton
131- variant = "outline"
132- size = "1"
133- disabled = { selectedNodeIndex === 0 }
134- onClick = { ( ) =>
135- setSelectedNodeIndex ( ( prev ) => {
136- if ( prev === 0 ) return prev ;
137- return prev - 1 ;
138- } )
139- }
140- >
141- < ArrowLeftIcon />
142- </ IconButton >
143- < IconButton
144- variant = "outline"
145- size = "1"
146- disabled = { selectedNodeIndex === children . length - 1 }
147- onClick = { ( ) => {
148- setSelectedNodeIndex ( ( prev ) => {
149- if ( prev === children . length - 1 ) return prev ;
150- return prev + 1 ;
151- } ) ;
152- } }
153- >
154- < ArrowRightIcon />
155- </ IconButton >
156- < UserInput > { selectedNode . message . cmessage_json . content } </ UserInput >
157- < MessageNodeChildren > { selectedNode . children } </ MessageNodeChildren >
158- </ >
156+ < Box >
157+ < Flex gap = "4" justify = "end" >
158+ < IconButton
159+ variant = "outline"
160+ size = "1"
161+ disabled = { selectedNodeIndex === 0 }
162+ onClick = { goBack }
163+ >
164+ < ArrowLeftIcon />
165+ </ IconButton >
166+ < IconButton
167+ variant = "outline"
168+ size = "1"
169+ disabled = { selectedNodeIndex === children . length }
170+ onClick = { goForward }
171+ >
172+ < ArrowRightIcon />
173+ </ IconButton >
174+ </ Flex >
175+ < MessageNode > { nodeToRender } </ MessageNode >
176+ </ Box >
159177 ) ;
160178} ;
0 commit comments