Files
Atomizer/docs/plans/CANVAS_UX_IMPROVEMENTS.md
Anto01 a3f18dc377 chore: Project cleanup and Canvas UX improvements (Phase 7-9)
## Cleanup (v0.5.0)
- Delete 102+ orphaned MCP session temp files
- Remove build artifacts (htmlcov, dist, __pycache__)
- Archive superseded plan docs (RALPH_LOOP V2/V3, CANVAS V3, etc.)
- Move debug/analysis scripts from tests/ to tools/analysis/
- Archive redundant NX journals to archive/nx_journals/
- Archive monolithic PROTOCOL.md to docs/archive/
- Update .gitignore with missing patterns
- Clean old study files (optimization_log_old.txt, run_optimization_old.py)

## Canvas UX (Phases 7-9)
- Phase 7: Resizable panels with localStorage persistence
  - Left sidebar: 200-400px, Right panel: 280-600px
  - New useResizablePanel hook and ResizeHandle component
- Phase 8: Enable all palette items
  - All 8 node types now draggable
  - Singleton logic for model/solver/algorithm/surrogate
- Phase 9: Solver configuration
  - Add SolverEngine type (nxnastran, mscnastran, python, etc.)
  - Add NastranSolutionType (SOL101-SOL200)
  - Engine/solution dropdowns in config panel
  - Python script path support

## Documentation
- Update CHANGELOG.md with recent versions
- Update docs/00_INDEX.md
- Create examples/README.md
- Add docs/plans/CANVAS_UX_IMPROVEMENTS.md
2026-01-24 15:17:34 -05:00

446 lines
12 KiB
Markdown

