Skip to content

Commit 35cddd1

Browse files
Merge pull request #25 from chriswritescode-dev/rst-support
Rst support - UI Refactor
2 parents 33db31a + 8d59e01 commit 35cddd1

34 files changed

+1367
-337
lines changed

CHANGELOG.md

Lines changed: 47 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,33 @@ All notable changes to CodeDox will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8-
## [Unreleased]
8+
## 0.2.8
9+
10+
### Added
11+
- **reStructuredText (RST) Support**: Complete RST document processing with intelligent code extraction
12+
- Support for `.. code-block::` directive with language specification
13+
- Support for `.. code::` and `.. sourcecode::` directives
14+
- Literal block extraction using `::` syntax
15+
- Automatic language detection from RST directives
16+
- Comprehensive test coverage with various RST formats
17+
- Integration with existing upload and processing pipeline
18+
19+
### Improved
20+
- **Code Extraction Pipeline**: Enhanced to handle RST documents alongside existing formats
21+
22+
### Technical Details
23+
- **RST Code Extraction**: Implemented `RSTCodeExtractor` class in `src/api/routes/upload_utils.py`
24+
- **Supported RST Features**:
25+
- `.. code-block:: python` with language specification and options
26+
- `.. code:: javascript` for shorter syntax
27+
- `.. sourcecode:: ruby` for alternative directive format
28+
- Literal blocks using `::` syntax with preserved indentation
29+
- Automatic filtering of directive options and metadata
30+
- Context preservation around code blocks
31+
- **Test Coverage**: Added comprehensive test suite in `tests/test_rst_extraction.py`
32+
- **File Support**: RST files (.rst, .rest, .restx, .rtxt, .rstx) now fully supported in upload processing
33+
34+
## [0.2.7]
935

1036
### Added
1137
- **GitHub Repository Processing**: Direct cloning and processing of GitHub repositories
@@ -17,12 +43,29 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1743
- Source URL generation for each processed file
1844
- **New CLI Command**: `upload-repo` command for GitHub repository processing
1945
- **Comprehensive GitHub Documentation**: Added detailed documentation for GitHub features
46+
- **Enhanced Search with Markdown Fallback**: Automatically searches documentation content when code snippet searches return limited results
47+
- **Markdown Search with Highlighting**: Full-text search across markdown documentation with intelligent highlighting and auto-scroll to matches
48+
- **Web UI Search Improvements**: Toggle between code-only and enhanced search modes in the UI
49+
- **Comprehensive Documentation**: Added detailed feature documentation with screenshots
2050

2151
### Improved
2252
- **Documentation Structure**: Better organization with dedicated GitHub processing section
2353
- **Markdown Formatting**: Fixed list formatting issues for better mkdocs rendering
54+
- **Code Quality**: Fixed import ordering, removed unused imports, and improved type hints throughout the codebase
55+
- **Test Infrastructure**: Enhanced test fixtures and database cleanup procedures
56+
- **Search Performance**: Optimized PostgreSQL full-text search with better indexing and query strategies
57+
- **MCP Tools**: Improved error handling and response formatting for better AI assistant integration
58+
59+
### Fixed
60+
- **Code Extraction**: Resolved issues with HTML code extraction and duplicate detection
61+
- **Upload UI**: Fixed spacing and layout issues in the upload interface
62+
- **Database Schema**: Cleaned up schema setup and migration handling
63+
64+
### Changed
65+
- **Screenshot Organization**: Consolidated all screenshots into docs/screenshots directory for single source of truth
66+
- **Search Defaults**: Changed default search behavior to use enhanced mode for better results
2467

25-
## [0.2.6] - 2025-01-01
68+
## [0.2.6]
2669

2770
### Added
2871
- **Enhanced Search with Markdown Fallback**: Automatically searches documentation content when code snippet searches return limited results
@@ -45,7 +88,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
4588
- **Screenshot Organization**: Consolidated all screenshots into docs/screenshots directory for single source of truth
4689
- **Search Defaults**: Changed default search behavior to use enhanced mode for better results
4790

48-
## [0.2.5] - 2024-12-31
91+
## [0.2.5]
4992

5093
### Added
5194
- Initial public release with core functionality
@@ -54,4 +97,4 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
5497
- PostgreSQL full-text search
5598
- MCP server integration
5699
- React/TypeScript Web UI
57-
- Upload support for markdown files
100+
- Upload support for markdown files

cli.py

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -199,14 +199,12 @@ async def run_upload():
199199
final_source_url = source_url if source_url else f"file://{os.path.abspath(file_path)}"
200200
final_name = name if name else os.path.basename(file_path)
201201

202-
# Determine content type from extension
203-
content_type = "markdown"
204-
if file_path.endswith(".rst"):
205-
content_type = "restructuredtext"
206-
elif file_path.endswith(".adoc"):
207-
content_type = "asciidoc"
208-
elif file_path.endswith(".txt"):
209-
content_type = "text"
202+
# Determine content type from extension using centralized config
203+
from src.constants import get_content_type_for_extension
204+
205+
content_type = get_content_type_for_extension(file_path)
206+
if not content_type:
207+
content_type = "text" # Default fallback
210208

