Add seed script with 7 trees, markdown rendering, and dark mode docs

- Add comprehensive seed script with 7 troubleshooting decision trees
  - Tier 1: Password Reset, Outlook/Email, VPN, Printer Problems
  - Tier 2: Slow Computer, Network Connectivity
  - Tier 3: File Share Access Problems
- Add markdown rendering with react-markdown package
  - MarkdownContent component for session player and node editor
  - Preview toggle in description fields
- Update documentation to reflect dark mode is complete
- Update all progress tracking docs with recent changes

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
chihlasm
2026-01-29 02:25:03 -05:00
parent 0fe2ca850f
commit adcaf2f4fe
12 changed files with 5051 additions and 80 deletions

View File

@@ -47,13 +47,17 @@
- [x] Download as file - [x] Download as file
**Content:** **Content:**
- [ ] Create 5 starter decision trees: - [x] Create 7 comprehensive decision trees via `backend/scripts/seed_trees.py`:
1. [ ] Citrix VDA Not Registering **Tier 1 - Help Desk:**
2. [ ] FSLogix Profile Issues 1. [x] Password Reset/Account Lockout (20+ nodes)
3. [ ] Active Directory Replication Failure 2. [x] Outlook/Email Problems (15+ nodes)
4. [ ] SonicWall VPN Tunnel Down 3. [x] VPN Connection Failures (15+ nodes)
5. [x] User Unable to Access File Share (stub) 4. [x] Printer Problems (15+ nodes)
6. [x] Password Reset/Account Lockout (FULL implementation) **Tier 2 - Desktop Support:**
5. [x] Slow Computer Troubleshooting (15+ nodes)
6. [x] Network Connectivity Issues (15+ nodes)
**Tier 3 - Systems:**
7. [x] File Share Access Problems (20+ nodes)
### Week 3: Polish & Testing ### Week 3: Polish & Testing
**Backend:** **Backend:**
@@ -62,15 +66,16 @@
- [x] Performance optimization - [x] Performance optimization
**Frontend:** **Frontend:**
- [ ] UI/UX refinements - *In progress* - [x] UI/UX refinements - Markdown rendering added
- [x] Responsive design (desktop focus) - [x] Responsive design (desktop focus)
- [x] Loading states - [x] Loading states
- [x] Error handling and user feedback (ErrorBoundary) - [x] Error handling and user feedback (ErrorBoundary)
- [x] Markdown rendering in session player and node editor
- [ ] Keyboard shortcuts - *Not yet implemented* - [ ] Keyboard shortcuts - *Not yet implemented*
- [ ] User preferences - [x] User preferences (partial)
- [x] Theme toggle (dark/light/system) - **COMPLETE**
- [x] Persist preferences in localStorage
- [ ] Settings modal/page accessible from user menu - [ ] Settings modal/page accessible from user menu
- [ ] Theme toggle (dark/light/system)
- [ ] Persist preferences in localStorage
- [ ] Default export format preference - [ ] Default export format preference
**Testing:** **Testing:**
@@ -116,18 +121,19 @@
### Week 5: Tree Management ### Week 5: Tree Management
**Backend:** **Backend:**
- [ ] Tree categories and tagging - [x] Tree categories and tagging
- [ ] Tree search API (full-text) - [x] Tree search API (full-text)
- [ ] Tree usage statistics - [ ] Tree usage statistics
- [ ] Session history API - [x] Session history API
**Frontend:** **Frontend:**
- [ ] Tree editor UI - [x] Tree editor UI
- [ ] Visual tree builder (drag-and-drop nodes) - [ ] Visual tree builder (drag-and-drop nodes) - *Form-based implemented instead*
- [ ] Add/edit/delete nodes - [x] Add/edit/delete nodes
- [ ] Set question types (yes/no, multiple choice, action) - [x] Set question types (yes/no, multiple choice, action)
- [ ] Add help text and documentation links - [x] Add help text and documentation links
- [ ] Save and publish - [x] Markdown preview in description fields
- [x] Save and publish
- [ ] Tree library/browser - [ ] Tree library/browser
- [ ] Category filters - [ ] Category filters
- [ ] Search functionality - [ ] Search functionality

View File