# Canvas UX Improvements - Master Plan
**Created:** January 2026
**Status:** Planning
**Branch:** `feature/studio-enhancement`
## Overview
This plan addresses three major UX issues in the Canvas Builder:
1. **Resizable Panels** - Right pane (chat/config) is fixed at 384px, cannot be adjusted
2. **Disabled Palette Items** - Model, Solver, Algorithm, Surrogate are grayed out and not draggable
3. **Solver Type Selection** - Solver node should allow selection of solver type (NX Nastran, Python, etc.)
---
## Phase 7: Resizable Panels
### Current State
- Left sidebar: Fixed 240px (expanded) or 56px (collapsed)
- Right panel (Chat/Config): Fixed 384px
- Canvas: Takes remaining space
### Requirements
- Users should be able to drag panel edges to resize
- Minimum/maximum constraints for usability
- Persist panel sizes in localStorage
- Smooth resize with proper cursor feedback
### Implementation
#### 7.1 Create Resizable Panel Hook
```typescript
// hooks/useResizablePanel.ts
interface ResizablePanelState {
width: number;
isDragging: boolean;
startDrag: (e: React.MouseEvent) => void;
}
function useResizablePanel(
key: string,
defaultWidth: number,
minWidth: number,
maxWidth: number
): ResizablePanelState
```
#### 7.2 Update CanvasView Layout
- Wrap left sidebar with resizer
- Wrap right panel with resizer
- Add visual drag handles (thin border that highlights on hover)
- Add cursor: col-resize on hover
#### 7.3 Files to Modify
| File | Changes |
|------|---------|
| `hooks/useResizablePanel.ts` | NEW - Resize hook with localStorage persistence |
| `pages/CanvasView.tsx` | Add resizers to left/right panels |
| `components/canvas/ResizeHandle.tsx` | NEW - Visual resize handle component |
#### 7.4 Constraints
| Panel | Min | Default | Max |
|-------|-----|---------|-----|
| Left (Palette/Files) | 200px | 240px | 400px |
| Right (Chat/Config) | 280px | 384px | 600px |
---
## Phase 8: Enable All Palette Items
### Current State
- Model, Solver, Algorithm, Surrogate are marked `canAdd: false`
- They appear grayed out with "Auto-created" text
- Users cannot drag them to canvas
### Problem Analysis
These nodes were marked as "synthetic" because they're derived from:
- **Model**: From `spec.model.sim.path`
- **Solver**: From model's solution type
- **Algorithm**: From `spec.optimization.algorithm`
- **Surrogate**: From `spec.optimization.surrogate`
However, users need to:
1. Add a Model node when creating a new study from scratch
2. Configure the Solver type
3. Choose an Algorithm
4. Enable/configure Surrogate
### Solution: Make All Items Draggable
#### 8.1 Update NodePalette
```typescript
// All items should be draggable
export const PALETTE_ITEMS: PaletteItem[] = [
{
type: 'model',
label: 'Model',
canAdd: true, // Changed from false
description: 'NX/FEM model file',
},
{
type: 'solver',
label: 'Solver',
canAdd: true, // Changed from false
description: 'Analysis solver',
},
// ... etc
];
```
#### 8.2 Handle "Singleton" Nodes
Some nodes should only exist once on the canvas:
- Model (only one model per study)
- Solver (one solver)
- Algorithm (one algorithm config)
- Surrogate (optional, one)
When user drags a singleton that already exists:
- Option A: Show warning toast "Model already exists"
- Option B: Select the existing node instead of creating new
- **Recommended**: Option B (select existing)
#### 8.3 Update SpecRenderer Drop Handler
```typescript
const onDrop = useCallback(async (event: DragEvent) => {
const type = event.dataTransfer.getData('application/reactflow');
// Check if singleton already exists
const SINGLETON_TYPES = ['model', 'solver', 'algorithm', 'surrogate'];
if (SINGLETON_TYPES.includes(type)) {
const existingNode = nodes.find(n => n.type === type);
if (existingNode) {
selectNode(existingNode.id);
showNotification(`${type} already exists - selected it`);
return;
}
}
// Create new node...
}, [...]);
```
#### 8.4 Default Data for New Node Types
```typescript
function getDefaultNodeData(type: NodeType, position) {
switch (type) {
case 'model':
return {
name: 'Model',
sim: { path: '', solver: 'nastran' },
canvas_position: position,
};
case 'solver':
return {
name: 'Solver',
type: 'nxnastran', // Default solver
solution_type: 'SOL101',
canvas_position: position,
};
case 'algorithm':
return {
name: 'Algorithm',
type: 'TPE',
budget: { max_trials: 100 },
canvas_position: position,
};
case 'surrogate':
return {
name: 'Surrogate',
enabled: false,
model_type: 'MLP',
min_trials: 20,
canvas_position: position,
};
// ... existing cases
}
}
```
#### 8.5 Files to Modify
| File | Changes |
|------|---------|
| `components/canvas/palette/NodePalette.tsx` | Set `canAdd: true` for all items |
| `components/canvas/SpecRenderer.tsx` | Handle singleton logic in onDrop |
| `lib/spec/converter.ts` | Ensure synthetic nodes have proper IDs |
| `hooks/useSpecStore.ts` | Add model/solver/algorithm to addNode support |
---
## Phase 9: Solver Type Selection
### Current State
- Solver node shows auto-detected solution type (SOL101, etc.)
- No ability to change solver engine or configure it
### Requirements
1. Allow selection of solver engine type
2. Configure solution type
3. Support future solver types
### Solver Types to Support
| Solver | Description | Status |
|--------|-------------|--------|
| `nxnastran` | NX Nastran (built-in) | Current |
| `mscnastran` | MSC Nastran (external) | Future |
| `python` | Python-based solver | Future |
| `abaqus` | Abaqus (via Python API) | Future |
| `ansys` | ANSYS (via Python API) | Future |
### Solution Types per Solver
**NX Nastran / MSC Nastran:**
- SOL101 - Linear Static
- SOL103 - Normal Modes
- SOL105 - Buckling
- SOL106 - Nonlinear Static
- SOL111 - Frequency Response
- SOL112 - Transient Response
- SOL200 - Design Optimization
**Python Solver:**
- Custom (user-defined)
### Schema Updates
#### 9.1 Update AtomizerSpec Types
```typescript
// types/atomizer-spec.ts
export type SolverEngine =
| 'nxnastran'
| 'mscnastran'
| 'python'
| 'abaqus'
| 'ansys';
export type NastranSolutionType =
| 'SOL101'
| 'SOL103'
| 'SOL105'
| 'SOL106'
| 'SOL111'
| 'SOL112'
| 'SOL200';
export interface SolverConfig {
/** Solver engine type */
engine: SolverEngine;
/** Solution type (for Nastran) */
solution_type?: NastranSolutionType;
/** Custom solver script path (for Python solver) */
script_path?: string;
/** Additional solver options */
options?: Record<string, unknown>;
}
export interface Model {
sim?: {
path: string;
solver: SolverConfig; // Changed from just 'nastran' string
};
// ...
}
```
#### 9.2 Update SolverNode Component
```typescript
// components/canvas/nodes/SolverNode.tsx
function SolverNodeComponent(props: NodeProps<SolverNodeData>) {
const { data } = props;
return (
<BaseNode {...props} icon={<Cpu size={16} />} iconColor="text-violet-400">
<div className="flex flex-col gap-1">
<span className="text-sm font-medium">{data.engine || 'nxnastran'}</span>
<span className="text-xs text-dark-400">
{data.solution_type || 'Auto-detect'}
</span>
</div>
</BaseNode>
);
}
```
#### 9.3 Solver Configuration Panel
Add to `NodeConfigPanelV2.tsx`:
```typescript
function SolverNodeConfig({ spec }: SpecConfigProps) {
const { patchSpec } = useSpecStore();
const solver = spec.model?.sim?.solver || { engine: 'nxnastran' };
const handleEngineChange = (engine: SolverEngine) => {
patchSpec('model.sim.solver.engine', engine);
};
const handleSolutionTypeChange = (type: NastranSolutionType) => {
patchSpec('model.sim.solver.solution_type', type);
};
return (
<>
<div>
<label className={labelClass}>Solver Engine</label>
<select
value={solver.engine}
onChange={(e) => handleEngineChange(e.target.value as SolverEngine)}
className={selectClass}
>
<option value="nxnastran">NX Nastran</option>
<option value="mscnastran">MSC Nastran</option>
<option value="python">Python Script</option>
</select>
</div>
{(solver.engine === 'nxnastran' || solver.engine === 'mscnastran') && (
<div>
<label className={labelClass}>Solution Type</label>
<select
value={solver.solution_type || ''}
onChange={(e) => handleSolutionTypeChange(e.target.value as NastranSolutionType)}
className={selectClass}
>
<option value="">Auto-detect from model</option>
<option value="SOL101">SOL101 - Linear Static</option>
<option value="SOL103">SOL103 - Normal Modes</option>
<option value="SOL105">SOL105 - Buckling</option>
<option value="SOL106">SOL106 - Nonlinear Static</option>
<option value="SOL111">SOL111 - Frequency Response</option>
<option value="SOL112">SOL112 - Transient Response</option>
</select>
</div>
)}
{solver.engine === 'python' && (
<div>
<label className={labelClass}>Solver Script</label>
<input
type="text"
value={solver.script_path || ''}
onChange={(e) => patchSpec('model.sim.solver.script_path', e.target.value)}
placeholder="/path/to/solver.py"
className={inputClass}
/>
<p className="text-xs text-dark-500 mt-1">
Python script that runs the analysis
</p>
</div>
)}
</>
);
}
```
#### 9.4 Files to Modify
| File | Changes |
|------|---------|
| `types/atomizer-spec.ts` | Add SolverEngine, SolverConfig types |
| `components/canvas/nodes/SolverNode.tsx` | Show engine and solution type |
| `components/canvas/panels/NodeConfigPanelV2.tsx` | Add SolverNodeConfig |
| `lib/canvas/schema.ts` | Update SolverNodeData |
| Backend: `config/spec_models.py` | Add SolverConfig Pydantic model |
---
## Implementation Order
| Phase | Effort | Priority | Dependencies |
|-------|--------|----------|--------------|
| **7.1** Resizable Panel Hook | 2h | High | None |
| **7.2** CanvasView Resizers | 2h | High | 7.1 |
| **8.1** Enable Palette Items | 1h | High | None |
| **8.2** Singleton Logic | 2h | High | 8.1 |
| **8.3** Default Node Data | 1h | High | 8.2 |
| **9.1** Schema Updates | 2h | Medium | None |
| **9.2** SolverNode UI | 1h | Medium | 9.1 |
| **9.3** Solver Config Panel | 2h | Medium | 9.1, 9.2 |
**Total Estimated Effort:** ~13 hours
---
## Success Criteria
### Phase 7 (Resizable Panels)
- [ ] Left panel can be resized between 200-400px
- [ ] Right panel can be resized between 280-600px
- [ ] Resize handles show cursor feedback
- [ ] Panel sizes persist across page reload
- [ ] Double-click on handle resets to default
### Phase 8 (Enable Palette Items)
- [ ] All 8 node types are draggable from palette
- [ ] Dragging singleton to canvas with existing node selects existing
- [ ] Toast notification explains the behavior
- [ ] New studies can start with empty canvas and add Model first
### Phase 9 (Solver Selection)
- [ ] Solver node shows engine type (nxnastran, python, etc.)
- [ ] Clicking solver node opens config panel
- [ ] Can select solver engine from dropdown
- [ ] Nastran solvers show solution type dropdown
- [ ] Python solver shows script path input
- [ ] Changes persist to atomizer_spec.json
---
## Future Considerations
### Additional Solver Support
- ANSYS integration via pyANSYS
- Abaqus integration via abaqus-python
- OpenFOAM for CFD
- Custom Python solvers with standardized interface
### Multi-Solver Workflows
- Support for chained solvers (thermal → structural)
- Co-simulation workflows
- Parallel solver execution
### Algorithm Node Enhancement
- Similar to Solver, allow algorithm selection
- Show algorithm-specific parameters
- Support custom algorithms
---
## Commit Strategy
```bash
# Phase 7
git commit -m "feat: Add resizable panels to canvas view"
# Phase 8
git commit -m "feat: Enable all palette items with singleton handling"
# Phase 9
git commit -m "feat: Add solver type selection and configuration"
```