mirror of
https://github.com/The-Low-Code-Foundation/OpenNoodl.git
synced 2026-01-11 23:02:56 +01:00
358 lines
11 KiB
Markdown
358 lines
11 KiB
Markdown
# DASH-003: Project Organization - Folders & Tags
|
||
|
||
## Overview
|
||
|
||
Add the ability to organize projects using folders and tags. This enables users with many projects to group related work, filter their view, and find projects quickly.
|
||
|
||
## Context
|
||
|
||
Currently, projects are displayed in a flat list sorted by recency. Users with many projects (10+) struggle to find specific projects. There's no way to group related projects (e.g., "Client Work", "Personal", "Tutorials").
|
||
|
||
This task adds a folder/tag system that works entirely client-side, storing metadata separately from the Noodl projects themselves.
|
||
|
||
## Requirements
|
||
|
||
### Functional Requirements
|
||
|
||
1. **Folders**
|
||
- Create, rename, delete folders
|
||
- Drag-and-drop projects into folders
|
||
- Nested folders (1 level deep max)
|
||
- "All Projects" virtual folder (shows everything)
|
||
- "Uncategorized" virtual folder (shows unorganized projects)
|
||
- Folder displayed in sidebar
|
||
|
||
2. **Tags**
|
||
- Create, rename, delete tags
|
||
- Assign multiple tags per project
|
||
- Color-coded tags
|
||
- Tag filtering (show projects with specific tags)
|
||
- Tags displayed as pills on project rows
|
||
|
||
3. **Filtering**
|
||
- Filter by folder (sidebar click)
|
||
- Filter by tag (tag click or dropdown)
|
||
- Combine folder + tag filters
|
||
- Search within filtered view
|
||
- Clear all filters button
|
||
|
||
4. **Persistence**
|
||
- Store folder/tag data in electron-store (not in project files)
|
||
- Data structure keyed by project path (stable identifier)
|
||
- Export/import organization data (stretch goal)
|
||
|
||
### Non-Functional Requirements
|
||
|
||
- Organization changes feel instant
|
||
- Drag-and-drop is smooth
|
||
- Works offline
|
||
- Survives app restart
|
||
|
||
## Data Model
|
||
|
||
### Storage Structure
|
||
|
||
```typescript
|
||
// Stored in electron-store under 'projectOrganization'
|
||
interface ProjectOrganizationData {
|
||
version: 1;
|
||
folders: Folder[];
|
||
tags: Tag[];
|
||
projectMeta: Record<string, ProjectMeta>; // keyed by project path
|
||
}
|
||
|
||
interface Folder {
|
||
id: string;
|
||
name: string;
|
||
parentId: string | null; // null = root level
|
||
order: number;
|
||
createdAt: string;
|
||
}
|
||
|
||
interface Tag {
|
||
id: string;
|
||
name: string;
|
||
color: string; // hex color
|
||
createdAt: string;
|
||
}
|
||
|
||
interface ProjectMeta {
|
||
folderId: string | null;
|
||
tagIds: string[];
|
||
customName?: string; // optional override
|
||
notes?: string; // stretch goal
|
||
}
|
||
```
|
||
|
||
### Color Palette for Tags
|
||
|
||
```typescript
|
||
const TAG_COLORS = [
|
||
'#EF4444', // Red
|
||
'#F97316', // Orange
|
||
'#EAB308', // Yellow
|
||
'#22C55E', // Green
|
||
'#06B6D4', // Cyan
|
||
'#3B82F6', // Blue
|
||
'#8B5CF6', // Purple
|
||
'#EC4899', // Pink
|
||
'#6B7280', // Gray
|
||
];
|
||
```
|
||
|
||
## Technical Approach
|
||
|
||
### 1. Storage Service
|
||
|
||
```typescript
|
||
// packages/noodl-editor/src/editor/src/services/ProjectOrganizationService.ts
|
||
|
||
class ProjectOrganizationService {
|
||
private static instance: ProjectOrganizationService;
|
||
|
||
// Folder operations
|
||
createFolder(name: string, parentId?: string): Folder;
|
||
renameFolder(id: string, name: string): void;
|
||
deleteFolder(id: string): void;
|
||
reorderFolder(id: string, newOrder: number): void;
|
||
|
||
// Tag operations
|
||
createTag(name: string, color: string): Tag;
|
||
renameTag(id: string, name: string): void;
|
||
deleteTag(id: string): void;
|
||
changeTagColor(id: string, color: string): void;
|
||
|
||
// Project organization
|
||
moveProjectToFolder(projectPath: string, folderId: string | null): void;
|
||
addTagToProject(projectPath: string, tagId: string): void;
|
||
removeTagFromProject(projectPath: string, tagId: string): void;
|
||
|
||
// Queries
|
||
getFolders(): Folder[];
|
||
getTags(): Tag[];
|
||
getProjectMeta(projectPath: string): ProjectMeta | null;
|
||
getProjectsInFolder(folderId: string | null): string[];
|
||
getProjectsWithTag(tagId: string): string[];
|
||
}
|
||
```
|
||
|
||
### 2. Sidebar Folder Tree
|
||
|
||
```
|
||
packages/noodl-core-ui/src/preview/launcher/Launcher/components/
|
||
├── FolderTree/
|
||
│ ├── FolderTree.tsx # Tree container
|
||
│ ├── FolderTreeItem.tsx # Individual folder row
|
||
│ ├── FolderTree.module.scss
|
||
│ └── index.ts
|
||
```
|
||
|
||
### 3. Tag Components
|
||
|
||
```
|
||
├── TagPill/
|
||
│ ├── TagPill.tsx # Small colored tag display
|
||
│ └── TagPill.module.scss
|
||
├── TagSelector/
|
||
│ ├── TagSelector.tsx # Dropdown to add/remove tags
|
||
│ └── TagSelector.module.scss
|
||
├── TagFilter/
|
||
│ ├── TagFilter.tsx # Filter bar with active tags
|
||
│ └── TagFilter.module.scss
|
||
```
|
||
|
||
### 4. Drag and Drop
|
||
|
||
Use `@dnd-kit/core` for drag-and-drop:
|
||
|
||
```typescript
|
||
// DragDropContext for launcher
|
||
import { DndContext, DragOverlay } from '@dnd-kit/core';
|
||
|
||
// Draggable project row
|
||
import { useDraggable } from '@dnd-kit/core';
|
||
|
||
// Droppable folder
|
||
import { useDroppable } from '@dnd-kit/core';
|
||
```
|
||
|
||
## Files to Create
|
||
|
||
1. `packages/noodl-editor/src/editor/src/services/ProjectOrganizationService.ts`
|
||
2. `packages/noodl-core-ui/src/preview/launcher/Launcher/components/FolderTree/FolderTree.tsx`
|
||
3. `packages/noodl-core-ui/src/preview/launcher/Launcher/components/FolderTree/FolderTreeItem.tsx`
|
||
4. `packages/noodl-core-ui/src/preview/launcher/Launcher/components/FolderTree/FolderTree.module.scss`
|
||
5. `packages/noodl-core-ui/src/preview/launcher/Launcher/components/TagPill/TagPill.tsx`
|
||
6. `packages/noodl-core-ui/src/preview/launcher/Launcher/components/TagSelector/TagSelector.tsx`
|
||
7. `packages/noodl-core-ui/src/preview/launcher/Launcher/components/TagFilter/TagFilter.tsx`
|
||
8. `packages/noodl-core-ui/src/preview/launcher/Launcher/hooks/useProjectOrganization.ts`
|
||
9. `packages/noodl-core-ui/src/preview/launcher/Launcher/components/CreateFolderModal/CreateFolderModal.tsx`
|
||
10. `packages/noodl-core-ui/src/preview/launcher/Launcher/components/CreateTagModal/CreateTagModal.tsx`
|
||
|
||
## Files to Modify
|
||
|
||
1. `packages/noodl-core-ui/src/preview/launcher/Launcher/Launcher.tsx`
|
||
- Add DndContext wrapper
|
||
- Add organization state to context
|
||
|
||
2. `packages/noodl-core-ui/src/preview/launcher/Launcher/components/LauncherSidebar/LauncherSidebar.tsx`
|
||
- Add FolderTree component
|
||
- Add "Create Folder" button
|
||
|
||
3. `packages/noodl-core-ui/src/preview/launcher/Launcher/views/Projects.tsx`
|
||
- Add TagFilter bar
|
||
- Filter projects based on folder/tag selection
|
||
- Make project rows draggable
|
||
|
||
4. `packages/noodl-core-ui/src/preview/launcher/Launcher/components/ProjectList/ProjectListRow.tsx`
|
||
- Add tag pills
|
||
- Add tag selector on hover/context menu
|
||
- Make row draggable
|
||
|
||
## UI Mockups
|
||
|
||
### Sidebar with Folders
|
||
|
||
```
|
||
┌─────────────────────────┐
|
||
│ 📁 All Projects (24) │
|
||
│ 📁 Uncategorized (5) │
|
||
├─────────────────────────┤
|
||
│ + Create Folder │
|
||
├─────────────────────────┤
|
||
│ 📂 Client Work (8) │
|
||
│ └─ 📁 Acme Corp (3) │
|
||
│ └─ 📁 BigCo (5) │
|
||
│ 📂 Personal (6) │
|
||
│ 📂 Tutorials (5) │
|
||
└─────────────────────────┘
|
||
```
|
||
|
||
### Project Row with Tags
|
||
|
||
```
|
||
┌──────────────────────────────────────────────────────────────────────────┐
|
||
│ 📁 E-commerce Dashboard 2h ago ✅ [🔴 Urgent] [🔵 Client] ~/dev/... │
|
||
└──────────────────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
### Tag Filter Bar
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────────────────────────┐
|
||
│ Filters: [🔴 Urgent ×] [🔵 Client ×] [+ Add Filter] [Clear All] │
|
||
└─────────────────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
## Implementation Steps
|
||
|
||
### Phase 1: Storage Foundation
|
||
1. Create ProjectOrganizationService
|
||
2. Define data model and storage
|
||
3. Create useProjectOrganization hook
|
||
4. Add to launcher context
|
||
|
||
### Phase 2: Folders
|
||
1. Create FolderTree component
|
||
2. Add to sidebar
|
||
3. Create folder modal
|
||
4. Implement folder filtering
|
||
5. Add context menu (rename, delete)
|
||
|
||
### Phase 3: Tags
|
||
1. Create TagPill component
|
||
2. Create TagSelector dropdown
|
||
3. Create TagFilter bar
|
||
4. Add tags to project rows
|
||
5. Implement tag filtering
|
||
|
||
### Phase 4: Drag and Drop
|
||
1. Add dnd-kit dependency
|
||
2. Wrap launcher in DndContext
|
||
3. Make project rows draggable
|
||
4. Make folders droppable
|
||
5. Handle drop events
|
||
|
||
### Phase 5: Polish
|
||
1. Add keyboard shortcuts
|
||
2. Improve animations
|
||
3. Handle edge cases (deleted projects, etc.)
|
||
4. Test thoroughly
|
||
|
||
## Testing Checklist
|
||
|
||
- [ ] Can create a folder
|
||
- [ ] Can rename a folder
|
||
- [ ] Can delete a folder (projects go to Uncategorized)
|
||
- [ ] Can create nested folder
|
||
- [ ] Clicking folder filters project list
|
||
- [ ] Can create a tag
|
||
- [ ] Can assign tag to project
|
||
- [ ] Can remove tag from project
|
||
- [ ] Clicking tag filters project list
|
||
- [ ] Can combine folder + tag filters
|
||
- [ ] Search works within filtered view
|
||
- [ ] Clear filters button works
|
||
- [ ] Drag project to folder works
|
||
- [ ] Data persists after app restart
|
||
- [ ] Removing project from disk shows appropriate state
|
||
|
||
## Dependencies
|
||
|
||
- DASH-001 (Tabbed Navigation System)
|
||
- DASH-002 (Project List Redesign) - for project rows
|
||
|
||
### External Dependencies
|
||
|
||
Add to `package.json`:
|
||
```json
|
||
{
|
||
"@dnd-kit/core": "^6.0.0",
|
||
"@dnd-kit/sortable": "^7.0.0"
|
||
}
|
||
```
|
||
|
||
## Blocked By
|
||
|
||
- DASH-002
|
||
|
||
## Blocks
|
||
|
||
- None (this is end of the DASH chain)
|
||
|
||
## Estimated Effort
|
||
|
||
- Storage service: 2-3 hours
|
||
- Folder tree UI: 3-4 hours
|
||
- Tag components: 3-4 hours
|
||
- Drag and drop: 3-4 hours
|
||
- Filtering logic: 2-3 hours
|
||
- Polish & testing: 3-4 hours
|
||
- **Total: 16-22 hours**
|
||
|
||
## Success Criteria
|
||
|
||
1. Users can create folders and organize projects
|
||
2. Users can create tags and assign them to projects
|
||
3. Filtering by folder and tag works correctly
|
||
4. Drag-and-drop feels natural
|
||
5. Organization data persists across sessions
|
||
6. System handles edge cases gracefully (deleted projects, etc.)
|
||
|
||
## Future Enhancements
|
||
|
||
- Export/import organization data
|
||
- Folder color customization
|
||
- Project notes/descriptions
|
||
- Bulk operations (move/tag multiple projects)
|
||
- Smart folders (auto-organize by criteria)
|
||
|
||
## Design Notes
|
||
|
||
The folder tree should feel familiar like:
|
||
- macOS Finder sidebar
|
||
- VS Code Explorer
|
||
- Notion page tree
|
||
|
||
Keep interactions lightweight - organization should help, not hinder, the workflow of quickly opening projects.
|