@@ -2,7 +2,7 @@
This document catalogs all tools, plugins, and MCP servers available to Claude Code when developing Apoklisis, along with guidelines for their effective use. This document catalogs all tools, plugins, and MCP servers available to Claude Code when developing Apoklisis, along with guidelines for their effective use.
**Last Updated**: 2026-01-28 **Last Updated**: 2026-01-29
**Project**: Apoklisis **Project**: Apoklisis
**Working Directory**: `c:\Dev\Projects\Apoklisis` **Working Directory**: `c:\Dev\Projects\Apoklisis`
**Platform**: Windows (win32) **Platform**: Windows (win32)
@@ -432,13 +432,15 @@ curl -X GET "http://localhost:8000/api/v1/trees" -H "Authorization: Bearer <toke
- ✅ NodePicker with type-grouped dropdown - ✅ NodePicker with type-grouped dropdown
- ✅ SharedLinksMap for detecting nodes with multiple sources - ✅ SharedLinksMap for detecting nodes with multiple sources
- ✅ Modal with scrollable content, fixed header/footer - ✅ Modal with scrollable content, fixed header/footer
- ✅ Markdown rendering in session player and node editor
- ✅ Dark mode / theme toggle
- ⏳ Validation polish (required fields, orphan detection) - ⏳ Validation polish (required fields, orphan detection)
**Phase 2 Remaining** - ⏳ **Planned** **Phase 2 Remaining** - ⏳ **Planned**
- Team management features - Team management features
- Mobile responsive improvements - Mobile responsive improvements
- User preferences (dark mode) - ~~User preferences (dark mode)~~ ✅ **COMPLETE**
### Backend File Structure ### Backend File Structure

View File

