summaryrefslogtreecommitdiff
path: root/frontend/src/components
diff options
context:
space:
mode:
Diffstat (limited to 'frontend/src/components')
-rw-r--r--frontend/src/components/LeftSidebar.tsx43
-rw-r--r--frontend/src/components/Sidebar.tsx45
2 files changed, 69 insertions, 19 deletions
diff --git a/frontend/src/components/LeftSidebar.tsx b/frontend/src/components/LeftSidebar.tsx
index aff2df8..1df63fe 100644
--- a/frontend/src/components/LeftSidebar.tsx
+++ b/frontend/src/components/LeftSidebar.tsx
@@ -2,9 +2,10 @@ import React, { useEffect, useMemo, useRef, useState, useCallback } from 'react'
import { useReactFlow } from 'reactflow';
import {
Folder, FileText, Archive, ChevronLeft, ChevronRight, Trash2, MessageSquare,
- MoreVertical, Download, Upload, Plus, RefreshCw, Edit3, Loader2
+ MoreVertical, Download, Upload, Plus, RefreshCw, Edit3, Loader2, LogOut, User
} from 'lucide-react';
import useFlowStore, { type FSItem, type BlueprintDocument, type FileMeta } from '../store/flowStore';
+import { useAuthStore } from '../store/authStore';
interface LeftSidebarProps {
isOpen: boolean;
@@ -39,6 +40,7 @@ const LeftSidebar: React.FC<LeftSidebarProps> = ({ isOpen, onToggle }) => {
serializeBlueprint,
clearBlueprint
} = useFlowStore();
+ const { user, logout } = useAuthStore();
const { setViewport, getViewport } = useReactFlow();
const isDark = theme === 'dark';
const fileInputRef = useRef<HTMLInputElement | null>(null);
@@ -443,13 +445,38 @@ const LeftSidebar: React.FC<LeftSidebarProps> = ({ isOpen, onToggle }) => {
<div className={`p-3 border-b flex justify-between items-center ${
isDark ? 'border-gray-700 bg-gray-900' : 'border-gray-200 bg-gray-50'
}`}>
- <h2 className={`font-bold text-sm uppercase ${isDark ? 'text-gray-300' : 'text-gray-700'}`}>Workspace</h2>
- <button
- onClick={onToggle}
- className={`p-1 rounded ${isDark ? 'hover:bg-gray-700' : 'hover:bg-gray-200'}`}
- >
- <ChevronLeft size={16} className={isDark ? 'text-gray-400' : 'text-gray-500'} />
- </button>
+ <div className="flex items-center gap-2">
+ <h2 className={`font-bold text-sm uppercase ${isDark ? 'text-gray-300' : 'text-gray-700'}`}>Workspace</h2>
+ {user && (
+ <span className={`text-xs px-2 py-0.5 rounded-full ${
+ isDark ? 'bg-gray-700 text-gray-400' : 'bg-gray-200 text-gray-600'
+ }`}>
+ <User size={10} className="inline mr-1" />
+ {user.username}
+ </span>
+ )}
+ </div>
+ <div className="flex items-center gap-1">
+ {user && (
+ <button
+ onClick={logout}
+ className={`p-1 rounded transition-colors ${
+ isDark
+ ? 'hover:bg-red-900/50 text-gray-400 hover:text-red-400'
+ : 'hover:bg-red-50 text-gray-500 hover:text-red-500'
+ }`}
+ title="Logout"
+ >
+ <LogOut size={16} />
+ </button>
+ )}
+ <button
+ onClick={onToggle}
+ className={`p-1 rounded ${isDark ? 'hover:bg-gray-700' : 'hover:bg-gray-200'}`}
+ >
+ <ChevronLeft size={16} className={isDark ? 'text-gray-400' : 'text-gray-500'} />
+ </button>
+ </div>
</div>
{/* Tabs */}
diff --git a/frontend/src/components/Sidebar.tsx b/frontend/src/components/Sidebar.tsx
index a8dd82e..17050aa 100644
--- a/frontend/src/components/Sidebar.tsx
+++ b/frontend/src/components/Sidebar.tsx
@@ -1,9 +1,10 @@
import React, { useState, useEffect, useRef, useMemo } from 'react';
import { useReactFlow } from 'reactflow';
import useFlowStore from '../store/flowStore';
+import { useAuthStore } from '../store/authStore';
import type { NodeData, Trace, Message, MergedTrace, MergeStrategy, FileMeta } from '../store/flowStore';
import ReactMarkdown from 'react-markdown';
-import { Play, Settings, Info, Save, ChevronLeft, ChevronRight, Maximize2, Edit3, X, Check, FileText, MessageCircle, Send, GripVertical, GitMerge, Trash2, AlertCircle, Loader2, Navigation, Upload, Search, Link } from 'lucide-react';
+import { Play, Settings, Info, Save, ChevronLeft, ChevronRight, Maximize2, Edit3, X, Check, FileText, MessageCircle, Send, GripVertical, GitMerge, Trash2, AlertCircle, Loader2, Navigation, Upload, Search, Link, LogOut } from 'lucide-react';
interface SidebarProps {
isOpen: boolean;
@@ -19,6 +20,7 @@ const Sidebar: React.FC<SidebarProps> = ({ isOpen, onToggle, onInteract }) => {
files, uploadFile, refreshFiles, addFileScope, removeFileScope, currentBlueprintPath,
saveCurrentBlueprint
} = useFlowStore();
+ const { getAuthHeader, user, logout } = useAuthStore();
const { setCenter, getViewport } = useReactFlow();
const isDark = theme === 'dark';
const [activeTab, setActiveTab] = useState<'interact' | 'settings' | 'debug'>('interact');
@@ -295,7 +297,7 @@ const Sidebar: React.FC<SidebarProps> = ({ isOpen, onToggle, onInteract }) => {
try {
const response = await fetch('http://localhost:8000/api/run_node_stream', {
method: 'POST',
- headers: { 'Content-Type': 'application/json' },
+ headers: { 'Content-Type': 'application/json', ...getAuthHeader() },
body: JSON.stringify({
node_id: runningNodeId,
incoming_contexts: [{ messages: context }],
@@ -386,7 +388,7 @@ const Sidebar: React.FC<SidebarProps> = ({ isOpen, onToggle, onInteract }) => {
try {
const res = await fetch('http://localhost:8000/api/summarize', {
method: 'POST',
- headers: { 'Content-Type': 'application/json' },
+ headers: { 'Content-Type': 'application/json', ...getAuthHeader() },
body: JSON.stringify({
content: selectedNode.data.response,
model: summaryModel
@@ -412,7 +414,7 @@ const Sidebar: React.FC<SidebarProps> = ({ isOpen, onToggle, onInteract }) => {
try {
const res = await fetch('http://localhost:8000/api/generate_title', {
method: 'POST',
- headers: { 'Content-Type': 'application/json' },
+ headers: { 'Content-Type': 'application/json', ...getAuthHeader() },
body: JSON.stringify({ user_prompt: userPrompt, response })
});
@@ -489,7 +491,7 @@ const Sidebar: React.FC<SidebarProps> = ({ isOpen, onToggle, onInteract }) => {
const res = await fetch('http://localhost:8000/api/summarize', {
method: 'POST',
- headers: { 'Content-Type': 'application/json' },
+ headers: { 'Content-Type': 'application/json', ...getAuthHeader() },
body: JSON.stringify({
content,
model_name: 'gpt-5-nano',
@@ -1003,7 +1005,7 @@ const Sidebar: React.FC<SidebarProps> = ({ isOpen, onToggle, onInteract }) => {
// Call LLM API with current messages as context
const response = await fetch('http://localhost:8000/api/run_node_stream', {
method: 'POST',
- headers: { 'Content-Type': 'application/json' },
+ headers: { 'Content-Type': 'application/json', ...getAuthHeader() },
body: JSON.stringify({
node_id: 'quick_chat_temp',
incoming_contexts: [{ messages: messagesBeforeSend }],
@@ -1835,17 +1837,30 @@ const Sidebar: React.FC<SidebarProps> = ({ isOpen, onToggle, onInteract }) => {
{activeTab === 'settings' && (
<div className="space-y-4">
{/* Attachments Section */}
+ {(() => {
+ const isGemini = selectedNode.data.model.startsWith('gemini');
+ return (
<div className={`p-3 rounded border ${isDark ? 'bg-gray-800 border-gray-700' : 'bg-gray-50 border-gray-200'}`}>
<label className={`block text-xs font-bold uppercase tracking-wider mb-2 ${isDark ? 'text-gray-400' : 'text-gray-500'}`}>
Attached Files
</label>
+ {isGemini && (
+ <p className={`text-xs mb-2 ${isDark ? 'text-yellow-400' : 'text-yellow-600'}`}>
+ File attachments are not supported for Gemini models.
+ </p>
+ )}
+
<div className="flex gap-2 mb-3">
<button
onClick={() => settingsUploadRef.current?.click()}
+ disabled={isGemini}
className={`flex-1 flex items-center justify-center gap-1.5 py-1.5 px-3 rounded text-xs font-medium transition-colors ${
- isDark ? 'bg-blue-600 hover:bg-blue-700 text-white' : 'bg-blue-600 hover:bg-blue-700 text-white'
+ isGemini
+ ? 'opacity-50 cursor-not-allowed bg-gray-400 text-gray-200'
+ : isDark ? 'bg-blue-600 hover:bg-blue-700 text-white' : 'bg-blue-600 hover:bg-blue-700 text-white'
}`}
+ title={isGemini ? 'Not supported for Gemini models' : 'Upload & Attach'}
>
<Upload size={14} />
Upload & Attach
@@ -1862,11 +1877,15 @@ const Sidebar: React.FC<SidebarProps> = ({ isOpen, onToggle, onInteract }) => {
refreshFiles();
setShowAttachModal(true);
}}
+ disabled={isGemini}
className={`flex-1 flex items-center justify-center gap-1.5 py-1.5 px-3 rounded text-xs font-medium border transition-colors ${
- isDark
- ? 'border-gray-600 hover:bg-gray-700 text-gray-200'
- : 'border-gray-300 hover:bg-gray-100 text-gray-700'
+ isGemini
+ ? 'opacity-50 cursor-not-allowed border-gray-400 text-gray-400'
+ : isDark
+ ? 'border-gray-600 hover:bg-gray-700 text-gray-200'
+ : 'border-gray-300 hover:bg-gray-100 text-gray-700'
}`}
+ title={isGemini ? 'Not supported for Gemini models' : 'Attach Existing File'}
>
<Link size={14} />
Attach Existing
@@ -1908,6 +1927,8 @@ const Sidebar: React.FC<SidebarProps> = ({ isOpen, onToggle, onInteract }) => {
</div>
)}
</div>
+ );
+ })()}
<div>
<label className={`block text-sm font-medium mb-1 ${isDark ? 'text-gray-300' : 'text-gray-700'}`}>Merge Strategy</label>
@@ -2562,7 +2583,8 @@ const Sidebar: React.FC<SidebarProps> = ({ isOpen, onToggle, onInteract }) => {
</label>
)}
- {/* File Attachment Buttons */}
+ {/* File Attachment Buttons - Hidden for Gemini */}
+ {!quickChatModel.startsWith('gemini') && (
<div className="flex items-center gap-1 ml-auto">
<button
onClick={() => quickChatUploadRef.current?.click()}
@@ -2603,6 +2625,7 @@ const Sidebar: React.FC<SidebarProps> = ({ isOpen, onToggle, onInteract }) => {
onChange={handleQuickChatUpload}
/>
</div>
+ )}
</div>
{/* Input Area */}