Add comprehensive documentation system and tool call tracking
## Documentation System - Create complete documentation hub at /dashboard/docs with: - Getting Started guide with quick setup and troubleshooting - Hook Setup Guide with platform-specific configurations - API Reference with all endpoints and examples - FAQ with searchable questions and categories - Add responsive design with interactive features - Update navigation in base template ## Tool Call Tracking - Add ToolCall model for tracking Claude Code tool usage - Create /api/tool-calls endpoints for recording and analytics - Add tool_call hook type with auto-session detection - Include tool calls in project statistics and recalculation - Track tool names, parameters, execution time, and success rates ## Project Enhancements - Add project timeline and statistics pages (fix 404 errors) - Create recalculation script for fixing zero statistics - Update project stats to include tool call counts - Enhance session model with tool call relationships ## Infrastructure - Switch from requirements.txt to pyproject.toml/uv.lock - Add data import functionality for claude.json files - Update database connection to include all new models - Add comprehensive API documentation 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
166247bf70
commit
bec1606c86
27 changed files with 6150 additions and 32 deletions
|
|
@ -29,6 +29,10 @@
|
|||
<i class="fas fa-search me-1"></i>
|
||||
Search
|
||||
</button>
|
||||
<button class="btn btn-outline-secondary" type="button" onclick="clearSearch()">
|
||||
<i class="fas fa-times me-1"></i>
|
||||
Clear
|
||||
</button>
|
||||
</div>
|
||||
<div class="form-text">
|
||||
Search through your conversation history with Claude Code
|
||||
|
|
@ -58,9 +62,10 @@
|
|||
<div class="card-body">
|
||||
<div id="conversation-results">
|
||||
<div class="text-center text-muted py-5">
|
||||
<i class="fas fa-search fa-3x mb-3"></i>
|
||||
<h5>Search Your Conversations</h5>
|
||||
<p>Enter a search term to find relevant conversations with Claude.</p>
|
||||
<div class="spinner-border text-primary" role="status">
|
||||
<span class="visually-hidden">Loading conversations...</span>
|
||||
</div>
|
||||
<p class="mt-2">Loading your recent conversations...</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -73,6 +78,7 @@
|
|||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
loadProjects();
|
||||
loadRecentConversations();
|
||||
});
|
||||
|
||||
async function loadProjects() {
|
||||
|
|
@ -86,17 +92,91 @@ async function loadProjects() {
|
|||
option.textContent = project.name;
|
||||
select.appendChild(option);
|
||||
});
|
||||
|
||||
// Add event listener for project filtering
|
||||
select.addEventListener('change', function() {
|
||||
const selectedProjectId = this.value ? parseInt(this.value) : null;
|
||||
loadConversationsForProject(selectedProjectId);
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Failed to load projects:', error);
|
||||
}
|
||||
}
|
||||
|
||||
async function loadRecentConversations() {
|
||||
await loadConversationsForProject(null);
|
||||
}
|
||||
|
||||
async function loadConversationsForProject(projectId = null) {
|
||||
const resultsContainer = document.getElementById('conversation-results');
|
||||
const resultsTitle = document.getElementById('results-title');
|
||||
|
||||
// Show loading state
|
||||
resultsContainer.innerHTML = `
|
||||
<div class="text-center text-muted py-3">
|
||||
<div class="spinner-border text-primary" role="status">
|
||||
<span class="visually-hidden">Loading...</span>
|
||||
</div>
|
||||
<p class="mt-2">Loading conversations...</p>
|
||||
</div>
|
||||
`;
|
||||
|
||||
try {
|
||||
// Update title based on filtering
|
||||
if (projectId) {
|
||||
const projects = await apiClient.getProjects();
|
||||
const project = projects.find(p => p.id === projectId);
|
||||
resultsTitle.textContent = `Conversations - ${project ? project.name : 'Selected Project'}`;
|
||||
} else {
|
||||
resultsTitle.textContent = 'Recent Conversations';
|
||||
}
|
||||
|
||||
const conversations = await apiClient.getConversations(projectId, 50);
|
||||
|
||||
if (!conversations.length) {
|
||||
const noResultsMessage = projectId ?
|
||||
`No conversations found for this project.` :
|
||||
`No conversation history has been recorded yet.`;
|
||||
|
||||
resultsContainer.innerHTML = `
|
||||
<div class="text-center text-muted py-5">
|
||||
<i class="fas fa-comments fa-3x mb-3"></i>
|
||||
<h5>No Conversations Found</h5>
|
||||
<p>${noResultsMessage}</p>
|
||||
${!projectId ? '<p class="small text-muted">Conversations will appear here as you use Claude Code.</p>' : ''}
|
||||
</div>
|
||||
`;
|
||||
return;
|
||||
}
|
||||
|
||||
displaySearchResults(conversations, null);
|
||||
|
||||
} catch (error) {
|
||||
console.error('Failed to load conversations:', error);
|
||||
resultsContainer.innerHTML = `
|
||||
<div class="text-center text-danger py-4">
|
||||
<i class="fas fa-exclamation-triangle fa-2x mb-2"></i>
|
||||
<p>Failed to load conversations. Please try again.</p>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
function handleSearchKeypress(event) {
|
||||
if (event.key === 'Enter') {
|
||||
searchConversations();
|
||||
}
|
||||
}
|
||||
|
||||
function clearSearch() {
|
||||
// Clear the search input
|
||||
document.getElementById('search-query').value = '';
|
||||
|
||||
// Return to filtered/unfiltered conversation list based on current project filter
|
||||
const projectId = document.getElementById('project-filter').value || null;
|
||||
loadConversationsForProject(projectId ? parseInt(projectId) : null);
|
||||
}
|
||||
|
||||
async function searchConversations() {
|
||||
const query = document.getElementById('search-query').value.trim();
|
||||
const projectId = document.getElementById('project-filter').value || null;
|
||||
|
|
@ -164,9 +244,11 @@ function displaySearchResults(results, query) {
|
|||
<i class="fas fa-clock me-1"></i>
|
||||
${ApiUtils.formatRelativeTime(result.timestamp)}
|
||||
</small>
|
||||
<span class="badge bg-success ms-2">
|
||||
${(result.relevance_score * 100).toFixed(0)}% match
|
||||
</span>
|
||||
${query ? `
|
||||
<span class="badge bg-success ms-2">
|
||||
${(result.relevance_score * 100).toFixed(0)}% match
|
||||
</span>
|
||||
` : ''}
|
||||
</div>
|
||||
|
||||
${result.user_prompt ? `
|
||||
|
|
@ -175,7 +257,7 @@ function displaySearchResults(results, query) {
|
|||
<i class="fas fa-user me-1"></i>
|
||||
You:
|
||||
</strong>
|
||||
<p class="mb-1">${highlightSearchTerms(ApiUtils.truncateText(result.user_prompt, 200), query)}</p>
|
||||
<p class="mb-1">${query ? highlightSearchTerms(ApiUtils.truncateText(result.user_prompt, 200), query) : ApiUtils.truncateText(result.user_prompt, 200)}</p>
|
||||
</div>
|
||||
` : ''}
|
||||
|
||||
|
|
@ -185,11 +267,11 @@ function displaySearchResults(results, query) {
|
|||
<i class="fas fa-robot me-1"></i>
|
||||
Claude:
|
||||
</strong>
|
||||
<p class="mb-1">${highlightSearchTerms(ApiUtils.truncateText(result.claude_response, 200), query)}</p>
|
||||
<p class="mb-1">${query ? highlightSearchTerms(ApiUtils.truncateText(result.claude_response, 200), query) : ApiUtils.truncateText(result.claude_response, 200)}</p>
|
||||
</div>
|
||||
` : ''}
|
||||
|
||||
${result.context && result.context.length ? `
|
||||
${result.context && result.context.length && query ? `
|
||||
<div class="mt-2">
|
||||
<small class="text-muted">Context snippets:</small>
|
||||
${result.context.map(snippet => `
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue