fix chat UI covering canvas when closed + update to add sending graph data button with message
parent
b055d16199
commit
a42147d178
|
@ -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;
|
||||||
|
}
|
||||||
|
|
|
@ -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>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
Loading…
Reference in New Issue