@@ -2,7 +2,7 @@
> **Purpose:** Quick-reference file showing exactly where the project stands. > **Purpose:** Quick-reference file showing exactly where the project stands.
> **For Claude Code:** Read this first to understand what's done and what's next. > **For Claude Code:** Read this first to understand what's done and what's next.
> **Last Updated:** January 28, 2026 > **Last Updated:** January 29, 2026
--- ---
@@ -43,7 +43,12 @@
- ✅ Visual tree preview with solution indicators - ✅ Visual tree preview with solution indicators
- ✅ Shared node detection (multiple sources → same target) - ✅ Shared node detection (multiple sources → same target)
- ✅ Modal with scrollable content, fixed header/footer - ✅ Modal with scrollable content, fixed header/footer
- ⏳ User preferences (dark mode) - NOT YET STARTED - ✅ Markdown preview toggle in description fields
-**Markdown Rendering** - Session player and node editor
-`react-markdown` package installed
-`MarkdownContent` component created
- ✅ Renders bold, italic, lists, code blocks, headers
- ✅ User preferences (dark mode) - COMPLETE
- ⏳ Keyboard shortcuts - NOT YET STARTED - ⏳ Keyboard shortcuts - NOT YET STARTED
### Documentation ### Documentation
@@ -61,9 +66,10 @@
|------|--------|-------| |------|--------|-------|
| Tree Editor | Functional | Core editing complete, polish ongoing | | Tree Editor | Functional | Core editing complete, polish ongoing |
| Tree Editor Validation | Partial | Basic validation working | | Tree Editor Validation | Partial | Basic validation working |
| User Preferences | Not started | Dark/light mode, export format default | | User Preferences | **Partial** | Dark/light mode complete, export format default pending |
| TypeScript strict mode | Warnings exist | tsconfig needs `strict: true` | | TypeScript strict mode | Warnings exist | tsconfig needs `strict: true` |
| Starter decision trees | 1 of 5 complete | Need 4 more real trees | | Starter decision trees | **7 of 7 complete** | Comprehensive seed script created |
| Markdown Rendering | **Complete** | Session player + node editor |
| Deployment | Not started | Railway/Render planned | | Deployment | Not started | Railway/Render planned |
--- ---
@@ -72,9 +78,9 @@
### Immediate (This Week) ### Immediate (This Week)
1. Complete Tree Editor validation (required fields, orphan detection) 1. Complete Tree Editor validation (required fields, orphan detection)
2. Add User Preferences (theme toggle, export format default) 2. ~~Add User Preferences (theme toggle, export format default)~~ Theme toggle **COMPLETE**, export format pending
3. Fix TypeScript strict mode warnings 3. Fix TypeScript strict mode warnings
4. Create remaining 4 starter decision trees 4. ~~Create remaining 4 starter decision trees~~ **COMPLETE** - 7 trees seeded
### Soon (Phase 2 Completion) ### Soon (Phase 2 Completion)
- Team management - Team management
@@ -189,7 +195,26 @@ pytest
--- ---
## Recent Changes (Jan 28, 2026) ## Recent Changes (Jan 29, 2026)
1. **Comprehensive Seed Script** (`backend/scripts/seed_trees.py`):
- 7 complete troubleshooting decision trees with 10-20+ nodes each
- **Tier 1 (Help Desk)**: Password Reset, Outlook/Email, VPN Connection, Printer Problems
- **Tier 2 (Desktop Support)**: Slow Computer, Network Connectivity
- **Tier 3 (Systems)**: File Share Access Problems
- Real PowerShell commands in action nodes
- Professional ticket documentation in solution nodes
2. **Markdown Rendering** in Session Player and Node Editor:
- Installed `react-markdown` package
- Created `MarkdownContent` component (`frontend/src/components/ui/MarkdownContent.tsx`)
- Updated `TreeNavigationPage.tsx` to render descriptions with markdown
- Added markdown preview toggle in `NodeFormAction.tsx` and `NodeFormResolution.tsx`
- Supports: bold, italic, lists, code blocks, headers, blockquotes
3. Updated LESSONS-LEARNED.md with:
- httpx installation requirement for seed scripts
- Email validation rejecting `.local` TLD (RFC 6761)
## Previous Changes (Jan 28, 2026)
1. Fixed DateTime timezone bugs in all models 1. Fixed DateTime timezone bugs in all models
2. Added production logging system 2. Added production logging system
@@ -222,10 +247,17 @@ pytest
*Update this section at the end of each coding session:* *Update this section at the end of each coding session:*
**Last Session (Jan 28, 2026):** **Last Session (Jan 29, 2026):**
- Created comprehensive seed script with 7 troubleshooting trees
- Added markdown rendering to session player and node editor
- Installed react-markdown package and created MarkdownContent component
- Added markdown preview toggle in description fields
- Fixed httpx and email validation issues (documented in LESSONS-LEARNED.md)
- Next: User preferences UI, Tree Editor validation polish, deployment
**Previous Session (Jan 28, 2026):**
- Completed Tree Editor core implementation - Completed Tree Editor core implementation
- Fixed modal scroll/overflow issue (content scrolls, header/footer fixed) - Fixed modal scroll/overflow issue (content scrolls, header/footer fixed)
- Added SharedLinksMap for tracking nodes that link to same target - Added SharedLinksMap for tracking nodes that link to same target
- Improved NodePicker with type-grouped dropdown - Improved NodePicker with type-grouped dropdown
- Added solution connection indicators in preview - Added solution connection indicators in preview
- Next: Tree Editor validation polish, user preferences UI

View File

