11import { useDispatch , useSelector } from "react-redux" ;
22import React from "react" ;
33import posthog from "posthog-js" ;
4+ import { useParams } from "react-router" ;
45import { convertImageToBase64 } from "#/utils/convert-image-to-base-64" ;
6+ import { TrajectoryActions } from "../trajectory/trajectory-actions" ;
57import { createChatMessage } from "#/services/chat-service" ;
6- import { InteractiveChatBox } from "./interactive-chat-box-okteto " ;
8+ import { InteractiveChatBox } from "./interactive-chat-box" ;
79import { addUserMessage } from "#/state/chat-slice" ;
810import { RootState } from "#/store" ;
911import { AgentState } from "#/types/agent-state" ;
@@ -14,15 +16,15 @@ import { useWsClient } from "#/context/ws-client-provider";
1416import { Messages } from "./messages" ;
1517import { ChatSuggestionsOkteto } from "./chat-suggestions-okteto" ;
1618import { ActionSuggestions } from "./action-suggestions" ;
19+
1720import { ScrollToBottomButton } from "#/components/shared/buttons/scroll-to-bottom-button" ;
1821import { LoadingSpinner } from "#/components/shared/loading-spinner" ;
22+ import { useGetTrajectory } from "#/hooks/mutation/use-get-trajectory" ;
23+ import { downloadTrajectory } from "#/utils/download-trajectory" ;
24+ import { displayErrorToast } from "#/utils/custom-toast-handlers" ;
1925
20- function getEntryPoint (
21- hasRepository : boolean | null ,
22- hasImportedProjectZip : boolean | null ,
23- ) : string {
26+ function getEntryPoint ( hasRepository : boolean | null ) : string {
2427 if ( hasRepository ) return "github" ;
25- if ( hasImportedProjectZip ) return "zip" ;
2628 return "direct" ;
2729}
2830
@@ -35,20 +37,23 @@ export function ChatInterfaceOkteto() {
3537
3638 const { messages } = useSelector ( ( state : RootState ) => state . chat ) ;
3739 const { curAgentState } = useSelector ( ( state : RootState ) => state . agent ) ;
40+
41+ const [ , setFeedbackPolarity ] = React . useState < "positive" | "negative" > (
42+ "positive" ,
43+ ) ;
44+ const [ , setFeedbackModalIsOpen ] = React . useState ( false ) ;
3845 const [ messageToSend , setMessageToSend ] = React . useState < string | null > ( null ) ;
39- const { selectedRepository, importedProjectZip } = useSelector (
46+ const { selectedRepository } = useSelector (
4047 ( state : RootState ) => state . initialQuery ,
4148 ) ;
49+ const params = useParams ( ) ;
50+ const { mutate : getTrajectory } = useGetTrajectory ( ) ;
4251
4352 const handleSendMessage = async ( content : string , files : File [ ] ) => {
4453 if ( messages . length === 0 ) {
4554 posthog . capture ( "initial_query_submitted" , {
46- entry_point : getEntryPoint (
47- selectedRepository !== null ,
48- importedProjectZip !== null ,
49- ) ,
55+ entry_point : getEntryPoint ( selectedRepository !== null ) ,
5056 query_character_length : content . length ,
51- uploaded_zip_size : importedProjectZip ?. length ,
5257 } ) ;
5358 } else {
5459 posthog . capture ( "user_message_sent" , {
@@ -71,6 +76,32 @@ export function ChatInterfaceOkteto() {
7176 send ( generateAgentStateChangeEvent ( AgentState . STOPPED ) ) ;
7277 } ;
7378
79+ const onClickShareFeedbackActionButton = async (
80+ polarity : "positive" | "negative" ,
81+ ) => {
82+ setFeedbackModalIsOpen ( true ) ;
83+ setFeedbackPolarity ( polarity ) ;
84+ } ;
85+
86+ const onClickExportTrajectoryButton = ( ) => {
87+ if ( ! params . conversationId ) {
88+ displayErrorToast ( "ConversationId unknown, cannot download trajectory" ) ;
89+ return ;
90+ }
91+
92+ getTrajectory ( params . conversationId , {
93+ onSuccess : async ( data ) => {
94+ await downloadTrajectory (
95+ params . conversationId ?? "unknown" ,
96+ data . trajectory ,
97+ ) ;
98+ } ,
99+ onError : ( error ) => {
100+ displayErrorToast ( error . message ) ;
101+ } ,
102+ } ) ;
103+ } ;
104+
74105 const isWaitingForUserInput =
75106 curAgentState === AgentState . AWAITING_USER_INPUT ||
76107 curAgentState === AgentState . FINISHED ;
@@ -112,6 +143,16 @@ export function ChatInterfaceOkteto() {
112143
113144 < div className = "flex flex-col gap-[6px] px-4 pb-4" >
114145 < div className = "flex justify-between relative" >
146+ < TrajectoryActions
147+ onPositiveFeedback = { ( ) =>
148+ onClickShareFeedbackActionButton ( "positive" )
149+ }
150+ onNegativeFeedback = { ( ) =>
151+ onClickShareFeedbackActionButton ( "negative" )
152+ }
153+ onExportTrajectory = { ( ) => onClickExportTrajectoryButton ( ) }
154+ />
155+
115156 < div className = "absolute left-1/2 transform -translate-x-1/2 bottom-0" >
116157 { curAgentState === AgentState . RUNNING && < TypingIndicator /> }
117158 </ div >
0 commit comments