mirror of
https://github.com/The-Low-Code-Foundation/OpenNoodl.git
synced 2026-01-12 07:12:54 +01:00
797 lines
22 KiB
Markdown
797 lines
22 KiB
Markdown
# TASK-008: ComponentsPanel Menu Enhancements & Sheet System
|
|
|
|
## ✅ CURRENT STATUS: COMPLETE
|
|
|
|
**Last Updated:** January 3, 2026
|
|
**Status:** ✅ COMPLETE
|
|
**Completion:** 100%
|
|
|
|
### Quick Summary
|
|
|
|
All ComponentsPanel features successfully implemented and working:
|
|
|
|
- ✅ Enhanced context menus with "Create" submenus - COMPLETE
|
|
- ✅ Sheet system backend (detection, filtering, management) - COMPLETE
|
|
- ✅ Sheet selector UI with dropdown - COMPLETE
|
|
- ✅ Sheet management actions wired up - COMPLETE
|
|
|
|
**Predecessor:** TASK-004B (ComponentsPanel React Migration) - COMPLETE ✅
|
|
|
|
### Completed Phases
|
|
|
|
**Phase 1: Enhanced Context Menus** ✅
|
|
|
|
- Create menu items in component/folder right-click menus
|
|
- All component templates + folder creation accessible
|
|
|
|
**Phase 2: Sheet System Backend** ✅ (December 27, 2025)
|
|
|
|
- Sheet detection from `#`-prefixed folders
|
|
- `useComponentsPanel` now exports: `sheets`, `currentSheet`, `selectSheet`
|
|
- Tree filtering by selected sheet
|
|
- `useSheetManagement` hook with full CRUD operations
|
|
- All operations with undo support
|
|
|
|
**Phase 3: Sheet Selector UI** ✅ (January 3, 2026)
|
|
|
|
- Sheet dropdown component with modern design
|
|
- Sheet list with selection indicator
|
|
- Three-dot menu for rename/delete actions
|
|
- Smooth animations and proper z-index layering
|
|
|
|
**Phase 4: Sheet Management Actions** ✅ (January 3, 2026)
|
|
|
|
- Create sheet with validation and undo support
|
|
- Rename sheet with component path updates
|
|
- Delete sheet with confirmation dialog
|
|
- All operations integrated with UndoQueue
|
|
|
|
**TASK-008C: Drag-Drop System** ✅
|
|
|
|
- All 7 drop combinations working
|
|
- Root drop zone implemented
|
|
|
|
---
|
|
|
|
## Overview
|
|
|
|
TASK-004B successfully migrated the ComponentsPanel to React, but several features from the legacy implementation were intentionally deferred. This task completes the ComponentsPanel by adding:
|
|
|
|
1. **Enhanced Context Menus**: Add "Create" submenus to component and folder right-click menus
|
|
2. **Sheet System UI**: Implement dropdown selector for managing component sheets
|
|
3. **Sheet Management**: Full CRUD operations for sheets with undo support
|
|
|
|
**Phase:** 2 (Runtime Migration System)
|
|
**Priority:** MEDIUM (UX enhancement, not blocking)
|
|
**Effort:** 8-12 hours
|
|
**Risk:** Low (foundation already stable)
|
|
|
|
---
|
|
|
|
## Background
|
|
|
|
### What Are Sheets?
|
|
|
|
Sheets are a way to organize components into top-level groups:
|
|
|
|
- **Sheet Folders**: Top-level folders with names starting with `#` (e.g., `#CloudFunctions`, `#Pages`)
|
|
- **Default Sheet**: All components not in a `#` folder
|
|
- **Special Sheets**: Some sheets can be hidden (e.g., `__cloud__` sheet)
|
|
|
|
### Current State
|
|
|
|
After TASK-004B completion, the React ComponentsPanel has:
|
|
|
|
**✅ Working:**
|
|
|
|
- Basic tree rendering with folders/components
|
|
- Component selection and navigation
|
|
- Expand/collapse folders
|
|
- Basic context menus (Make Home, Rename, Duplicate, Delete)
|
|
- Drag-drop for organizing components
|
|
- Root folder transparency (no unnamed folder)
|
|
|
|
**❌ Missing:**
|
|
|
|
- "Create" submenus in context menus
|
|
- Sheet selector UI (currently no way to see/switch sheets)
|
|
- Sheet creation/deletion/rename
|
|
- Visual indication of current sheet
|
|
|
|
### Legacy Implementation
|
|
|
|
The legacy `ComponentsPanel.ts.legacy` shows:
|
|
|
|
- Full context menu system with "Create" submenus
|
|
- Sheet selector bar with tabs
|
|
- Sheet management actions (add, rename, delete)
|
|
- Sheet drag-drop support
|
|
|
|
---
|
|
|
|
## Goals
|
|
|
|
1. **Enhanced Context Menus** - Add "Create" submenus with all component types + folder
|
|
2. **Sheet Dropdown UI** - Replace legacy tab bar with modern dropdown selector
|
|
3. **Sheet Management** - Full create/rename/delete with undo support
|
|
4. **Sheet Filtering** - Show only components in selected sheet
|
|
5. **TypeScript Throughout** - Proper typing, no TSFixme
|
|
|
|
---
|
|
|
|
## Architecture
|
|
|
|
### Component Structure
|
|
|
|
```
|
|
ComponentsPanel/
|
|
├── ComponentsPanelReact.tsx # Add sheet selector UI
|
|
├── components/
|
|
│ ├── ComponentTree.tsx # Enhance context menus
|
|
│ ├── ComponentItem.tsx # Update menu items
|
|
│ ├── FolderItem.tsx # Update menu items
|
|
│ └── SheetSelector.tsx # NEW: Dropdown for sheets
|
|
├── hooks/
|
|
│ ├── useComponentsPanel.ts # Add sheet filtering
|
|
│ ├── useComponentActions.ts # Add sheet actions
|
|
│ └── useSheetManagement.ts # NEW: Sheet operations
|
|
└── types.ts # Add sheet types
|
|
```
|
|
|
|
### State Management
|
|
|
|
**Sheet State (in useComponentsPanel):**
|
|
|
|
- `currentSheet: ComponentsPanelFolder | null` - Active sheet
|
|
- `sheets: ComponentsPanelFolder[]` - All available sheets
|
|
- `selectSheet(sheet)` - Switch to a sheet
|
|
- `filterBySheet(sheet)` - Filter tree to show only sheet components
|
|
|
|
**Sheet Actions (in useSheetManagement):**
|
|
|
|
- `createSheet(name)` - Create new sheet with undo
|
|
- `renameSheet(sheet, newName)` - Rename sheet with undo
|
|
- `deleteSheet(sheet)` - Delete sheet with confirmation + undo
|
|
- `moveToSheet(item, targetSheet)` - Move component/folder to sheet
|
|
|
|
---
|
|
|
|
## Implementation Phases
|
|
|
|
### Phase 1: Enhanced Context Menus (2-3 hours)
|
|
|
|
Add "Create" submenus to existing context menus.
|
|
|
|
**Files to Modify:**
|
|
|
|
- `components/ComponentItem.tsx` - Add "Create" submenu before divider
|
|
- `components/FolderItem.tsx` - Add "Create" submenu before divider
|
|
- `hooks/useComponentActions.ts` - Already has `handleAddComponent` and `handleAddFolder`
|
|
|
|
**Tasks:**
|
|
|
|
1. **Check PopupMenu Submenu Support**
|
|
|
|
- Read PopupMenu source to see if nested menus are supported
|
|
- If not, may need to enhance PopupMenu or use alternative approach
|
|
|
|
2. **Add "Create" Submenu to Component Context Menu**
|
|
|
|
- Position: After "Make Home", before "Rename"
|
|
- Items:
|
|
- Page (template)
|
|
- Visual Component (template)
|
|
- Logic Component (template)
|
|
- Cloud Function (template)
|
|
- Divider
|
|
- Folder
|
|
- Each item calls `handleAddComponent(template, parentPath)`
|
|
|
|
3. **Add "Create" Submenu to Folder Context Menu**
|
|
|
|
- Same items as component menu
|
|
- Parent path is folder path
|
|
|
|
4. **Wire Up Template Selection**
|
|
- Get templates from `ComponentTemplates.instance.getTemplates()`
|
|
- Filter by runtime type (browser vs cloud)
|
|
- Pass correct parent path to popup
|
|
|
|
**Success Criteria:**
|
|
|
|
- [ ] Component right-click shows "Create" submenu
|
|
- [ ] Folder right-click shows "Create" submenu
|
|
- [ ] All 4 component templates + folder appear in submenu
|
|
- [ ] Clicking template opens creation popup at correct path
|
|
- [ ] All operations support undo/redo
|
|
|
|
### Phase 2: Sheet System Backend (2 hours)
|
|
|
|
Implement sheet detection and filtering logic.
|
|
|
|
**Files to Create:**
|
|
|
|
- `hooks/useSheetManagement.ts` - Sheet operations hook
|
|
|
|
**Files to Modify:**
|
|
|
|
- `hooks/useComponentsPanel.ts` - Add sheet filtering
|
|
|
|
**Tasks:**
|
|
|
|
1. **Sheet Detection in useComponentsPanel**
|
|
|
|
```typescript
|
|
// Identify sheets from projectFolder.folders
|
|
const sheets = useMemo(() => {
|
|
const allSheets = [{ name: 'Default', folder: projectFolder, isDefault: true }];
|
|
|
|
projectFolder.folders
|
|
.filter((f) => f.name.startsWith('#'))
|
|
.forEach((f) => {
|
|
allSheets.push({
|
|
name: f.name.substring(1), // Remove # prefix
|
|
folder: f,
|
|
isDefault: false
|
|
});
|
|
});
|
|
|
|
// Filter out hidden sheets
|
|
return allSheets.filter((s) => !hideSheets?.includes(s.name));
|
|
}, [projectFolder, hideSheets]);
|
|
```
|
|
|
|
2. **Current Sheet State**
|
|
|
|
```typescript
|
|
const [currentSheet, setCurrentSheet] = useState(() => {
|
|
// Default to first non-hidden sheet
|
|
return sheets[0] || null;
|
|
});
|
|
```
|
|
|
|
3. **Sheet Filtering**
|
|
|
|
```typescript
|
|
const filteredTreeData = useMemo(() => {
|
|
if (!currentSheet) return treeData;
|
|
if (currentSheet.isDefault) {
|
|
// Show components not in any # folder
|
|
return filterNonSheetComponents(treeData);
|
|
} else {
|
|
// Show only components in this sheet's folder
|
|
return filterSheetComponents(treeData, currentSheet.folder);
|
|
}
|
|
}, [treeData, currentSheet]);
|
|
```
|
|
|
|
4. **Create useSheetManagement Hook**
|
|
- `createSheet(name)` - Create `#SheetName` folder
|
|
- `renameSheet(sheet, newName)` - Rename folder with component path updates
|
|
- `deleteSheet(sheet)` - Delete folder and all components (with confirmation)
|
|
- All operations use `UndoQueue.pushAndDo()` pattern
|
|
|
|
**Success Criteria:**
|
|
|
|
- [ ] Sheets correctly identified from folder structure
|
|
- [ ] Current sheet state maintained
|
|
- [ ] Tree data filtered by selected sheet
|
|
- [ ] Sheet CRUD operations with undo support
|
|
|
|
### Phase 3: Sheet Selector UI (2-3 hours)
|
|
|
|
Create dropdown component for sheet selection.
|
|
|
|
**Files to Create:**
|
|
|
|
- `components/SheetSelector.tsx` - Dropdown component
|
|
- `components/SheetSelector.module.scss` - Styles
|
|
|
|
**Component Structure:**
|
|
|
|
```typescript
|
|
interface SheetSelectorProps {
|
|
sheets: Sheet[];
|
|
currentSheet: Sheet | null;
|
|
onSelectSheet: (sheet: Sheet) => void;
|
|
onCreateSheet: () => void;
|
|
onRenameSheet: (sheet: Sheet) => void;
|
|
onDeleteSheet: (sheet: Sheet) => void;
|
|
}
|
|
|
|
export function SheetSelector({
|
|
sheets,
|
|
currentSheet,
|
|
onSelectSheet,
|
|
onCreateSheet,
|
|
onRenameSheet,
|
|
onDeleteSheet
|
|
}: SheetSelectorProps) {
|
|
// Dropdown implementation
|
|
}
|
|
```
|
|
|
|
**UI Design:**
|
|
|
|
```
|
|
┌─────────────────────────────────┐
|
|
│ Components ▼ [Default] │ ← Header with dropdown
|
|
├─────────────────────────────────┤
|
|
│ Click dropdown: │
|
|
│ ┌─────────────────────────────┐ │
|
|
│ │ ● Default │ │
|
|
│ │ Pages │ │
|
|
│ │ Components │ │
|
|
│ │ ──────────────── │ │
|
|
│ │ + Add Sheet │ │
|
|
│ └─────────────────────────────┘ │
|
|
└─────────────────────────────────┘
|
|
```
|
|
|
|
**Tasks:**
|
|
|
|
1. **Create SheetSelector Component**
|
|
|
|
- Button showing current sheet name with dropdown icon
|
|
- Click opens dropdown menu
|
|
- List of all sheets with selection indicator
|
|
- "Add Sheet" button at bottom
|
|
|
|
2. **Sheet List Item with Actions**
|
|
|
|
- Sheet name
|
|
- Three-dot menu for rename/delete
|
|
- Cannot delete "Default" sheet
|
|
- Click sheet name to switch
|
|
|
|
3. **Integrate into ComponentsPanelReact**
|
|
|
|
```tsx
|
|
<div className={css['Header']}>
|
|
<span className={css['Title']}>Components</span>
|
|
<SheetSelector
|
|
sheets={sheets}
|
|
currentSheet={currentSheet}
|
|
onSelectSheet={selectSheet}
|
|
onCreateSheet={handleCreateSheet}
|
|
onRenameSheet={handleRenameSheet}
|
|
onDeleteSheet={handleDeleteSheet}
|
|
/>
|
|
<button className={css['AddButton']} onClick={handleAddClick}>
|
|
+
|
|
</button>
|
|
</div>
|
|
```
|
|
|
|
4. **Style the Dropdown**
|
|
- Match existing ComponentsPanel styling
|
|
- Smooth open/close animation
|
|
- Proper z-index layering
|
|
|
|
**Success Criteria:**
|
|
|
|
- [ ] Dropdown button shows current sheet name
|
|
- [ ] Clicking opens sheet list
|
|
- [ ] Sheet list shows all non-hidden sheets
|
|
- [ ] "Add Sheet" button at bottom
|
|
- [ ] Three-dot menu on each sheet (except Default)
|
|
- [ ] Clicking sheet switches view
|
|
|
|
### Phase 4: Sheet Management Actions (1-2 hours)
|
|
|
|
Wire up all sheet management actions.
|
|
|
|
**Files to Modify:**
|
|
|
|
- `ComponentsPanelReact.tsx` - Wire up SheetSelector callbacks
|
|
|
|
**Tasks:**
|
|
|
|
1. **Create Sheet Action**
|
|
|
|
```typescript
|
|
const handleCreateSheet = useCallback(() => {
|
|
const popup = new PopupLayer.StringInputPopup({
|
|
label: 'New sheet name',
|
|
okLabel: 'Create',
|
|
cancelLabel: 'Cancel',
|
|
onOk: (name: string) => {
|
|
if (!name || name.trim() === '') {
|
|
ToastLayer.showError('Sheet name cannot be empty');
|
|
return;
|
|
}
|
|
createSheet(name);
|
|
PopupLayer.instance.hidePopup();
|
|
}
|
|
});
|
|
|
|
popup.render();
|
|
PopupLayer.instance.showPopup({
|
|
content: popup,
|
|
position: 'center'
|
|
});
|
|
}, [createSheet]);
|
|
```
|
|
|
|
2. **Rename Sheet Action**
|
|
|
|
- Show StringInputPopup with current name
|
|
- Validate name (non-empty, unique)
|
|
- Call `renameSheet()` from useSheetManagement
|
|
- Update displays new name immediately (via ProjectModel events)
|
|
|
|
3. **Delete Sheet Action**
|
|
|
|
- Show confirmation dialog with component count
|
|
- Call `deleteSheet()` from useSheetManagement
|
|
- Switch to Default sheet after deletion
|
|
|
|
4. **Drag-Drop Between Sheets** (Optional Enhancement)
|
|
- Extend useDragDrop to support sheet boundaries
|
|
- Allow dropping on sheet name in dropdown
|
|
- Move component/folder to target sheet
|
|
|
|
**Success Criteria:**
|
|
|
|
- [ ] "Add Sheet" creates new sheet with undo
|
|
- [ ] Rename sheet updates all component paths
|
|
- [ ] Delete sheet removes folder and components
|
|
- [ ] All operations show in undo history
|
|
- [ ] UI updates immediately after operations
|
|
|
|
### Phase 5: Integration & Testing (1 hour)
|
|
|
|
Final integration and comprehensive testing.
|
|
|
|
**Tasks:**
|
|
|
|
1. **Update TASK-004B Documentation**
|
|
|
|
- Mark as "Feature Complete" (not just "Complete")
|
|
- Add reference to TASK-008 for sheet system
|
|
|
|
2. **Test All Menu Features**
|
|
|
|
- [ ] Component context menu "Create" submenu works
|
|
- [ ] Folder context menu "Create" submenu works
|
|
- [ ] All templates create components at correct path
|
|
- [ ] Folder creation from context menu works
|
|
|
|
3. **Test All Sheet Features**
|
|
|
|
- [ ] Sheet dropdown displays correctly
|
|
- [ ] Switching sheets filters component list
|
|
- [ ] Creating sheet adds to dropdown
|
|
- [ ] Renaming sheet updates dropdown and paths
|
|
- [ ] Deleting sheet removes from dropdown
|
|
|
|
4. **Test Edge Cases**
|
|
|
|
- [ ] Hidden sheets don't appear in dropdown
|
|
- [ ] Locked sheet mode prevents switching (for Cloud Functions panel)
|
|
- [ ] Empty sheets show correctly
|
|
- [ ] Deleting last component in sheet folder
|
|
|
|
5. **Test Undo/Redo**
|
|
- [ ] Create sheet → undo removes it
|
|
- [ ] Rename sheet → undo reverts name
|
|
- [ ] Delete sheet → undo restores it
|
|
- [ ] Move to sheet → undo moves back
|
|
|
|
**Success Criteria:**
|
|
|
|
- [ ] All features working end-to-end
|
|
- [ ] No console errors or warnings
|
|
- [ ] Smooth UX with proper feedback
|
|
- [ ] Documentation updated
|
|
|
|
---
|
|
|
|
## Technical Details
|
|
|
|
### PopupMenu Submenu Support
|
|
|
|
The legacy implementation used nested PopupMenu items. Need to verify if current PopupMenu supports this:
|
|
|
|
**Option A: Nested Menu Support**
|
|
|
|
```typescript
|
|
{
|
|
icon: IconName.Plus,
|
|
label: 'Create',
|
|
submenu: [
|
|
{ icon: IconName.Page, label: 'Page', onClick: ... },
|
|
{ icon: IconName.Component, label: 'Visual Component', onClick: ... },
|
|
// etc
|
|
]
|
|
}
|
|
```
|
|
|
|
**Option B: Flat Menu with Dividers**
|
|
|
|
```typescript
|
|
[
|
|
{ icon: IconName.Plus, label: 'Create Page', onClick: ... },
|
|
{ icon: IconName.Plus, label: 'Create Visual Component', onClick: ... },
|
|
{ icon: IconName.Plus, label: 'Create Logic Component', onClick: ... },
|
|
{ icon: IconName.Plus, label: 'Create Cloud Function', onClick: ... },
|
|
{ type: 'divider' },
|
|
{ icon: IconName.Plus, label: 'Create Folder', onClick: ... },
|
|
{ type: 'divider' },
|
|
// existing items...
|
|
]
|
|
```
|
|
|
|
**Decision:** Check PopupMenu implementation first. If nested menus aren't supported, use Option B as it's simpler and still provides good UX.
|
|
|
|
### Sheet Folder Structure
|
|
|
|
Sheets are implemented as top-level folders:
|
|
|
|
```
|
|
projectFolder (root)
|
|
├── #Pages/ ← Sheet: "Pages"
|
|
│ ├── HomePage
|
|
│ ├── AboutPage
|
|
├── #Components/ ← Sheet: "Components"
|
|
│ ├── Header
|
|
│ ├── Footer
|
|
├── #__cloud__/ ← Special hidden sheet
|
|
│ ├── MyCloudFunction
|
|
├── App ← Default sheet
|
|
├── Settings ← Default sheet
|
|
```
|
|
|
|
**Key Points:**
|
|
|
|
- Sheet names start with `#` in folder structure
|
|
- Display names remove the `#` prefix
|
|
- Default sheet = any component not in a `#` folder
|
|
- Hidden sheets filtered by `hideSheets` option
|
|
|
|
### Sheet Filtering Algorithm
|
|
|
|
```typescript
|
|
function filterBySheet(components, sheet) {
|
|
if (sheet.isDefault) {
|
|
// Show only components NOT in any sheet folder
|
|
return components.filter((comp) => !comp.name.startsWith('/#'));
|
|
} else {
|
|
// Show only components in this sheet's folder
|
|
const sheetPath = sheet.folder.getPath();
|
|
return components.filter((comp) => comp.name.startsWith(sheetPath));
|
|
}
|
|
}
|
|
```
|
|
|
|
### UndoQueue Pattern
|
|
|
|
All sheet operations must use the proven pattern:
|
|
|
|
```typescript
|
|
UndoQueue.instance.pushAndDo(
|
|
new UndoActionGroup({
|
|
label: 'create sheet',
|
|
do: () => {
|
|
// Perform action
|
|
},
|
|
undo: () => {
|
|
// Revert action
|
|
}
|
|
})
|
|
);
|
|
```
|
|
|
|
**NOT** the old broken pattern:
|
|
|
|
```typescript
|
|
// ❌ DON'T DO THIS
|
|
const undoGroup = new UndoActionGroup({ label: 'action' });
|
|
undoGroup.push({ do: ..., undo: ... });
|
|
UndoQueue.instance.push(undoGroup);
|
|
undoGroup.do();
|
|
```
|
|
|
|
---
|
|
|
|
## Files to Modify
|
|
|
|
### Create (New)
|
|
|
|
```
|
|
packages/noodl-editor/src/editor/src/views/panels/ComponentsPanelNew/
|
|
├── components/
|
|
│ ├── SheetSelector.tsx # NEW
|
|
│ └── SheetSelector.module.scss # NEW
|
|
└── hooks/
|
|
└── useSheetManagement.ts # NEW
|
|
```
|
|
|
|
### Modify (Existing)
|
|
|
|
```
|
|
packages/noodl-editor/src/editor/src/views/panels/ComponentsPanelNew/
|
|
├── ComponentsPanelReact.tsx # Add SheetSelector
|
|
├── components/
|
|
│ ├── ComponentItem.tsx # Enhance context menu
|
|
│ └── FolderItem.tsx # Enhance context menu
|
|
├── hooks/
|
|
│ ├── useComponentsPanel.ts # Add sheet filtering
|
|
│ └── useComponentActions.ts # Add sheet actions
|
|
└── types.ts # Add Sheet types
|
|
```
|
|
|
|
---
|
|
|
|
## Testing Checklist
|
|
|
|
### Context Menu Enhancements
|
|
|
|
- [ ] Component right-click shows "Create" submenu
|
|
- [ ] "Create" submenu shows all 4 templates + folder
|
|
- [ ] Clicking template opens creation popup
|
|
- [ ] Component created at correct path
|
|
- [ ] Folder creation works from context menu
|
|
- [ ] Folder right-click has same "Create" submenu
|
|
- [ ] All operations support undo/redo
|
|
|
|
### Sheet Selector UI
|
|
|
|
- [ ] Dropdown button appears in header
|
|
- [ ] Dropdown shows current sheet name
|
|
- [ ] Clicking opens sheet list
|
|
- [ ] All non-hidden sheets appear in list
|
|
- [ ] Current sheet has selection indicator
|
|
- [ ] "Add Sheet" button at bottom
|
|
- [ ] Three-dot menu on non-default sheets
|
|
- [ ] Clicking sheet switches view
|
|
|
|
### Sheet Management
|
|
|
|
- [ ] Create sheet opens input popup
|
|
- [ ] New sheet appears in dropdown
|
|
- [ ] Components filtered by selected sheet
|
|
- [ ] Rename sheet updates name everywhere
|
|
- [ ] Rename sheet updates component paths
|
|
- [ ] Delete sheet shows confirmation
|
|
- [ ] Delete sheet removes from dropdown
|
|
- [ ] Delete sheet removes all components
|
|
- [ ] Hidden sheets don't appear (e.g., **cloud**)
|
|
|
|
### Sheet Filtering
|
|
|
|
- [ ] Default sheet shows non-sheet components
|
|
- [ ] Named sheet shows only its components
|
|
- [ ] Switching sheets updates tree immediately
|
|
- [ ] Empty sheets show empty state
|
|
- [ ] Component creation adds to current sheet
|
|
|
|
### Undo/Redo
|
|
|
|
- [ ] Create sheet → undo removes it
|
|
- [ ] Create sheet → undo → redo restores it
|
|
- [ ] Rename sheet → undo reverts name
|
|
- [ ] Delete sheet → undo restores sheet and components
|
|
- [ ] Move to sheet → undo moves back
|
|
|
|
### Edge Cases
|
|
|
|
- [ ] Cannot delete Default sheet
|
|
- [ ] Cannot create sheet with empty name
|
|
- [ ] Cannot create sheet with duplicate name
|
|
- [ ] Locked sheet mode prevents switching
|
|
- [ ] Hidden sheets stay hidden
|
|
- [ ] Deleting last component doesn't break UI
|
|
|
|
---
|
|
|
|
## Risks & Mitigations
|
|
|
|
### Risk: PopupMenu doesn't support nested menus
|
|
|
|
**Mitigation:** Use flat menu structure with dividers. Still provides good UX.
|
|
|
|
### Risk: Sheet filtering breaks component selection
|
|
|
|
**Mitigation:** Test extensively. Ensure ProjectModel events update sheet view correctly.
|
|
|
|
### Risk: Sheet delete is destructive
|
|
|
|
**Mitigation:** Show confirmation with component count. Make undo work perfectly.
|
|
|
|
---
|
|
|
|
## Success Criteria
|
|
|
|
1. **Context Menus Enhanced**: "Create" submenus with all templates work perfectly
|
|
2. **Sheet UI Complete**: Dropdown selector with all management features
|
|
3. **Sheet Operations**: Full CRUD with undo support
|
|
4. **Feature Parity**: All legacy sheet features now in React
|
|
5. **Clean Code**: TypeScript throughout, no TSFixme
|
|
6. **Documentation**: Updated task status, learnings captured
|
|
|
|
---
|
|
|
|
## Future Enhancements (Out of Scope)
|
|
|
|
- Drag-drop between sheets (drag component onto sheet name)
|
|
- Sheet reordering
|
|
- Sheet color coding
|
|
- Sheet icons
|
|
- Keyboard shortcuts for sheet switching
|
|
- Sheet search/filter
|
|
|
|
---
|
|
|
|
## Dependencies
|
|
|
|
**Blocked by:** None (TASK-004B complete)
|
|
|
|
**Blocks:** None (UX enhancement)
|
|
|
|
---
|
|
|
|
## References
|
|
|
|
- **TASK-004B**: ComponentsPanel React Migration (predecessor)
|
|
- **Legacy Implementation**: `ComponentsPanel.ts.legacy` - Complete reference
|
|
- **Current React**: `ComponentsPanelReact.tsx` - Foundation to build on
|
|
- **Templates**: `ComponentTemplates.ts` - Template system
|
|
- **Actions**: `useComponentActions.ts` - Action patterns
|
|
- **Undo Pattern**: `dev-docs/reference/UNDO-QUEUE-PATTERNS.md`
|
|
|
|
---
|
|
|
|
## Notes for Implementation
|
|
|
|
### PopupMenu Investigation
|
|
|
|
Before starting Phase 1, check:
|
|
|
|
1. Does PopupMenu support nested menus?
|
|
2. If yes, what's the API?
|
|
3. If no, is it easy to add or should we use flat menus?
|
|
|
|
File to check: `packages/noodl-editor/src/editor/src/views/PopupLayer/PopupMenu.tsx`
|
|
|
|
### Sheet State Management
|
|
|
|
Consider using a custom hook `useSheetState()` to encapsulate:
|
|
|
|
- Current sheet selection
|
|
- Sheet list with filtering
|
|
- Sheet switching logic
|
|
- Persistence (if needed)
|
|
|
|
This keeps ComponentsPanelReact clean and focused.
|
|
|
|
### Component Path Updates
|
|
|
|
When renaming sheets, ALL components in that sheet need path updates. This is similar to folder rename. Use the same pattern:
|
|
|
|
```typescript
|
|
const componentsInSheet = ProjectModel.instance.getComponents().filter((c) => c.name.startsWith(oldSheetPath));
|
|
|
|
componentsInSheet.forEach((comp) => {
|
|
const relativePath = comp.name.substring(oldSheetPath.length);
|
|
const newName = newSheetPath + relativePath;
|
|
ProjectModel.instance.renameComponent(comp, newName);
|
|
});
|
|
```
|
|
|
|
### Hidden Sheets
|
|
|
|
The `hideSheets` option is important for panels like the Cloud Functions panel. It might show:
|
|
|
|
- `hideSheets: ['__cloud__']` - Don't show cloud functions in main panel
|
|
|
|
OR it might be locked to ONLY cloud functions:
|
|
|
|
- `lockCurrentSheetName: '__cloud__'` - Only show cloud functions
|
|
|
|
Both patterns should work seamlessly.
|
|
|
|
---
|
|
|
|
_Last Updated: December 26, 2025_
|