@@ -6,6 +6,69 @@
--- ---
## Environment Setup (New Machine)
### Database Name Mismatch After Fresh Clone
**Problem:** After cloning the repo and running `docker-compose up -d`, Alembic migrations fail with `database "decision_tree" does not exist`.
**Cause:** The `.env` file contains the old database name (`decision_tree`) but `docker-compose.yml` creates a database called `apoklisis`.
**Solution:** Update `.env` to use the correct database name:
```
DATABASE_URL=postgresql+asyncpg://postgres:postgres@localhost:5432/apoklisis
DATABASE_URL_SYNC=postgresql://postgres:postgres@localhost:5432/apoklisis
```
**Files affected:** `backend/.env`
---
### Missing @/lib/utils (cn function)
**Problem:** Frontend fails to compile with error: `Failed to resolve import "@/lib/utils" from "src/pages/SessionDetailPage.tsx". Does the file exist?`
**Cause:** The `src/lib/utils.ts` file wasn't committed to the repo or was missed during setup. This file provides the `cn()` utility function used for combining Tailwind classes.
**Solution:** Create `frontend/src/lib/utils.ts`:
```typescript
import { type ClassValue, clsx } from 'clsx'
import { twMerge } from 'tailwind-merge'
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs))
}
```
**Dependencies required:** `clsx` and `tailwind-merge` (already in package.json)
**Files affected:** `frontend/src/lib/utils.ts`
---
### pip install in venv doesn't need --break-system-packages
**Problem:** Confusion about whether to use `--break-system-packages` flag.
**Clarification:** The `--break-system-packages` flag is only needed when installing packages **outside** of a virtual environment. When your venv is active (you see `(venv)` prefix), you don't need this flag.
---
### New Machine Setup Checklist
When setting up development on a new machine:
1. **Clone repo:** `git clone <repo-url>`
2. **Start Docker Desktop**
3. **Start database:** `cd backend && docker-compose up -d`
4. **Fix .env database name** if it says `decision_tree` → change to `apoklisis`
5. **Create venv:** `python -m venv venv`
6. **Activate venv:** `.\venv\Scripts\Activate`
7. **Install backend deps:** `pip install -r requirements.txt`
8. **Run migrations:** `alembic upgrade head`
9. **Start backend:** `uvicorn app.main:app --reload`
10. **Install frontend deps:** `cd ../frontend && npm install`
11. **Create lib/utils.ts** if missing (see above)
12. **Start frontend:** `npm run dev`
---
## Python / Backend ## Python / Backend
### DateTime Timezone Handling ⚠️ CRITICAL ### DateTime Timezone Handling ⚠️ CRITICAL
@@ -428,6 +491,40 @@ pytest
--- ---
## Seed Scripts
### httpx Not Installed
**Problem:** Running `python -m scripts.seed_trees` fails with `ModuleNotFoundError: No module named 'httpx'`
**Cause:** The seed script uses `httpx` for async HTTP requests, which isn't in the base requirements.
**Solution:** Install httpx before running seed scripts:
```powershell
pip install httpx
```
---
### Email Validation Rejects .local Domains
**Problem:** Seed script fails with email validation error when using `.local` domain for seed user email.
**Error:** `value is not a valid email address: The part after the @-sign is a special-use or reserved name that cannot be used with email.`
**Cause:** The `email-validator` library (used by Pydantic) correctly rejects `.local` as it's a reserved TLD per RFC 6761.
**Solution:** Use a standard domain like `example.com` for seed/test users:
```python
# BAD
"email": "seed.admin@apoklisis.local"
# GOOD
"email": "seed.admin@example.com"
```
**Files affected:** `backend/scripts/seed_trees.py`, any test fixtures with email addresses
---
## Adding New Lessons ## Adding New Lessons
When you encounter and fix a bug, add it here with: When you encounter and fix a bug, add it here with:

View File

