fix chat UI covering canvas when closed + update to add sending graph data button with message

pull/9266/head
Bentlybro 2025-01-17 12:50:31 +00:00
parent b055d16199
commit a42147d178
2 changed files with 270 additions and 120 deletions

View File

@ -1,103 +1,170 @@
.launcher-container {
display: flex;
flex-direction: column;
gap: 8px;
align-items: center;
}
.custom-launcher-button { .custom-launcher-button {
background-color: #8b5cf6 !important; background-color: #8b5cf6 !important;
border: none !important; border: none !important;
border-radius: 50% !important; border-radius: 50% !important;
color: white !important; color: white !important;
cursor: pointer !important; cursor: pointer !important;
height: 60px !important; height: 60px !important;
padding: 18px !important; padding: 18px !important;
position: fixed !important; position: fixed !important;
right: 35px !important; right: 35px !important;
bottom: 15px !important; bottom: 15px !important;
transition: all 0.2s ease-in-out !important; transition: all 0.2s ease-in-out !important;
width: 60px !important; width: 60px !important;
z-index: 999 !important; z-index: 999 !important;
} display: flex !important;
align-items: center !important;
.custom-launcher-button:hover { justify-content: center !important;
background-color: #7c3aed !important; }
transform: scale(1.1) !important;
}
.custom-launcher-button:hover {
.rcw-launcher { background-color: #7c3aed !important;
display: none !important; transform: scale(1.1) !important;
} }
.rcw-widget-container { .capture-graph-button {
height: 65vh !important; width: 40px;
margin-bottom: 50px !important; height: 40px;
border-radius: 10px !important; color: #fff;
max-width: 610px !important; background-color: #4b5563;
width: 100% !important; border-radius: 50%;
} display: flex;
align-items: center;
.rcw-conversation-container { justify-content: center;
border-radius: 10px !important; cursor: pointer;
background-color: white !important; transition: all 0.2s ease;
border: none !important; border: none;
} outline: none;
position: fixed !important;
.rcw-header { right: 35px !important;
background-color: #8b5cf6 !important; bottom: 100px !important;
border-radius: 10px 10px 0 0 !important; }
padding: 0px !important;
min-height: 0px !important; .capture-graph-button:hover {
} background-color: #374151;
transform: scale(1.05);
.rcw-messages-container { }
background-color: white !important;
padding: 12px 8px !important; .capture-graph-button:focus {
max-width: 100% !important; outline: 2px solid #60a5fa;
overflow-x: hidden !important; outline-offset: 2px;
font-size: 0.9rem !important; }
}
.capture-graph-button.active {
.rcw-message { background-color: #10b981;
padding: 4px 8px !important; box-shadow: 0 0 0 2px #fff, 0 0 0 4px #10b981;
width: auto !important; }
max-width: 100% !important;
display: flex !important; .capture-graph-button.active:hover {
flex-direction: column !important; background-color: #059669;
margin: 4px 0 !important; }
}
.rcw-launcher {
.rcw-message-text { display: none !important;
background-color: #f3f4f6 !important; }
color: #1f2937 !important;
border-radius: 8px !important; .rcw-widget-container {
padding: 8px !important; height: 65vh !important;
max-width: 100% !important; margin-bottom: 50px !important;
word-wrap: break-word !important; border-radius: 10px !important;
white-space: pre-wrap !important; max-width: 610px !important;
overflow-wrap: break-word !important; width: 100% !important;
line-height: 1.4 !important; }
overflow-x: auto !important;
margin: 0 !important; .rcw-conversation-container {
} border-radius: 10px !important;
background-color: white !important;
.rcw-message-text pre { border: none !important;
max-width: 100% !important; }
overflow-x: auto !important;
white-space: pre-wrap !important; .rcw-header {
word-wrap: break-word !important; background-color: #8b5cf6 !important;
margin: 8px 0 !important; border-radius: 10px 10px 0 0 !important;
} padding: 0px !important;
min-height: 0px !important;
.rcw-message-text code { }
word-wrap: break-word !important;
white-space: pre-wrap !important; .rcw-messages-container {
display: block !important; background-color: white !important;
width: 100% !important; padding: 12px 8px !important;
} max-width: 100% !important;
overflow-x: hidden !important;
.rcw-client .rcw-message-text { font-size: 0.9rem !important;
background-color: #8b5cf6 !important; }
color: white !important;
} .rcw-message {
padding: 4px 8px !important;
.rcw-sender { width: auto !important;
background-color: white !important; max-width: 100% !important;
padding: 10px !important; display: flex !important;
border-radius: 0 0 10px 10px !important; flex-direction: column !important;
border-top: 1px solid #e5e7eb !important; margin: 4px 0 !important;
} }
.rcw-message-text {
background-color: #f3f4f6 !important;
color: #1f2937 !important;
border-radius: 8px !important;
padding: 8px !important;
max-width: 100% !important;
word-wrap: break-word !important;
white-space: pre-wrap !important;
overflow-wrap: break-word !important;
line-height: 1.4 !important;
overflow-x: auto !important;
margin: 0 !important;
}
.rcw-message-text pre {
max-width: 100% !important;
overflow-x: auto !important;
white-space: pre-wrap !important;
word-wrap: break-word !important;
margin: 8px 0 !important;
}
.rcw-message-text code {
word-wrap: break-word !important;
white-space: pre-wrap !important;
display: block !important;
width: 100% !important;
}
.rcw-client .rcw-message-text {
background-color: #8b5cf6 !important;
color: white !important;
}
.rcw-sender {
background-color: white !important;
padding: 10px !important;
border-radius: 0 0 10px 10px !important;
border-top: 1px solid #e5e7eb !important;
}
.rcw-send {
display: none !important;
}
.rcw-widget-container.rcw-close-widget-container {
pointer-events: none !important;
}
.rcw-widget-container.rcw-close-widget-container .rcw-conversation-container,
.rcw-widget-container.rcw-close-widget-container .rcw-sender {
pointer-events: none !important;
visibility: hidden !important;
display: none !important;
}
.rcw-widget-container.rcw-close-widget-container .launcher-container {
pointer-events: all !important;
}

View File

@ -5,6 +5,10 @@ import { Widget, addResponseMessage, addLinkSnippet, deleteMessages } from 'reac
import 'react-chat-widget/lib/styles.css'; import 'react-chat-widget/lib/styles.css';
import './OttoChatWidget.css'; import './OttoChatWidget.css';
import useSupabase from '../hooks/useSupabase'; import useSupabase from '../hooks/useSupabase';
import useAgentGraph from '../hooks/useAgentGraph';
import { Node, Edge } from '@xyflow/react';
import { useSearchParams } from 'next/navigation';
import { useToast } from '@/components/ui/use-toast';
interface Document { interface Document {
url: string; url: string;
@ -22,19 +26,42 @@ interface Message {
response: string; response: string;
} }
interface GraphData {
nodes: {
id: string;
type: string;
position: { x: number; y: number };
data: any;
}[];
edges: {
id: string;
source: string;
target: string;
sourceHandle: string | null;
targetHandle: string | null;
data: any;
}[];
}
interface ChatPayload { interface ChatPayload {
query: string; query: string;
conversation_history: { query: string; response: string }[]; conversation_history: { query: string; response: string }[];
user_id: string; user_id: string;
message_id: string; message_id: string;
graph_data?: GraphData;
} }
const OttoChatWidget = () => { const OttoChatWidget = () => {
const [chatWindowOpen, setChatWindowOpen] = useState(false); const [chatWindowOpen, setChatWindowOpen] = useState(false);
const [messages, setMessages] = useState<Message[]>([]); const [messages, setMessages] = useState<Message[]>([]);
const [includeGraphData, setIncludeGraphData] = useState(false);
const welcomeMessageSent = useRef(false); const welcomeMessageSent = useRef(false);
const processingMessageId = useRef<number | null>(null); const processingMessageId = useRef<number | null>(null);
const { user } = useSupabase(); const { user } = useSupabase();
const searchParams = useSearchParams();
const flowID = searchParams.get('flowID');
const { nodes, edges } = useAgentGraph(flowID || undefined);
const { toast } = useToast();
useEffect(() => { useEffect(() => {
if (!welcomeMessageSent.current) { if (!welcomeMessageSent.current) {
@ -58,6 +85,26 @@ const OttoChatWidget = () => {
addResponseMessage('Processing your question...'); addResponseMessage('Processing your question...');
try { try {
const graphData: GraphData | undefined = (includeGraphData && nodes && edges) ? {
nodes: nodes.map(node => ({
id: node.id,
type: node.type || 'custom',
position: { x: node.position.x, y: node.position.y },
data: node.data
})),
edges: edges.map(edge => ({
id: edge.id,
source: edge.source,
target: edge.target,
sourceHandle: edge.sourceHandle ?? null,
targetHandle: edge.targetHandle ?? null,
data: edge.data || {}
}))
} : undefined;
// Reset the includeGraphData flag after using it
setIncludeGraphData(false);
const payload: ChatPayload = { const payload: ChatPayload = {
query: newMessage, query: newMessage,
conversation_history: messages.map(msg => ({ conversation_history: messages.map(msg => ({
@ -65,7 +112,8 @@ const OttoChatWidget = () => {
response: msg.response response: msg.response
})), })),
user_id: user?.id || 'anonymous', user_id: user?.id || 'anonymous',
message_id: messageId message_id: messageId,
graph_data: graphData
}; };
const response = await fetch('http://192.168.0.39:2344/ask', { const response = await fetch('http://192.168.0.39:2344/ask', {
@ -119,24 +167,59 @@ const OttoChatWidget = () => {
autofocus={true} autofocus={true}
emojis={true} emojis={true}
launcher={(handleToggle: () => void) => ( launcher={(handleToggle: () => void) => (
<button <div className="launcher-container">
onClick={handleToggle} <button
className="custom-launcher-button" onClick={handleToggle}
aria-label="Open chat widget" className="custom-launcher-button"
> aria-label="Open chat widget"
<svg
viewBox="0 0 24 24"
width="24"
height="24"
stroke="currentColor"
strokeWidth="2"
fill="none"
strokeLinecap="round"
strokeLinejoin="round"
> >
<path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z" /> <svg
</svg> viewBox="0 0 24 24"
</button> width="24"
height="24"
stroke="currentColor"
strokeWidth="2"
fill="none"
strokeLinecap="round"
strokeLinejoin="round"
>
<path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z" />
</svg>
</button>
{chatWindowOpen && nodes && edges && (
<button
onClick={() => {
setIncludeGraphData(prev => {
const newState = !prev;
toast({
title: newState
? "Graph data will be included with your next message"
: "Graph data will not be included with your next message",
duration: 2000,
});
return newState;
});
}}
className={`capture-graph-button ${includeGraphData ? 'active' : ''}`}
aria-label="Include graph data with next message"
>
<svg
viewBox="0 0 24 24"
width="20"
height="20"
stroke="currentColor"
strokeWidth="2"
fill="none"
strokeLinecap="round"
strokeLinejoin="round"
>
<rect x="3" y="3" width="18" height="18" rx="2" ry="2" />
<circle cx="8.5" cy="8.5" r="1.5" />
<polyline points="21 15 16 10 5 21" />
</svg>
</button>
)}
</div>
)} )}
/> />
); );