211209
processor = UploadProcessor()
212210

@@ -278,15 +276,16 @@ async def run_upload_repo():
278276
task = progress.add_task("Cloning repository...", total=None)
279277

280278
# Auto-generate name from repo URL if not provided
281-
if not name:
279+
repo_name = name
280+
if not repo_name:
282281
import re
283282

284283
match = re.search(r"/([^/]+?)(?:\.git)?$", repo_url)
285-
name = match.group(1) if match else "Repository Documentation"
284+
repo_name = match.group(1) if match else "Repository Documentation"
286285

287286
config = GitHubRepoConfig(
288287
repo_url=repo_url,
289-
name=name,
288+
name=repo_name,
290289
path=path,
291290
branch=branch,
292291
token=token,

docs/getting-started/upgrade.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ docker-compose down
5050
git fetch origin
5151

5252
# For specific version
53-
git checkout v0.2.6
53+
git checkout v0.2.8
5454

5555
# Or for latest main branch
5656
git pull origin main
@@ -130,7 +130,7 @@ python cli.py search "test query"
130130

131131
## Version-Specific Upgrade Notes
132132

133-
### Upgrading to 0.2.6
133+
### Upgrading to 0.2.8
134134

135135
**New Features:**
136136
- Enhanced markdown search with fallback

docs/index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ CodeDox solves this by:
3232
### Intelligent Code Extraction
3333

3434
- **AI-Enhanced Processing**: LLM-powered language detection, title generation, and intelligent descriptions
35-
- **Multi-Format Support**: Extracts from Markdown, HTML, text files, and 20+ documentation frameworks
35+
- **Multi-Format Support**: Extracts from Markdown, HTML, text files
3636
- **Smart Context Preservation**: Maintains relationships and surrounding context for better code understanding
3737
- **Batch Processing**: Efficient parallel processing with configurable concurrency
3838

frontend/src/components/ConfirmationDialog.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import React from 'react';
2+
import { useKeyboardShortcut } from '../hooks/useKeyboardShortcut';
23

34
interface ConfirmationDialogProps {
45
isOpen: boolean;
@@ -23,6 +24,9 @@ export const ConfirmationDialog: React.FC<ConfirmationDialogProps> = ({
2324
variant = 'default',
2425
isConfirming = false,
2526
}) => {
27+
// Handle Escape key to cancel
28+
useKeyboardShortcut('Escape', onCancel, { isEnabled: isOpen && !isConfirming });
29+
2630
if (!isOpen) return null;
2731

2832
return (

frontend/src/components/DocumentSearchModal.tsx

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import React, { useState, useEffect, useRef } from "react";
22
import { Search, X, FileText, ExternalLink, Loader2 } from "lucide-react";
33
import { api } from "../lib/api";
44
import { FullPageModal } from "./FullPageModal";
5+
import { useKeyboardShortcut } from "../hooks/useKeyboardShortcut";
56

67
interface DocumentSearchModalProps {
78
isOpen: boolean;
@@ -34,6 +35,8 @@ export const DocumentSearchModal: React.FC<DocumentSearchModalProps> = ({
3435
}
3536
}, [isOpen]);
3637

38+
useKeyboardShortcut("Escape", onClose, isOpen);
39+
3740
const performSearch = async (searchQuery: string) => {
3841
if (!searchQuery.trim()) {
3942
setResults([]);
@@ -73,11 +76,7 @@ export const DocumentSearchModal: React.FC<DocumentSearchModalProps> = ({
7376
setFullPageModalOpen(true);
7477
};
7578

76-
const handleKeyDown = (e: React.KeyboardEvent) => {
77-
if (e.key === "Escape") {
78-
onClose();
79-
}
80-
};
79+
8180

8281
if (!isOpen) return null;
8382

@@ -92,7 +91,6 @@ export const DocumentSearchModal: React.FC<DocumentSearchModalProps> = ({
9291
type="text"
9392
value={query}
9493
onChange={(e) => setQuery(e.target.value)}
95-
onKeyDown={handleKeyDown}
9694
placeholder="Search pages by title, URL, or content..."
9795
className="flex-1 bg-transparent outline-none text-gray-900 dark:text-gray-100 placeholder-gray-500"
9896
autoFocus

frontend/src/components/FullPageModal.tsx

Lines changed: 9 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
} from "lucide-react";
1313
import { api } from "../lib/api";
1414
import { Link } from "react-router-dom";
15+
import { useKeyboardShortcut } from "../hooks/useKeyboardShortcut";
1516

1617
interface FullPageModalProps {
1718
url: string;
@@ -44,25 +45,14 @@ export const FullPageModal: React.FC<FullPageModalProps> = ({
4445
}, [isOpen, url]);
4546

4647
// Handle keyboard shortcuts
47-
useEffect(() => {
48-
const handleKeyDown = (e: KeyboardEvent) => {
49-
if (!isOpen) return;
50-
51-
// ESC to close modal
52-
if (e.key === "Escape") {
53-
onClose();
54-
}
55-
56-
// Ctrl/Cmd + F to focus search
57-
if ((e.ctrlKey || e.metaKey) && e.key === "f") {
58-
e.preventDefault();
59-
searchInputRef.current?.focus();
60-
}
61-
};
62-
63-
window.addEventListener("keydown", handleKeyDown);
64-
return () => window.removeEventListener("keydown", handleKeyDown);
65-
}, [isOpen, onClose]);
48+
useKeyboardShortcut('Escape', onClose, { isEnabled: isOpen });
49+
50+
useKeyboardShortcut('f', () => {
51+
searchInputRef.current?.focus();
52+
}, {
53+
isEnabled: isOpen,
54+
ctrlKey: true
55+
});
6656

6757
const fetchPageMarkdown = async () => {
6858
setLoading(true);

frontend/src/components/Layout.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,14 +100,14 @@ export default function Layout() {
100100
<div className="px-3 pt-4 pb-2 space-y-2">
101101
<button
102102
onClick={() => setCrawlDialogOpen(true)}
103-
className="w-full flex items-center gap-2 px-3 py-2.5 text-sm bg-primary hover:bg-primary/90 text-primary-foreground rounded-lg transition-all font-medium shadow-sm hover:shadow-md"
103+
className="cursor-pointer w-full flex items-center gap-2 px-3 py-2.5 text-sm bg-primary hover:bg-primary/90 text-primary-foreground rounded-lg transition-all font-medium shadow-sm hover:shadow-md"
104104
>
105105
<Plus className="h-4 w-4" />
106106
<span className="flex-1 text-left">New Crawl</span>
107107
</button>
108108
<button
109109
onClick={() => setDocumentSearchOpen(true)}
110-
className="w-full flex items-center gap-2 px-3 py-2 text-sm bg-gray-100 dark:bg-gray-800 hover:bg-gray-200 dark:hover:bg-gray-700 rounded-lg transition-colors text-gray-600 dark:text-gray-400"
110+
className="cursor-pointer w-full flex items-center gap-2 px-3 py-2 text-sm bg-gray-100 dark:bg-gray-800 hover:bg-gray-200 dark:hover:bg-gray-700 rounded-lg transition-colors text-gray-600 dark:text-gray-400"
111111
>
112112
<FileSearch className="h-4 w-4" />
113113
<span className="flex-1 text-left">Markdown Pages</span>

frontend/src/components/NewCrawlDialog.tsx

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import React, { useState } from 'react';
22
import { X } from 'lucide-react';
33
import { useToast } from '../hooks/useToast';
4+
import { useKeyboardShortcut } from '../hooks/useKeyboardShortcut';
45

56
interface NewCrawlDialogProps {
67
isOpen: boolean;
@@ -38,6 +39,15 @@ export const NewCrawlDialog: React.FC<NewCrawlDialogProps> = ({
3839

3940
const [maxConcurrentInput, setMaxConcurrentInput] = useState('5');
4041

42+
const handleClose = () => {
43+
setFormData({ name: '', version: '', base_url: '', max_pages: undefined, max_depth: 1, domain_filter: '', url_patterns: '', max_concurrent_crawls: 5 });
44+
setMaxConcurrentInput('5');
45+
onClose();
46+
};
47+
48+
// Handle Escape key to close dialog
49+
useKeyboardShortcut('Escape', handleClose, { isEnabled: isOpen && !isSubmitting });
50+
4151
if (!isOpen) return null;
4252

4353
const handleSubmit = (e: React.FormEvent) => {
@@ -64,12 +74,6 @@ export const NewCrawlDialog: React.FC<NewCrawlDialogProps> = ({
6474
onSubmit(submitData);
6575
};
6676

67-
const handleClose = () => {
68-
setFormData({ name: '', version: '', base_url: '', max_pages: undefined, max_depth: 1, domain_filter: '', url_patterns: '', max_concurrent_crawls: 5 });
69-
setMaxConcurrentInput('5');
70-
onClose();
71-
};
72-
7377
return (
7478
<div className="fixed inset-0 bg-slate-600/50 backdrop-blur-sm flex items-center justify-center z-50">
7579
<div className="bg-card border-2 border-border rounded-lg w-full max-w-md max-h-[90vh] shadow-2xl animate-slide-up flex flex-col">

frontend/src/components/RecrawlDialog.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { useState } from "react";
22
import { X, RefreshCw, AlertTriangle } from "lucide-react";
3+
import { useKeyboardShortcut } from "../hooks/useKeyboardShortcut";
34

45
interface RecrawlDialogProps {
56
isOpen: boolean;
@@ -20,6 +21,9 @@ export function RecrawlDialog({
2021
}: RecrawlDialogProps) {
2122
const [ignoreHash, setIgnoreHash] = useState(false);
2223

24+
// Handle Escape key to cancel
25+
useKeyboardShortcut('Escape', onCancel, { isEnabled: isOpen && !isRecrawling });
26+
2327
if (!isOpen) return null;
2428

2529
return (

0 commit comments

Comments
 (0)