@@ -1,6 +1,6 @@
# Project Apoklisis - Development Progress # Project Apoklisis - Development Progress
**Last Updated**: January 28, 2026 **Last Updated**: January 29, 2026
**Current Phase**: Phase 2 Frontend - COMPLETE & TESTED **Current Phase**: Phase 2 Frontend - COMPLETE & TESTED
--- ---
@@ -427,6 +427,7 @@ frontend/
| `NodePicker.tsx` | Type-grouped dropdown for selecting next_node_id | | `NodePicker.tsx` | Type-grouped dropdown for selecting next_node_id |
| `TreePreviewPanel.tsx` | Visual tree preview with SharedLinksMap | | `TreePreviewPanel.tsx` | Visual tree preview with SharedLinksMap |
| `TreePreviewNode.tsx` | Node cards with solution indicators | | `TreePreviewNode.tsx` | Node cards with solution indicators |
| `MarkdownContent.tsx` | Reusable markdown renderer (react-markdown) |
**Routes Added**: **Routes Added**:
- `/trees/new` - Create new tree - `/trees/new` - Create new tree
@@ -438,27 +439,45 @@ frontend/
- Solution connection indicators (green checkmark badges) - Solution connection indicators (green checkmark badges)
- Shared node detection (shows when multiple nodes link to same target) - Shared node detection (shows when multiple nodes link to same target)
- Modal with scrollable content, fixed header/footer - Modal with scrollable content, fixed header/footer
- **Markdown preview toggle** in description fields
- **Markdown rendering** in session player (decision/action/solution descriptions)
--- ---
## What's Next ## What's Next
### Phase 1b: Pre-built Trees (Partial) ### Phase 1b: Pre-built Trees (COMPLETE)
**Seed Data Script**: `backend/scripts/seed_data.py` **Seed Data Scripts**:
- `backend/scripts/seed_data.py` - Original script
- `backend/scripts/seed_trees.py` - Comprehensive 7-tree seed script (NEW)
**Trees Implemented**: **Trees Implemented** (via `seed_trees.py`):
1. ✅ **Password Reset/Account Lockout** - Full implementation (~15 decision nodes)
2. 🔲 **File Share Access Problems** - Stub created (placeholder nodes) **Tier 1 - Help Desk:**
3. 🔲 FSLogix Profile Issues - Not started 1. ✅ **Password Reset/Account Lockout** - Full implementation (~20 nodes)
4. 🔲 Citrix VDA Registration - Not started 2. ✅ **Outlook/Email Problems** - Complete with MAPI profile, OST, and connectivity checks
5. 🔲 AD Replication Issues - Not started 3. ✅ **VPN Connection Failures** - GlobalProtect, Cisco AnyConnect troubleshooting
4. ✅ **Printer Problems** - Print queue, driver, spooler, network printer diagnostics
**Tier 2 - Desktop Support:**
5. ✅ **Slow Computer Troubleshooting** - Startup, disk, RAM, malware diagnostics
6. ✅ **Network Connectivity Issues** - IP config, DNS, gateway, firewall checks
**Tier 3 - Systems:**
7. ✅ **File Share Access Problems** - Full implementation with NTFS, share permissions, DFS checks
**Each tree features:**
- 10-20+ nodes with realistic branching
- Real PowerShell commands in action nodes
- Professional ticket documentation guidance in solution nodes
- Markdown-formatted descriptions
### Remaining Work ### Remaining Work
1. **Tree Editor Polish**: Validation, required fields, orphan detection 1. **Tree Editor Polish**: Validation, required fields, orphan detection
2. **User Preferences**: Dark mode, export format defaults 2. ~~**User Preferences**: Dark mode, export format defaults~~ Dark mode **COMPLETE**, export format pending
3. **More Trees**: Add remaining 4 trees from `TS-EXAMPLES.md` 3. ~~**More Trees**: Add remaining 4 trees from `TS-EXAMPLES.md`~~ **COMPLETE** - 7 comprehensive trees seeded
4. **Deployment**: Set up CI/CD pipeline and deploy to Render/Railway 4. **Deployment**: Set up CI/CD pipeline and deploy to Render/Railway
--- ---
@@ -481,12 +500,21 @@ frontend/
- ✅ **Integration tests** - 40+ tests with full coverage (all passing) - ✅ **Integration tests** - 40+ tests with full coverage (all passing)
- ✅ **Frontend COMPLETE** - Full React app with all core pages - ✅ **Frontend COMPLETE** - Full React app with all core pages
- ✅ **Tree Editor IMPLEMENTED** - Form-based editing with visual preview - ✅ **Tree Editor IMPLEMENTED** - Form-based editing with visual preview
- ✅ **Markdown Rendering** - Session player and node editor support markdown
- ✅ **7 Seed Trees** - Comprehensive troubleshooting trees across Tier 1/2/3
- ✅ **Full workflow tested** - Register → Login → Browse → Navigate → Complete → Export all working - ✅ **Full workflow tested** - Register → Login → Browse → Navigate → Complete → Export all working
- 📝 **Single-user focus** for MVP (team features are in schema but low priority) - 📝 **Single-user focus** for MVP (team features are in schema but low priority)
### Recommended Next Steps ### Recommended Next Steps
1. **Tree Editor Validation**: Required fields, orphan node detection, save validation 1. ~~**User Preferences**: Dark mode toggle~~ **COMPLETE**
2. **User Preferences**: Dark mode toggle, export format defaults 2. **Tree Editor Validation**: Required fields, orphan node detection, save validation
3. **Add more trees**: Implement remaining 4 trees from `TS-EXAMPLES.md` 3. **Deploy**: Set up CI/CD pipeline and deploy to Render/Railway
4. **Deploy**: Set up CI/CD pipeline and deploy to Render/Railway 4. **Real-world Testing**: Use on actual support tickets
### Recent Additions (Jan 29, 2026)
1. **Seed Script** (`backend/scripts/seed_trees.py`) - 7 comprehensive troubleshooting trees
2. **Markdown Rendering** - `react-markdown` package + `MarkdownContent` component
3. **Preview Toggle** - Description fields in node editor can toggle between edit/preview
4. **LESSONS-LEARNED.md** updated with httpx and email validation fixes

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -17,6 +17,7 @@
"lucide-react": "^0.563.0", "lucide-react": "^0.563.0",
"react": "^19.2.0", "react": "^19.2.0",
"react-dom": "^19.2.0", "react-dom": "^19.2.0",
"react-markdown": "^10.1.0",
"react-router-dom": "^7.13.0", "react-router-dom": "^7.13.0",
"tailwind-merge": "^3.4.0", "tailwind-merge": "^3.4.0",
"zundo": "^2.3.0", "zundo": "^2.3.0",

