删除无用文件
This commit is contained in:
28
src/App.tsx
28
src/App.tsx
@@ -10,7 +10,6 @@ import { ProjectList } from "@/components/ProjectList";
|
|||||||
import { SessionList } from "@/components/SessionList";
|
import { SessionList } from "@/components/SessionList";
|
||||||
import { RunningClaudeSessions } from "@/components/RunningClaudeSessions";
|
import { RunningClaudeSessions } from "@/components/RunningClaudeSessions";
|
||||||
import { Topbar } from "@/components/Topbar";
|
import { Topbar } from "@/components/Topbar";
|
||||||
import { ClaudeFileEditor } from "@/components/ClaudeFileEditor";
|
|
||||||
import { CCAgents } from "@/components/CCAgents";
|
import { CCAgents } from "@/components/CCAgents";
|
||||||
import { NFOCredits } from "@/components/NFOCredits";
|
import { NFOCredits } from "@/components/NFOCredits";
|
||||||
import { ClaudeBinaryDialog } from "@/components/ClaudeBinaryDialog";
|
import { ClaudeBinaryDialog } from "@/components/ClaudeBinaryDialog";
|
||||||
@@ -37,7 +36,6 @@ const MCPManager = lazy(() => import('@/components/MCPManager').then(m => ({ def
|
|||||||
type View =
|
type View =
|
||||||
| "welcome"
|
| "welcome"
|
||||||
| "projects"
|
| "projects"
|
||||||
| "claude-file-editor"
|
|
||||||
| "settings"
|
| "settings"
|
||||||
| "cc-agents"
|
| "cc-agents"
|
||||||
| "create-agent"
|
| "create-agent"
|
||||||
@@ -70,7 +68,7 @@ function AppContent() {
|
|||||||
const [projects, setProjects] = useState<Project[]>([]);
|
const [projects, setProjects] = useState<Project[]>([]);
|
||||||
const [selectedProject, setSelectedProject] = useState<Project | null>(null);
|
const [selectedProject, setSelectedProject] = useState<Project | null>(null);
|
||||||
const [sessions, setSessions] = useState<Session[]>([]);
|
const [sessions, setSessions] = useState<Session[]>([]);
|
||||||
const [editingClaudeFile, setEditingClaudeFile] = useState<ClaudeMdFile | null>(null);
|
// Removed: project-level ClaudeFileEditor state
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
const [error, setError] = useState<string | null>(null);
|
const [error, setError] = useState<string | null>(null);
|
||||||
const [showNFO, setShowNFO] = useState(false);
|
const [showNFO, setShowNFO] = useState(false);
|
||||||
@@ -390,18 +388,7 @@ function AppContent() {
|
|||||||
/**
|
/**
|
||||||
* Handles editing a CLAUDE.md file from a project
|
* Handles editing a CLAUDE.md file from a project
|
||||||
*/
|
*/
|
||||||
const handleEditClaudeFile = (file: ClaudeMdFile) => {
|
// Removed project-level ClaudeFileEditor routes and handlers
|
||||||
setEditingClaudeFile(file);
|
|
||||||
handleViewChange("claude-file-editor");
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns from CLAUDE.md file editor to projects view
|
|
||||||
*/
|
|
||||||
const handleBackFromClaudeFileEditor = () => {
|
|
||||||
setEditingClaudeFile(null);
|
|
||||||
handleViewChange("projects");
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles view changes with navigation protection
|
* Handles view changes with navigation protection
|
||||||
@@ -533,7 +520,6 @@ function AppContent() {
|
|||||||
sessions={sessions}
|
sessions={sessions}
|
||||||
projectPath={selectedProject.path}
|
projectPath={selectedProject.path}
|
||||||
onBack={handleBack}
|
onBack={handleBack}
|
||||||
onEditClaudeFile={handleEditClaudeFile}
|
|
||||||
onSessionClick={(session) => {
|
onSessionClick={(session) => {
|
||||||
// Navigate to session detail view in tabs mode
|
// Navigate to session detail view in tabs mode
|
||||||
setView("tabs");
|
setView("tabs");
|
||||||
@@ -585,15 +571,7 @@ function AppContent() {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
case "claude-file-editor":
|
// Removed: claude-file-editor view
|
||||||
return editingClaudeFile ? (
|
|
||||||
<div className="h-full overflow-hidden">
|
|
||||||
<ClaudeFileEditor
|
|
||||||
file={editingClaudeFile}
|
|
||||||
onBack={handleBackFromClaudeFileEditor}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
) : null;
|
|
||||||
|
|
||||||
case "tabs":
|
case "tabs":
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -1,181 +0,0 @@
|
|||||||
import React, { useState, useEffect } from "react";
|
|
||||||
import MDEditor from "@uiw/react-md-editor";
|
|
||||||
import { motion } from "framer-motion";
|
|
||||||
import { ArrowLeft, Save, Loader2 } from "lucide-react";
|
|
||||||
import { Button } from "@/components/ui/button";
|
|
||||||
import { Toast, ToastContainer } from "@/components/ui/toast";
|
|
||||||
import { api, type ClaudeMdFile } from "@/lib/api";
|
|
||||||
import { cn } from "@/lib/utils";
|
|
||||||
import { useTranslation } from "@/hooks/useTranslation";
|
|
||||||
|
|
||||||
interface ClaudeFileEditorProps {
|
|
||||||
/**
|
|
||||||
* The CLAUDE.md file to edit
|
|
||||||
*/
|
|
||||||
file: ClaudeMdFile;
|
|
||||||
/**
|
|
||||||
* Callback to go back to the previous view
|
|
||||||
*/
|
|
||||||
onBack: () => void;
|
|
||||||
/**
|
|
||||||
* Optional className for styling
|
|
||||||
*/
|
|
||||||
className?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ClaudeFileEditor component for editing project-specific CLAUDE.md files
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
* <ClaudeFileEditor
|
|
||||||
* file={claudeMdFile}
|
|
||||||
* onBack={() => setEditingFile(null)}
|
|
||||||
* />
|
|
||||||
*/
|
|
||||||
export const ClaudeFileEditor: React.FC<ClaudeFileEditorProps> = ({
|
|
||||||
file,
|
|
||||||
onBack,
|
|
||||||
className,
|
|
||||||
}) => {
|
|
||||||
const { t } = useTranslation();
|
|
||||||
const [content, setContent] = useState<string>("");
|
|
||||||
const [originalContent, setOriginalContent] = useState<string>("");
|
|
||||||
const [loading, setLoading] = useState(true);
|
|
||||||
const [saving, setSaving] = useState(false);
|
|
||||||
const [error, setError] = useState<string | null>(null);
|
|
||||||
const [toast, setToast] = useState<{ message: string; type: "success" | "error" } | null>(null);
|
|
||||||
|
|
||||||
const hasChanges = content !== originalContent;
|
|
||||||
|
|
||||||
// Load the file content on mount
|
|
||||||
useEffect(() => {
|
|
||||||
loadFileContent();
|
|
||||||
}, [file.absolute_path]);
|
|
||||||
|
|
||||||
const loadFileContent = async () => {
|
|
||||||
try {
|
|
||||||
setLoading(true);
|
|
||||||
setError(null);
|
|
||||||
const fileContent = await api.readClaudeMdFile(file.absolute_path);
|
|
||||||
setContent(fileContent);
|
|
||||||
setOriginalContent(fileContent);
|
|
||||||
} catch (err) {
|
|
||||||
console.error("Failed to load file:", err);
|
|
||||||
setError(t('loadFileFailed'));
|
|
||||||
} finally {
|
|
||||||
setLoading(false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleSave = async () => {
|
|
||||||
try {
|
|
||||||
setSaving(true);
|
|
||||||
setError(null);
|
|
||||||
setToast(null);
|
|
||||||
await api.saveClaudeMdFile(file.absolute_path, content);
|
|
||||||
setOriginalContent(content);
|
|
||||||
setToast({ message: t('fileSavedSuccess'), type: "success" });
|
|
||||||
} catch (err) {
|
|
||||||
console.error("Failed to save file:", err);
|
|
||||||
setError(t('saveFileFailed'));
|
|
||||||
setToast({ message: t('saveFileFailed'), type: "error" });
|
|
||||||
} finally {
|
|
||||||
setSaving(false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleBack = () => {
|
|
||||||
if (hasChanges) {
|
|
||||||
const confirmLeave = window.confirm(
|
|
||||||
t('unsavedChangesConfirm')
|
|
||||||
);
|
|
||||||
if (!confirmLeave) return;
|
|
||||||
}
|
|
||||||
onBack();
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={cn("flex flex-col h-full bg-background", className)}>
|
|
||||||
<div className="w-full max-w-5xl mx-auto flex flex-col h-full">
|
|
||||||
{/* Header */}
|
|
||||||
<motion.div
|
|
||||||
initial={{ opacity: 0, y: -20 }}
|
|
||||||
animate={{ opacity: 1, y: 0 }}
|
|
||||||
transition={{ duration: 0.3 }}
|
|
||||||
className="flex items-center justify-between p-4 border-b border-border"
|
|
||||||
>
|
|
||||||
<div className="flex items-center space-x-3">
|
|
||||||
<Button
|
|
||||||
variant="ghost"
|
|
||||||
size="icon"
|
|
||||||
onClick={handleBack}
|
|
||||||
className="h-8 w-8"
|
|
||||||
>
|
|
||||||
<ArrowLeft className="h-4 w-4" />
|
|
||||||
</Button>
|
|
||||||
<div className="min-w-0 flex-1">
|
|
||||||
<h2 className="text-lg font-semibold truncate">{file.relative_path}</h2>
|
|
||||||
<p className="text-xs text-muted-foreground">
|
|
||||||
{t('editProjectSpecificPrompt')}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<Button
|
|
||||||
onClick={handleSave}
|
|
||||||
disabled={!hasChanges || saving}
|
|
||||||
size="sm"
|
|
||||||
>
|
|
||||||
{saving ? (
|
|
||||||
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
|
|
||||||
) : (
|
|
||||||
<Save className="mr-2 h-4 w-4" />
|
|
||||||
)}
|
|
||||||
{saving ? t('saving') : t('app.save')}
|
|
||||||
</Button>
|
|
||||||
</motion.div>
|
|
||||||
|
|
||||||
{/* Error display */}
|
|
||||||
{error && (
|
|
||||||
<motion.div
|
|
||||||
initial={{ opacity: 0 }}
|
|
||||||
animate={{ opacity: 1 }}
|
|
||||||
className="mx-4 mt-4 rounded-lg border border-destructive/50 bg-destructive/10 p-3 text-xs text-destructive"
|
|
||||||
>
|
|
||||||
{error}
|
|
||||||
</motion.div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* Editor */}
|
|
||||||
<div className="flex-1 p-4 overflow-hidden">
|
|
||||||
{loading ? (
|
|
||||||
<div className="flex items-center justify-center h-full">
|
|
||||||
<Loader2 className="h-6 w-6 animate-spin text-muted-foreground" />
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<div className="h-full rounded-lg border border-border overflow-hidden shadow-sm" data-color-mode="dark">
|
|
||||||
<MDEditor
|
|
||||||
value={content}
|
|
||||||
onChange={(val) => setContent(val || "")}
|
|
||||||
preview="edit"
|
|
||||||
height="100%"
|
|
||||||
visibleDragbar={false}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Toast Notification */}
|
|
||||||
<ToastContainer>
|
|
||||||
{toast && (
|
|
||||||
<Toast
|
|
||||||
message={toast.message}
|
|
||||||
type={toast.type}
|
|
||||||
onDismiss={() => setToast(null)}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</ToastContainer>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
@@ -146,12 +146,6 @@ const TabPanel: React.FC<TabPanelProps> = ({ tab, isActive }) => {
|
|||||||
initialProjectPath: session.project_path,
|
initialProjectPath: session.project_path,
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
onEditClaudeFile={(file: ClaudeMdFile) => {
|
|
||||||
// Open CLAUDE.md file in a new tab
|
|
||||||
window.dispatchEvent(new CustomEvent('open-claude-file', {
|
|
||||||
detail: { file }
|
|
||||||
}));
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
) : (
|
) : (
|
||||||
@@ -236,13 +230,7 @@ const TabPanel: React.FC<TabPanelProps> = ({ tab, isActive }) => {
|
|||||||
|
|
||||||
// Removed 'claude-md' tab type
|
// Removed 'claude-md' tab type
|
||||||
|
|
||||||
case 'claude-file':
|
// Removed 'claude-file' tab type
|
||||||
if (!tab.claudeFileId) {
|
|
||||||
return <div className="p-4">{t('messages.noClaudeFileIdSpecified')}</div>;
|
|
||||||
}
|
|
||||||
// Note: We need to get the actual file object for ClaudeFileEditor
|
|
||||||
// For now, returning a placeholder
|
|
||||||
return <div className="p-4">{t('messages.claudeFileEditorNotImplemented')}</div>;
|
|
||||||
|
|
||||||
case 'agent-execution':
|
case 'agent-execution':
|
||||||
if (!tab.agentData) {
|
if (!tab.agentData) {
|
||||||
@@ -301,7 +289,7 @@ const TabPanel: React.FC<TabPanelProps> = ({ tab, isActive }) => {
|
|||||||
|
|
||||||
export const TabContent: React.FC = () => {
|
export const TabContent: React.FC = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { tabs, activeTabId, createChatTab, findTabBySessionId, createClaudeFileTab, createAgentExecutionTab, createCreateAgentTab, createImportAgentTab, closeTab, updateTab } = useTabState();
|
const { tabs, activeTabId, createChatTab, findTabBySessionId, createAgentExecutionTab, createCreateAgentTab, createImportAgentTab, closeTab, updateTab } = useTabState();
|
||||||
const [hasInitialized, setHasInitialized] = React.useState(false);
|
const [hasInitialized, setHasInitialized] = React.useState(false);
|
||||||
|
|
||||||
// Debug: Monitor activeTabId changes
|
// Debug: Monitor activeTabId changes
|
||||||
@@ -349,11 +337,6 @@ export const TabContent: React.FC = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleOpenClaudeFile = (event: CustomEvent) => {
|
|
||||||
const { file } = event.detail;
|
|
||||||
createClaudeFileTab(file.id, file.name || 'CLAUDE.md');
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleOpenAgentExecution = (event: CustomEvent) => {
|
const handleOpenAgentExecution = (event: CustomEvent) => {
|
||||||
const { agent, tabId } = event.detail;
|
const { agent, tabId } = event.detail;
|
||||||
createAgentExecutionTab(agent, tabId);
|
createAgentExecutionTab(agent, tabId);
|
||||||
@@ -413,7 +396,6 @@ export const TabContent: React.FC = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
window.addEventListener('open-session-in-tab', handleOpenSessionInTab as EventListener);
|
window.addEventListener('open-session-in-tab', handleOpenSessionInTab as EventListener);
|
||||||
window.addEventListener('open-claude-file', handleOpenClaudeFile as EventListener);
|
|
||||||
window.addEventListener('open-agent-execution', handleOpenAgentExecution as EventListener);
|
window.addEventListener('open-agent-execution', handleOpenAgentExecution as EventListener);
|
||||||
window.addEventListener('open-create-agent-tab', handleOpenCreateAgentTab);
|
window.addEventListener('open-create-agent-tab', handleOpenCreateAgentTab);
|
||||||
window.addEventListener('open-import-agent-tab', handleOpenImportAgentTab);
|
window.addEventListener('open-import-agent-tab', handleOpenImportAgentTab);
|
||||||
@@ -422,7 +404,6 @@ export const TabContent: React.FC = () => {
|
|||||||
window.addEventListener('create-smart-session-tab', handleCreateSmartSessionTab as EventListener);
|
window.addEventListener('create-smart-session-tab', handleCreateSmartSessionTab as EventListener);
|
||||||
return () => {
|
return () => {
|
||||||
window.removeEventListener('open-session-in-tab', handleOpenSessionInTab as EventListener);
|
window.removeEventListener('open-session-in-tab', handleOpenSessionInTab as EventListener);
|
||||||
window.removeEventListener('open-claude-file', handleOpenClaudeFile as EventListener);
|
|
||||||
window.removeEventListener('open-agent-execution', handleOpenAgentExecution as EventListener);
|
window.removeEventListener('open-agent-execution', handleOpenAgentExecution as EventListener);
|
||||||
window.removeEventListener('open-create-agent-tab', handleOpenCreateAgentTab);
|
window.removeEventListener('open-create-agent-tab', handleOpenCreateAgentTab);
|
||||||
window.removeEventListener('open-import-agent-tab', handleOpenImportAgentTab);
|
window.removeEventListener('open-import-agent-tab', handleOpenImportAgentTab);
|
||||||
@@ -430,7 +411,7 @@ export const TabContent: React.FC = () => {
|
|||||||
window.removeEventListener('claude-session-selected', handleClaudeSessionSelected as EventListener);
|
window.removeEventListener('claude-session-selected', handleClaudeSessionSelected as EventListener);
|
||||||
window.removeEventListener('create-smart-session-tab', handleCreateSmartSessionTab as EventListener);
|
window.removeEventListener('create-smart-session-tab', handleCreateSmartSessionTab as EventListener);
|
||||||
};
|
};
|
||||||
}, [createChatTab, findTabBySessionId, createClaudeFileTab, createAgentExecutionTab, createCreateAgentTab, createImportAgentTab, closeTab, updateTab]);
|
}, [createChatTab, findTabBySessionId, createAgentExecutionTab, createCreateAgentTab, createImportAgentTab, closeTab, updateTab]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex-1 h-full relative">
|
<div className="flex-1 h-full relative">
|
||||||
|
|||||||
@@ -34,8 +34,6 @@ const TabItem: React.FC<TabItemProps> = ({ tab, isActive, onClose, onClick, isDr
|
|||||||
return Server;
|
return Server;
|
||||||
case 'settings':
|
case 'settings':
|
||||||
return Settings;
|
return Settings;
|
||||||
case 'claude-file':
|
|
||||||
return FileText;
|
|
||||||
case 'agent-execution':
|
case 'agent-execution':
|
||||||
return Bot;
|
return Bot;
|
||||||
case 'create-agent':
|
case 'create-agent':
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { useTranslation } from '@/hooks/useTranslation';
|
|||||||
|
|
||||||
export interface Tab {
|
export interface Tab {
|
||||||
id: string;
|
id: string;
|
||||||
type: 'chat' | 'agent' | 'projects' | 'usage' | 'mcp' | 'settings' | 'claude-file' | 'agent-execution' | 'create-agent' | 'import-agent';
|
type: 'chat' | 'agent' | 'projects' | 'usage' | 'mcp' | 'settings' | 'agent-execution' | 'create-agent' | 'import-agent';
|
||||||
title: string;
|
title: string;
|
||||||
sessionId?: string; // for chat tabs
|
sessionId?: string; // for chat tabs
|
||||||
sessionData?: any; // for chat tabs - stores full session object
|
sessionData?: any; // for chat tabs - stores full session object
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ const TAB_SCREEN_NAMES: Record<string, string> = {
|
|||||||
'usage': 'usage_dashboard',
|
'usage': 'usage_dashboard',
|
||||||
'mcp': 'mcp_manager',
|
'mcp': 'mcp_manager',
|
||||||
'settings': 'settings',
|
'settings': 'settings',
|
||||||
'claude-file': 'file_editor',
|
|
||||||
'agent-execution': 'agent_execution',
|
'agent-execution': 'agent_execution',
|
||||||
'create-agent': 'create_agent',
|
'create-agent': 'create_agent',
|
||||||
'import-agent': 'import_agent',
|
'import-agent': 'import_agent',
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ interface UseTabStateReturn {
|
|||||||
createUsageTab: () => string | null;
|
createUsageTab: () => string | null;
|
||||||
createMCPTab: () => string | null;
|
createMCPTab: () => string | null;
|
||||||
createSettingsTab: () => string | null;
|
createSettingsTab: () => string | null;
|
||||||
createClaudeFileTab: (fileId: string, fileName: string) => string;
|
// Removed: createClaudeFileTab
|
||||||
createCreateAgentTab: () => string;
|
createCreateAgentTab: () => string;
|
||||||
createImportAgentTab: () => string;
|
createImportAgentTab: () => string;
|
||||||
closeTab: (id: string, force?: boolean) => Promise<boolean>;
|
closeTab: (id: string, force?: boolean) => Promise<boolean>;
|
||||||
@@ -162,23 +162,7 @@ export const useTabState = (): UseTabStateReturn => {
|
|||||||
|
|
||||||
// Removed createClaudeMdTab: using Prompt Files manager instead
|
// Removed createClaudeMdTab: using Prompt Files manager instead
|
||||||
|
|
||||||
const createClaudeFileTab = useCallback((fileId: string, fileName: string): string => {
|
// Removed: project-level CLAUDE.md file tab creation
|
||||||
// Check if tab already exists for this file
|
|
||||||
const existingTab = tabs.find(tab => tab.type === 'claude-file' && tab.claudeFileId === fileId);
|
|
||||||
if (existingTab) {
|
|
||||||
setActiveTab(existingTab.id);
|
|
||||||
return existingTab.id;
|
|
||||||
}
|
|
||||||
|
|
||||||
return addTab({
|
|
||||||
type: 'claude-file',
|
|
||||||
title: fileName,
|
|
||||||
claudeFileId: fileId,
|
|
||||||
status: 'idle',
|
|
||||||
hasUnsavedChanges: false,
|
|
||||||
icon: 'file-text'
|
|
||||||
});
|
|
||||||
}, [addTab, tabs, setActiveTab]);
|
|
||||||
|
|
||||||
const createAgentExecutionTab = useCallback((agent: any, _tabId: string): string => {
|
const createAgentExecutionTab = useCallback((agent: any, _tabId: string): string => {
|
||||||
return addTab({
|
return addTab({
|
||||||
@@ -312,7 +296,6 @@ export const useTabState = (): UseTabStateReturn => {
|
|||||||
createUsageTab,
|
createUsageTab,
|
||||||
createMCPTab,
|
createMCPTab,
|
||||||
createSettingsTab,
|
createSettingsTab,
|
||||||
createClaudeFileTab,
|
|
||||||
createCreateAgentTab,
|
createCreateAgentTab,
|
||||||
createImportAgentTab,
|
createImportAgentTab,
|
||||||
closeTab,
|
closeTab,
|
||||||
|
|||||||
Reference in New Issue
Block a user