View File

@@ -1,6 +1,8 @@
import { useState } from 'react'
import { DynamicArrayField } from './DynamicArrayField' import { DynamicArrayField } from './DynamicArrayField'
import { NodePicker } from './NodePicker' import { NodePicker } from './NodePicker'
import { useTreeEditorStore } from '@/store/treeEditorStore' import { useTreeEditorStore } from '@/store/treeEditorStore'
import { MarkdownContent } from '@/components/ui/MarkdownContent'
import type { TreeStructure } from '@/types' import type { TreeStructure } from '@/types'
import { cn } from '@/lib/utils' import { cn } from '@/lib/utils'
@@ -11,6 +13,7 @@ interface NodeFormActionProps {
export function NodeFormAction({ node, onUpdate }: NodeFormActionProps) { export function NodeFormAction({ node, onUpdate }: NodeFormActionProps) {
const { validationErrors } = useTreeEditorStore() const { validationErrors } = useTreeEditorStore()
const [showPreview, setShowPreview] = useState(false)
const titleError = validationErrors.find( const titleError = validationErrors.find(
e => e.nodeId === node.id && e.field === 'title' e => e.nodeId === node.id && e.field === 'title'
@@ -71,20 +74,46 @@ export function NodeFormAction({ node, onUpdate }: NodeFormActionProps) {
{/* Description */} {/* Description */}
<div> <div>
<label className="block text-sm font-medium text-foreground"> <div className="flex items-center justify-between">
Description <label className="block text-sm font-medium text-foreground">
</label> Description
<textarea </label>
value={node.description || ''} {node.description && (
onChange={(e) => onUpdate({ description: e.target.value })} <button
placeholder="Detailed instructions for this action..." type="button"
rows={3} onClick={() => setShowPreview(!showPreview)}
className={cn( className="text-xs text-primary hover:underline"
'mt-1 block w-full rounded-md border border-input px-3 py-2 text-sm', >
'bg-background text-foreground placeholder:text-muted-foreground', {showPreview ? 'Edit' : 'Preview'}
'focus:border-primary focus:outline-none focus:ring-1 focus:ring-primary' </button>
)} )}
/> </div>
<p className="mb-1 text-xs text-muted-foreground">
Supports markdown: **bold**, *italic*, - lists, 1. numbered lists, `code`
</p>
{showPreview && node.description ? (
<div className="mt-1 rounded-md border border-input bg-muted/50 p-3 text-sm">
<MarkdownContent content={node.description} />
</div>
) : (
<textarea
value={node.description || ''}
onChange={(e) => onUpdate({ description: e.target.value })}
placeholder="Detailed instructions for this action...
**Example formatting:**
1. First step
2. Second step
**Note:** Important information here"
rows={5}
className={cn(
'mt-1 block w-full rounded-md border border-input px-3 py-2 text-sm',
'bg-background text-foreground placeholder:text-muted-foreground',
'focus:border-primary focus:outline-none focus:ring-1 focus:ring-primary'
)}
/>
)}
</div> </div>
{/* Commands */} {/* Commands */}

View File

@@ -1,5 +1,7 @@
import { useState } from 'react'
import { DynamicArrayField } from './DynamicArrayField' import { DynamicArrayField } from './DynamicArrayField'
import { useTreeEditorStore } from '@/store/treeEditorStore' import { useTreeEditorStore } from '@/store/treeEditorStore'
import { MarkdownContent } from '@/components/ui/MarkdownContent'
import type { TreeStructure } from '@/types' import type { TreeStructure } from '@/types'
import { cn } from '@/lib/utils' import { cn } from '@/lib/utils'
@@ -10,6 +12,7 @@ interface NodeFormResolutionProps {
export function NodeFormResolution({ node, onUpdate }: NodeFormResolutionProps) { export function NodeFormResolution({ node, onUpdate }: NodeFormResolutionProps) {
const { validationErrors } = useTreeEditorStore() const { validationErrors } = useTreeEditorStore()
const [showPreview, setShowPreview] = useState(false)
const titleError = validationErrors.find( const titleError = validationErrors.find(
e => e.nodeId === node.id && e.field === 'title' e => e.nodeId === node.id && e.field === 'title'
@@ -66,20 +69,45 @@ export function NodeFormResolution({ node, onUpdate }: NodeFormResolutionProps)
{/* Description */} {/* Description */}
<div> <div>
<label className="block text-sm font-medium text-foreground"> <div className="flex items-center justify-between">
Description <label className="block text-sm font-medium text-foreground">
</label> Description
<textarea </label>
value={node.description || ''} {node.description && (
onChange={(e) => onUpdate({ description: e.target.value })} <button
placeholder="Summary of the resolution and any follow-up recommendations..." type="button"
rows={3} onClick={() => setShowPreview(!showPreview)}
className={cn( className="text-xs text-primary hover:underline"
'mt-1 block w-full rounded-md border border-input px-3 py-2 text-sm', >
'bg-background text-foreground placeholder:text-muted-foreground', {showPreview ? 'Edit' : 'Preview'}
'focus:border-primary focus:outline-none focus:ring-1 focus:ring-primary' </button>
)} )}
/> </div>
<p className="mb-1 text-xs text-muted-foreground">
Supports markdown: **bold**, *italic*, - lists, 1. numbered lists, `code`
</p>
{showPreview && node.description ? (
<div className="mt-1 rounded-md border border-input bg-muted/50 p-3 text-sm">
<MarkdownContent content={node.description} />
</div>
) : (
<textarea
value={node.description || ''}
onChange={(e) => onUpdate({ description: e.target.value })}
placeholder="Summary of the resolution and any follow-up recommendations...
**Ticket Notes:**
Document what was done and the outcome.
**Close ticket as:** Resolved"
rows={5}
className={cn(
'mt-1 block w-full rounded-md border border-input px-3 py-2 text-sm',
'bg-background text-foreground placeholder:text-muted-foreground',
'focus:border-primary focus:outline-none focus:ring-1 focus:ring-primary'
)}
/>
)}
</div> </div>
{/* Resolution Steps */} {/* Resolution Steps */}

View File

@@ -0,0 +1,94 @@
import ReactMarkdown from 'react-markdown'
import { cn } from '@/lib/utils'
interface MarkdownContentProps {
content: string
className?: string
}
/**
* Renders markdown content with proper styling.
* Supports: bold, italic, lists, code blocks, headers, etc.
*/
export function MarkdownContent({ content, className }: MarkdownContentProps) {
return (
<div className={cn('prose prose-sm dark:prose-invert max-w-none', className)}>
<ReactMarkdown
components={{
// Style paragraphs
p: ({ children }) => (
<p className="mb-3 last:mb-0">{children}</p>
),
// Style bold text
strong: ({ children }) => (
<strong className="font-semibold text-foreground">{children}</strong>
),
// Style ordered lists
ol: ({ children }) => (
<ol className="mb-3 ml-4 list-decimal space-y-1 last:mb-0">{children}</ol>
),
// Style unordered lists
ul: ({ children }) => (
<ul className="mb-3 ml-4 list-disc space-y-1 last:mb-0">{children}</ul>
),
// Style list items
li: ({ children }) => (
<li className="text-muted-foreground">{children}</li>
),
// Style inline code
code: ({ className, children, ...props }) => {
// Check if it's a code block (has language class) or inline code
const isBlock = className?.includes('language-')
if (isBlock) {
return (
<code
className={cn(
'block rounded bg-muted p-3 font-mono text-sm overflow-x-auto',
className
)}
{...props}
>
{children}
</code>
)
}
return (
<code
className="rounded bg-muted px-1.5 py-0.5 font-mono text-sm"
{...props}
>
{children}
</code>
)
},
// Style code blocks (pre)
pre: ({ children }) => (
<pre className="mb-3 overflow-x-auto rounded bg-muted p-0 last:mb-0">
{children}
</pre>
),
// Style headers
h1: ({ children }) => (
<h1 className="mb-3 text-lg font-bold text-foreground">{children}</h1>
),
h2: ({ children }) => (
<h2 className="mb-2 text-base font-bold text-foreground">{children}</h2>
),
h3: ({ children }) => (
<h3 className="mb-2 text-sm font-bold text-foreground">{children}</h3>
),
// Style horizontal rules
hr: () => <hr className="my-4 border-border" />,
// Style blockquotes
blockquote: ({ children }) => (
<blockquote className="mb-3 border-l-4 border-primary/50 pl-4 italic text-muted-foreground last:mb-0">
{children}
</blockquote>
),
}}
>
{content}
</ReactMarkdown>
</div>
)
}

View File

@@ -4,6 +4,7 @@ import { treesApi, sessionsApi } from '@/api'
import { useTreeNavigationShortcuts } from '@/hooks/useKeyboardShortcuts' import { useTreeNavigationShortcuts } from '@/hooks/useKeyboardShortcuts'
import type { Tree, Session, DecisionRecord, TreeStructure } from '@/types' import type { Tree, Session, DecisionRecord, TreeStructure } from '@/types'
import { cn } from '@/lib/utils' import { cn } from '@/lib/utils'
import { MarkdownContent } from '@/components/ui/MarkdownContent'
interface LocationState { interface LocationState {
sessionId?: string sessionId?: string
@@ -380,7 +381,9 @@ export function TreeNavigationPage() {
{currentNode.question} {currentNode.question}
</h2> </h2>
{currentNode.help_text && ( {currentNode.help_text && (
<p className="mb-4 text-sm text-muted-foreground">{currentNode.help_text}</p> <div className="mb-4 text-sm text-muted-foreground">
<MarkdownContent content={currentNode.help_text} />
</div>
)} )}
<div className="mb-4 space-y-2"> <div className="mb-4 space-y-2">
{currentNode.options?.map((option, index) => ( {currentNode.options?.map((option, index) => (
@@ -411,7 +414,11 @@ export function TreeNavigationPage() {
<h2 className="mb-2 text-xl font-semibold text-card-foreground"> <h2 className="mb-2 text-xl font-semibold text-card-foreground">
{currentNode.title} {currentNode.title}
</h2> </h2>
<p className="mb-4 text-muted-foreground">{currentNode.description}</p> {currentNode.description && (
<div className="mb-4 text-muted-foreground">
<MarkdownContent content={currentNode.description} />
</div>
)}
{currentNode.commands && currentNode.commands.length > 0 && ( {currentNode.commands && currentNode.commands.length > 0 && (
<div className="mb-4"> <div className="mb-4">
<p className="mb-2 text-sm font-medium text-foreground">Commands:</p> <p className="mb-2 text-sm font-medium text-foreground">Commands:</p>
@@ -457,7 +464,11 @@ export function TreeNavigationPage() {
<h2 className="mb-2 text-xl font-semibold text-card-foreground"> <h2 className="mb-2 text-xl font-semibold text-card-foreground">
{currentNode.title} {currentNode.title}
</h2> </h2>
<p className="mb-4 text-muted-foreground">{currentNode.description}</p> {currentNode.description && (
<div className="mb-4 text-muted-foreground">
<MarkdownContent content={currentNode.description} />
</div>
)}
{currentNode.resolution_steps && currentNode.resolution_steps.length > 0 && ( {currentNode.resolution_steps && currentNode.resolution_steps.length > 0 && (
<div className="mb-4"> <div className="mb-4">
<p className="mb-2 text-sm font-medium text-foreground">Resolution steps:</p> <p className="mb-2 text-sm font-medium text-foreground">Resolution steps:</p>