mirror of
https://github.com/The-Low-Code-Foundation/OpenNoodl.git
synced 2026-01-11 14:52:55 +01:00
Merged Axel changes. Added dev docs for Cline
This commit is contained in:
153
.clineignore
Normal file
153
.clineignore
Normal file
@@ -0,0 +1,153 @@
|
|||||||
|
# =============================================================================
|
||||||
|
# OpenNoodl .clineignore
|
||||||
|
# =============================================================================
|
||||||
|
# This file tells Cline which folders/files to ignore when indexing the codebase.
|
||||||
|
# Place this file at the root of the OpenNoodl repository.
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# Specific heavy file locations that Cline doesn't need
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
packages/noodl-editor/src/assets/
|
||||||
|
packages/noodl-core-ui/src/assets/
|
||||||
|
packages/noodl-editor/build/icons/
|
||||||
|
packages/noodl-editor/src/editor/parse-dashboard-public/
|
||||||
|
packages/noodl-editor/src/assets/
|
||||||
|
packages/noodl-editor/tests/testfs/
|
||||||
|
packages/noodl-editor/tests/recordings/
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# Dependencies (MASSIVE - always ignore)
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
node_modules/
|
||||||
|
**/node_modules/
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# Build & Distribution Output
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
build/
|
||||||
|
dist/
|
||||||
|
**/build/
|
||||||
|
**/dist/
|
||||||
|
publish/
|
||||||
|
**/publish/
|
||||||
|
bundles/
|
||||||
|
**/bundles/
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# External Dependencies (Parse Dashboard, etc.)
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
deps/
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# Git
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
.git/
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# Compiled/Bundled JavaScript (not source code)
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
*.bundle.js
|
||||||
|
*.min.js
|
||||||
|
*.min.css
|
||||||
|
**/*.bundle.js
|
||||||
|
**/*.min.js
|
||||||
|
|
||||||
|
# Specific bundled/minified files
|
||||||
|
packages/noodl-viewer-react/static/
|
||||||
|
packages/noodl-editor/src/editor/parse-dashboard-public/
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# Static Assets (images, fonts, etc.)
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
**/assets/fonts/
|
||||||
|
**/assets/images/
|
||||||
|
**/public/fonts/
|
||||||
|
**/public/images/
|
||||||
|
**/*.png
|
||||||
|
**/*.jpg
|
||||||
|
**/*.jpeg
|
||||||
|
**/*.gif
|
||||||
|
**/*.ico
|
||||||
|
**/*.woff
|
||||||
|
**/*.woff2
|
||||||
|
**/*.ttf
|
||||||
|
**/*.eot
|
||||||
|
**/*.svg
|
||||||
|
!packages/noodl-core-ui/src/**/*.svg
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# Test Artifacts
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
coverage/
|
||||||
|
**/coverage/
|
||||||
|
**/__snapshots__/
|
||||||
|
*.snap
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# IDE & Editor Configs (not needed for code understanding)
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
.idea/
|
||||||
|
.vscode/
|
||||||
|
*.code-workspace
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# OS Generated Files
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
|
*.log
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# Temporary & Cache Files
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
.cache/
|
||||||
|
**/.cache/
|
||||||
|
*.tmp
|
||||||
|
*.temp
|
||||||
|
.eslintcache
|
||||||
|
.prettiercache
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# Environment & Secrets
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
.env
|
||||||
|
.env.*
|
||||||
|
*.pem
|
||||||
|
*.key
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# Electron Build Artifacts
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
packages/noodl-editor/release/
|
||||||
|
packages/noodl-editor/out/
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# Storybook Build Output
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
storybook-static/
|
||||||
|
**/storybook-static/
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# Generated Type Declarations (if separate from source)
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
**/*.d.ts.map
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# Lock Files (package structure is in package.json)
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
package-lock.json
|
||||||
|
yarn.lock
|
||||||
|
pnpm-lock.yaml
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# Miscellaneous Large/Unneeded Files
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
*.dmg
|
||||||
|
*.exe
|
||||||
|
*.AppImage
|
||||||
|
*.deb
|
||||||
|
*.rpm
|
||||||
|
*.zip
|
||||||
|
*.tar.gz
|
||||||
601
dev-docs/.clinerules
Normal file
601
dev-docs/.clinerules
Normal file
@@ -0,0 +1,601 @@
|
|||||||
|
# Cline Development Guidelines for OpenNoodl
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
This document provides guidelines for AI-assisted development on the OpenNoodl codebase using Cline in VSCode. Follow these guidelines to ensure consistent, well-documented, and testable contributions.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Before Starting Any Task
|
||||||
|
|
||||||
|
### 1.1 Understand the Context
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Always check which branch you're on
|
||||||
|
git branch
|
||||||
|
|
||||||
|
# Check for uncommitted changes
|
||||||
|
git status
|
||||||
|
|
||||||
|
# Review recent commits
|
||||||
|
git log --oneline -10
|
||||||
|
```
|
||||||
|
|
||||||
|
### 1.2 Read Relevant Documentation
|
||||||
|
|
||||||
|
Before modifying any file, understand its purpose:
|
||||||
|
|
||||||
|
1. Check for README files in the package
|
||||||
|
2. Read JSDoc comments on functions
|
||||||
|
3. Look for related test files
|
||||||
|
4. Search for usage patterns: `grep -r "functionName" packages/`
|
||||||
|
|
||||||
|
### 1.3 Identify Dependencies
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Check what imports a file
|
||||||
|
grep -r "from.*filename" packages/
|
||||||
|
|
||||||
|
# Check what the file imports
|
||||||
|
head -50 path/to/file.ts | grep "import"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. Code Style Requirements
|
||||||
|
|
||||||
|
### 2.1 TypeScript Standards
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// ✅ GOOD: Explicit types
|
||||||
|
interface NodeProps {
|
||||||
|
id: string;
|
||||||
|
type: NodeType;
|
||||||
|
connections: Connection[];
|
||||||
|
}
|
||||||
|
|
||||||
|
function processNode(node: NodeProps): ProcessedNode {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
|
||||||
|
// ❌ BAD: Implicit any
|
||||||
|
function processNode(node) {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
|
||||||
|
// ❌ BAD: Using TSFixme
|
||||||
|
function processNode(node: TSFixme): TSFixme {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2.2 React Component Standards
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
// ✅ GOOD: Functional component with types
|
||||||
|
interface ButtonProps {
|
||||||
|
label: string;
|
||||||
|
onClick: () => void;
|
||||||
|
disabled?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function Button({ label, onClick, disabled = false }: ButtonProps) {
|
||||||
|
return (
|
||||||
|
<button onClick={onClick} disabled={disabled}>
|
||||||
|
{label}
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ❌ BAD: Class component (unless necessary for lifecycle)
|
||||||
|
class Button extends React.Component {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2.3 Import Organization
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// 1. External packages (alphabetical)
|
||||||
|
import classNames from 'classnames';
|
||||||
|
import React, { useCallback, useState } from 'react';
|
||||||
|
|
||||||
|
// 2. Internal packages (alphabetical by alias)
|
||||||
|
import { IconName } from '@noodl-core-ui/components/common/Icon';
|
||||||
|
import { NodeGraphModel } from '@noodl-models/nodegraphmodel';
|
||||||
|
import { KeyCode } from '@noodl-utils/keyboard/KeyCode';
|
||||||
|
|
||||||
|
// 3. Relative imports (by depth, then alphabetical)
|
||||||
|
import { localHelper } from './helpers';
|
||||||
|
import css from './Component.module.scss';
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2.4 Naming Conventions
|
||||||
|
|
||||||
|
| Type | Convention | Example |
|
||||||
|
|------|------------|---------|
|
||||||
|
| Components | PascalCase | `NodeEditor.tsx` |
|
||||||
|
| Hooks | camelCase, use prefix | `useNodeSelection.ts` |
|
||||||
|
| Utils | camelCase | `formatNodeName.ts` |
|
||||||
|
| Constants | UPPER_SNAKE | `MAX_CONNECTIONS` |
|
||||||
|
| CSS Modules | kebab-case | `node-editor.module.scss` |
|
||||||
|
| Test files | Same + .test | `NodeEditor.test.tsx` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Documentation Requirements
|
||||||
|
|
||||||
|
### 3.1 File Headers
|
||||||
|
|
||||||
|
Every new file should have a header comment:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
/**
|
||||||
|
* NodeProcessor
|
||||||
|
*
|
||||||
|
* Handles the processing of node graph updates and manages
|
||||||
|
* the execution order of connected nodes.
|
||||||
|
*
|
||||||
|
* @module noodl-runtime
|
||||||
|
* @since 1.2.0
|
||||||
|
*/
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.2 Function Documentation
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
/**
|
||||||
|
* Processes a node and propagates changes to connected nodes.
|
||||||
|
*
|
||||||
|
* @param node - The node to process
|
||||||
|
* @param context - The execution context
|
||||||
|
* @param options - Processing options
|
||||||
|
* @param options.force - Force re-evaluation even if inputs unchanged
|
||||||
|
* @returns The processed output values
|
||||||
|
* @throws {NodeProcessingError} If the node definition is invalid
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* ```typescript
|
||||||
|
* const output = processNode(myNode, context, { force: true });
|
||||||
|
* console.log(output.value);
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
function processNode(
|
||||||
|
node: NodeInstance,
|
||||||
|
context: ExecutionContext,
|
||||||
|
options: ProcessOptions = {}
|
||||||
|
): NodeOutput {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.3 Complex Logic Comments
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Calculate the topological sort order for node evaluation.
|
||||||
|
// This ensures nodes are processed after their dependencies.
|
||||||
|
// Uses Kahn's algorithm for O(V+E) complexity.
|
||||||
|
const sortedNodes = topologicalSort(nodes, connections);
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Testing Requirements
|
||||||
|
|
||||||
|
### 4.1 Test File Location
|
||||||
|
|
||||||
|
Tests should be co-located or in a parallel `tests/` directory:
|
||||||
|
|
||||||
|
```
|
||||||
|
// Option A: Co-located
|
||||||
|
components/
|
||||||
|
├── Button/
|
||||||
|
│ ├── Button.tsx
|
||||||
|
│ ├── Button.test.tsx
|
||||||
|
│ └── Button.module.scss
|
||||||
|
|
||||||
|
// Option B: Parallel (current pattern in noodl-editor)
|
||||||
|
packages/noodl-editor/
|
||||||
|
├── src/
|
||||||
|
│ └── components/Button.tsx
|
||||||
|
└── tests/
|
||||||
|
└── components/Button.test.ts
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4.2 Test Structure
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { describe, it, expect, beforeEach, jest } from '@jest/globals';
|
||||||
|
import { renderHook, act } from '@testing-library/react-hooks';
|
||||||
|
|
||||||
|
describe('useNodeSelection', () => {
|
||||||
|
// Setup
|
||||||
|
let mockContext: NodeGraphContext;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
mockContext = createMockContext();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Group related tests
|
||||||
|
describe('when selecting a single node', () => {
|
||||||
|
it('should update selection state', () => {
|
||||||
|
const { result } = renderHook(() => useNodeSelection(mockContext));
|
||||||
|
|
||||||
|
act(() => {
|
||||||
|
result.current.selectNode('node-1');
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(result.current.selectedNodes).toContain('node-1');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should clear previous selection by default', () => {
|
||||||
|
// ...
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when multi-selecting nodes', () => {
|
||||||
|
// ...
|
||||||
|
});
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4.3 What to Test
|
||||||
|
|
||||||
|
| Priority | What to Test |
|
||||||
|
|----------|--------------|
|
||||||
|
| High | Utility functions |
|
||||||
|
| High | Data transformations |
|
||||||
|
| High | State management logic |
|
||||||
|
| Medium | React hooks |
|
||||||
|
| Medium | Component behavior |
|
||||||
|
| Low | Pure UI rendering |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. Git Workflow
|
||||||
|
|
||||||
|
### 5.1 Branch Naming
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Features
|
||||||
|
git checkout -b feature/add-vercel-deployment
|
||||||
|
|
||||||
|
# Bug fixes
|
||||||
|
git checkout -b fix/page-router-scroll
|
||||||
|
|
||||||
|
# Refactoring
|
||||||
|
git checkout -b refactor/remove-tsfixme-panels
|
||||||
|
|
||||||
|
# Documentation
|
||||||
|
git checkout -b docs/update-node-api
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5.2 Commit Messages
|
||||||
|
|
||||||
|
Follow conventional commits:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Format: type(scope): description
|
||||||
|
|
||||||
|
# Features
|
||||||
|
git commit -m "feat(editor): add breakpoint support for node connections"
|
||||||
|
|
||||||
|
# Bug fixes
|
||||||
|
git commit -m "fix(viewer): resolve scroll position reset in nested Page Router"
|
||||||
|
|
||||||
|
# Refactoring
|
||||||
|
git commit -m "refactor(runtime): replace TSFixme with proper types in node processor"
|
||||||
|
|
||||||
|
# Documentation
|
||||||
|
git commit -m "docs(api): add JSDoc to all public node methods"
|
||||||
|
|
||||||
|
# Tests
|
||||||
|
git commit -m "test(editor): add unit tests for node selection hook"
|
||||||
|
|
||||||
|
# Chores
|
||||||
|
git commit -m "chore(deps): update react to 19.0.0"
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5.3 Commit Frequency
|
||||||
|
|
||||||
|
- Commit after each logical change
|
||||||
|
- Don't combine unrelated changes
|
||||||
|
- Commit working states (tests should pass)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. Codebase Navigation
|
||||||
|
|
||||||
|
### 6.1 Key Directories
|
||||||
|
|
||||||
|
```
|
||||||
|
packages/
|
||||||
|
├── noodl-editor/
|
||||||
|
│ ├── src/
|
||||||
|
│ │ ├── editor/src/
|
||||||
|
│ │ │ ├── models/ # Data models (ProjectModel, NodeGraph, etc.)
|
||||||
|
│ │ │ ├── views/ # UI components and views
|
||||||
|
│ │ │ ├── utils/ # Helper utilities
|
||||||
|
│ │ │ ├── store/ # State stores (AI Assistant, etc.)
|
||||||
|
│ │ │ └── pages/ # Page-level components
|
||||||
|
│ │ ├── main/ # Electron main process
|
||||||
|
│ │ └── shared/ # Shared utilities
|
||||||
|
│ └── tests/ # Test files
|
||||||
|
│
|
||||||
|
├── noodl-runtime/
|
||||||
|
│ └── src/
|
||||||
|
│ ├── nodes/ # Runtime node definitions
|
||||||
|
│ └── nodecontext.js # Execution context
|
||||||
|
│
|
||||||
|
├── noodl-viewer-react/
|
||||||
|
│ └── src/
|
||||||
|
│ └── nodes/ # React-based visual nodes
|
||||||
|
│
|
||||||
|
└── noodl-core-ui/
|
||||||
|
└── src/
|
||||||
|
└── components/ # Shared UI components
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6.2 Finding Things
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Find a component
|
||||||
|
find packages/ -name "*NodeEditor*" -type f
|
||||||
|
|
||||||
|
# Find where something is imported
|
||||||
|
grep -r "import.*from.*NodeEditor" packages/
|
||||||
|
|
||||||
|
# Find where a function is called
|
||||||
|
grep -r "processNode(" packages/ --include="*.ts" --include="*.tsx"
|
||||||
|
|
||||||
|
# Find all TODO comments
|
||||||
|
grep -rn "TODO\|FIXME" packages/noodl-editor/src
|
||||||
|
|
||||||
|
# Find test files
|
||||||
|
find packages/ -name "*.test.ts" -o -name "*.spec.ts"
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6.3 Understanding Data Flow
|
||||||
|
|
||||||
|
1. **User Action** → `views/` components capture events
|
||||||
|
2. **State Update** → `models/` handle business logic
|
||||||
|
3. **Runtime Sync** → `ViewerConnection` sends to preview
|
||||||
|
4. **Persistence** → `ProjectModel` saves to disk
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. Common Patterns
|
||||||
|
|
||||||
|
### 7.1 Event Handling Pattern
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Models use EventDispatcher for pub/sub
|
||||||
|
import { EventDispatcher } from '../../../shared/utils/EventDispatcher';
|
||||||
|
|
||||||
|
class MyModel extends EventDispatcher {
|
||||||
|
doSomething() {
|
||||||
|
// ... logic
|
||||||
|
this.notifyListeners('updated', { data: result });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Usage
|
||||||
|
const model = new MyModel();
|
||||||
|
model.on('updated', (data) => {
|
||||||
|
console.log('Model updated:', data);
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### 7.2 React Hook Pattern
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Custom hook for model subscription
|
||||||
|
function useModel<T>(model: EventDispatcher, event: string): T {
|
||||||
|
const [state, setState] = useState<T>(model.getState());
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const handler = (newState: T) => setState(newState);
|
||||||
|
model.on(event, handler);
|
||||||
|
return () => model.off(event, handler);
|
||||||
|
}, [model, event]);
|
||||||
|
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 7.3 Node Definition Pattern
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// In noodl-runtime/src/nodes/
|
||||||
|
const MyNode = {
|
||||||
|
name: 'My.Custom.Node',
|
||||||
|
displayName: 'My Custom Node',
|
||||||
|
category: 'Custom',
|
||||||
|
|
||||||
|
inputs: {
|
||||||
|
inputValue: {
|
||||||
|
type: 'string',
|
||||||
|
displayName: 'Input Value',
|
||||||
|
default: ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
outputs: {
|
||||||
|
outputValue: {
|
||||||
|
type: 'string',
|
||||||
|
displayName: 'Output Value'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
setInputValue(value) {
|
||||||
|
this._internal.inputValue = value;
|
||||||
|
this.flagOutputDirty('outputValue');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
getOutputValue(name) {
|
||||||
|
if (name === 'outputValue') {
|
||||||
|
return this._internal.inputValue.toUpperCase();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 8. Error Handling
|
||||||
|
|
||||||
|
### 8.1 User-Facing Errors
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { ToastLayer } from '../views/ToastLayer/ToastLayer';
|
||||||
|
|
||||||
|
try {
|
||||||
|
await riskyOperation();
|
||||||
|
} catch (error) {
|
||||||
|
// Log for debugging
|
||||||
|
console.error('Operation failed:', error);
|
||||||
|
|
||||||
|
// Show user-friendly message
|
||||||
|
ToastLayer.showError('Unable to complete operation. Please try again.');
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 8.2 Developer Errors
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Use assertions for developer errors
|
||||||
|
function processNode(node: NodeInstance) {
|
||||||
|
if (!node.id) {
|
||||||
|
throw new Error(`processNode: node.id is required`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!node.definition) {
|
||||||
|
throw new Error(`processNode: node "${node.id}" has no definition`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 8.3 Graceful Degradation
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function getNodeIcon(node: NodeInstance): string {
|
||||||
|
try {
|
||||||
|
return node.definition.icon || 'default-icon';
|
||||||
|
} catch {
|
||||||
|
console.warn(`Could not get icon for node ${node.id}`);
|
||||||
|
return 'default-icon';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 9. Performance Considerations
|
||||||
|
|
||||||
|
### 9.1 Avoid Unnecessary Re-renders
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
// ✅ GOOD: Memoized callback
|
||||||
|
const handleClick = useCallback(() => {
|
||||||
|
onNodeSelect(node.id);
|
||||||
|
}, [node.id, onNodeSelect]);
|
||||||
|
|
||||||
|
// ✅ GOOD: Memoized expensive computation
|
||||||
|
const sortedNodes = useMemo(() => {
|
||||||
|
return topologicalSort(nodes);
|
||||||
|
}, [nodes]);
|
||||||
|
|
||||||
|
// ❌ BAD: New function on every render
|
||||||
|
<Button onClick={() => onNodeSelect(node.id)} />
|
||||||
|
```
|
||||||
|
|
||||||
|
### 9.2 Lazy Loading
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
// Lazy load heavy components
|
||||||
|
const CodeEditor = React.lazy(() => import('./CodeEditor'));
|
||||||
|
|
||||||
|
function EditorPanel() {
|
||||||
|
return (
|
||||||
|
<Suspense fallback={<LoadingSpinner />}>
|
||||||
|
<CodeEditor />
|
||||||
|
</Suspense>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 9.3 Batch Updates
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Batch multiple state updates
|
||||||
|
import { unstable_batchedUpdates } from 'react-dom';
|
||||||
|
|
||||||
|
unstable_batchedUpdates(() => {
|
||||||
|
setSelection(newSelection);
|
||||||
|
setHighlight(newHighlight);
|
||||||
|
setZoom(newZoom);
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 10. Checklist Before Submitting
|
||||||
|
|
||||||
|
### Code Quality
|
||||||
|
- [ ] No `TSFixme` types added
|
||||||
|
- [ ] All new functions have JSDoc comments
|
||||||
|
- [ ] Complex logic has inline comments
|
||||||
|
- [ ] No console.log statements (except errors/warnings)
|
||||||
|
- [ ] No unused imports or variables
|
||||||
|
|
||||||
|
### Testing
|
||||||
|
- [ ] Unit tests for new utility functions
|
||||||
|
- [ ] Integration tests for new features
|
||||||
|
- [ ] Existing tests still pass
|
||||||
|
- [ ] Manual testing completed
|
||||||
|
|
||||||
|
### Documentation
|
||||||
|
- [ ] README updated if needed
|
||||||
|
- [ ] JSDoc added to public APIs
|
||||||
|
- [ ] Comments explain "why", not "what"
|
||||||
|
|
||||||
|
### Git
|
||||||
|
- [ ] Meaningful commit messages
|
||||||
|
- [ ] No unrelated changes in commits
|
||||||
|
- [ ] Branch named correctly
|
||||||
|
- [ ] Based on latest main branch
|
||||||
|
|
||||||
|
### Performance
|
||||||
|
- [ ] No obvious performance regressions
|
||||||
|
- [ ] Large lists use virtualization
|
||||||
|
- [ ] Expensive computations are memoized
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Quick Reference Commands
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Development
|
||||||
|
npm run dev # Start editor with hot reload
|
||||||
|
npm run test:editor # Run tests
|
||||||
|
npm run build:editor # Production build
|
||||||
|
|
||||||
|
# Code Quality
|
||||||
|
npx eslint packages/noodl-editor/src --fix
|
||||||
|
npx prettier --write "packages/**/*.{ts,tsx}"
|
||||||
|
npx tsc --noEmit # Type check
|
||||||
|
|
||||||
|
# Debugging
|
||||||
|
DEBUG=* npm run dev # Verbose logging
|
||||||
|
npm run test:editor -- --verbose
|
||||||
|
|
||||||
|
# Finding Issues
|
||||||
|
grep -r "TSFixme" packages/ # Find type escapes
|
||||||
|
grep -r "any" packages/ --include="*.ts" | head -20
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*Last Updated: December 2024*
|
||||||
185
dev-docs/CLINE-INSTRUCTIONS.md
Normal file
185
dev-docs/CLINE-INSTRUCTIONS.md
Normal file
@@ -0,0 +1,185 @@
|
|||||||
|
# Cline Custom Instructions for OpenNoodl
|
||||||
|
|
||||||
|
Copy this entire file into your Cline Custom Instructions (VSCode → Cline extension settings → Custom Instructions).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Identity
|
||||||
|
|
||||||
|
You are an expert TypeScript/React developer working on OpenNoodl, a visual low-code application builder. You write clean, well-documented, tested code that follows established patterns.
|
||||||
|
|
||||||
|
## Core Behaviors
|
||||||
|
|
||||||
|
### Before ANY Code Changes
|
||||||
|
|
||||||
|
1. **Read the task documentation first**
|
||||||
|
- Check `dev-docs/tasks/` for the current task
|
||||||
|
- Understand the full scope before writing code
|
||||||
|
- Follow the checklist step-by-step
|
||||||
|
|
||||||
|
2. **Understand the codebase location**
|
||||||
|
- Check `dev-docs/reference/CODEBASE-MAP.md`
|
||||||
|
- Use `grep -r "pattern" packages/` to find related code
|
||||||
|
- Look at similar existing implementations
|
||||||
|
|
||||||
|
3. **Verify your understanding**
|
||||||
|
- State your confidence level (1-10) before major changes
|
||||||
|
- List assumptions that need validation
|
||||||
|
- Ask clarifying questions rather than guessing
|
||||||
|
|
||||||
|
### Code Quality Standards
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// ✅ ALWAYS: Explicit types
|
||||||
|
function processNode(node: NodeInstance): ProcessedResult {
|
||||||
|
// Implementation
|
||||||
|
}
|
||||||
|
|
||||||
|
// ❌ NEVER: Any types or TSFixme
|
||||||
|
function processNode(node: any): any {
|
||||||
|
// Implementation
|
||||||
|
}
|
||||||
|
|
||||||
|
// ✅ ALWAYS: JSDoc for public functions
|
||||||
|
/**
|
||||||
|
* Processes a node and returns the result.
|
||||||
|
* @param node - The node instance to process
|
||||||
|
* @returns The processed result with output values
|
||||||
|
*/
|
||||||
|
function processNode(node: NodeInstance): ProcessedResult {
|
||||||
|
// Implementation
|
||||||
|
}
|
||||||
|
|
||||||
|
// ✅ ALWAYS: Explain "why" in comments
|
||||||
|
// We batch updates here to prevent cascading re-renders
|
||||||
|
// when multiple inputs change in the same frame
|
||||||
|
this.scheduleAfterInputsHaveUpdated(() => {
|
||||||
|
// ...
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### React Patterns
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// ✅ PREFER: Functional components with hooks
|
||||||
|
export function MyComponent({ value, onChange }: MyComponentProps) {
|
||||||
|
const [state, setState] = useState(value);
|
||||||
|
|
||||||
|
const handleChange = useCallback((newValue: string) => {
|
||||||
|
setState(newValue);
|
||||||
|
onChange?.(newValue);
|
||||||
|
}, [onChange]);
|
||||||
|
|
||||||
|
return <input value={state} onChange={e => handleChange(e.target.value)} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ❌ AVOID: Class components (unless lifecycle methods required)
|
||||||
|
class MyComponent extends React.Component {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Import Organization
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// 1. External packages
|
||||||
|
import React, { useState, useCallback } from 'react';
|
||||||
|
import classNames from 'classnames';
|
||||||
|
|
||||||
|
// 2. Internal packages (alphabetical by alias)
|
||||||
|
import { IconName } from '@noodl-core-ui/components/common/Icon';
|
||||||
|
import { NodeGraphModel } from '@noodl-models/nodegraphmodel';
|
||||||
|
import { guid } from '@noodl-utils/utils';
|
||||||
|
|
||||||
|
// 3. Relative imports
|
||||||
|
import { localHelper } from './helpers';
|
||||||
|
import { MyComponentProps } from './types';
|
||||||
|
|
||||||
|
// 4. Styles last
|
||||||
|
import css from './MyComponent.module.scss';
|
||||||
|
```
|
||||||
|
|
||||||
|
## Task Execution Protocol
|
||||||
|
|
||||||
|
### Starting Work
|
||||||
|
|
||||||
|
1. Read the full task README.md
|
||||||
|
2. Check off prerequisites in CHECKLIST.md
|
||||||
|
3. Create your branch: `git checkout -b task/XXX-name`
|
||||||
|
4. State: "Starting TASK-XXX. Confidence: X/10. Assumptions: [list]"
|
||||||
|
|
||||||
|
### During Work
|
||||||
|
|
||||||
|
1. Make incremental changes
|
||||||
|
2. Test frequently: `npm run build:editor`
|
||||||
|
3. Document changes in CHANGELOG.md as you go
|
||||||
|
4. Commit logical chunks with descriptive messages
|
||||||
|
|
||||||
|
### Before Completing
|
||||||
|
|
||||||
|
1. Run full test suite: `npm run test:editor`
|
||||||
|
2. Run type check: `npx tsc --noEmit`
|
||||||
|
3. Review all changes against the checklist
|
||||||
|
4. Update CHANGELOG.md with final summary
|
||||||
|
|
||||||
|
## Confidence Checks
|
||||||
|
|
||||||
|
Rate your confidence (1-10) at these points:
|
||||||
|
- Before starting a task
|
||||||
|
- Before making significant changes
|
||||||
|
- After completing each checklist item
|
||||||
|
- Before marking task complete
|
||||||
|
|
||||||
|
If confidence < 7:
|
||||||
|
- List what's uncertain
|
||||||
|
- Ask for clarification
|
||||||
|
- Research existing patterns in codebase
|
||||||
|
|
||||||
|
## Error Recovery
|
||||||
|
|
||||||
|
When something goes wrong:
|
||||||
|
|
||||||
|
1. **Don't panic** - state what happened clearly
|
||||||
|
2. **Check the error** - read the full message
|
||||||
|
3. **Search codebase** - look for similar patterns
|
||||||
|
4. **Check common issues** - `dev-docs/reference/COMMON-ISSUES.md`
|
||||||
|
5. **Ask for help** - provide context and what you've tried
|
||||||
|
|
||||||
|
## Prohibited Actions
|
||||||
|
|
||||||
|
- ❌ Modifying `node_modules/`, `build/`, `dist/`
|
||||||
|
- ❌ Adding `any` or `TSFixme` types
|
||||||
|
- ❌ Committing without running tests
|
||||||
|
- ❌ Making changes outside task scope without asking
|
||||||
|
- ❌ Deleting code without understanding why it exists
|
||||||
|
- ❌ Guessing when uncertain (ask instead)
|
||||||
|
|
||||||
|
## Helpful Prompts
|
||||||
|
|
||||||
|
Use these phrases to maintain quality:
|
||||||
|
|
||||||
|
- "Before I continue, let me verify my understanding..."
|
||||||
|
- "Confidence level: X/10 because..."
|
||||||
|
- "I notice [pattern] in the existing code, I'll follow that..."
|
||||||
|
- "This change might affect [X], should I check?"
|
||||||
|
- "I'm uncertain about [X], can you clarify?"
|
||||||
|
|
||||||
|
## Project-Specific Knowledge
|
||||||
|
|
||||||
|
### Key Models
|
||||||
|
- `ProjectModel` - Project state, components, settings
|
||||||
|
- `NodeGraphModel` - Graph structure, connections
|
||||||
|
- `ComponentModel` - Individual component definition
|
||||||
|
- `NodeLibrary` - Available node types
|
||||||
|
|
||||||
|
### Key Patterns
|
||||||
|
- Event system: `model.on('event', handler)` / `model.off(handler)`
|
||||||
|
- Dirty flagging: `this.flagOutputDirty('outputName')`
|
||||||
|
- Scheduled updates: `this.scheduleAfterInputsHaveUpdated(() => {})`
|
||||||
|
|
||||||
|
### Key Directories
|
||||||
|
- Editor UI: `packages/noodl-editor/src/editor/src/views/`
|
||||||
|
- Models: `packages/noodl-editor/src/editor/src/models/`
|
||||||
|
- Runtime nodes: `packages/noodl-runtime/src/nodes/`
|
||||||
|
- Visual nodes: `packages/noodl-viewer-react/src/nodes/`
|
||||||
|
- UI components: `packages/noodl-core-ui/src/components/`
|
||||||
122
dev-docs/README.md
Normal file
122
dev-docs/README.md
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
# OpenNoodl Development Documentation
|
||||||
|
|
||||||
|
Welcome to the OpenNoodl development docs. This folder contains everything needed for AI-assisted development with Cline and human contributors alike.
|
||||||
|
|
||||||
|
## 📁 Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
dev-docs/
|
||||||
|
├── .clinerules # Project rules (copy to repo root)
|
||||||
|
├── README.md # This file
|
||||||
|
├── CLINE-INSTRUCTIONS.md # Custom instructions for Cline
|
||||||
|
├── TASK-TEMPLATE.md # Template for creating new tasks
|
||||||
|
│
|
||||||
|
├── guidelines/ # Development standards
|
||||||
|
│ ├── CODING-STANDARDS.md # Code style and patterns
|
||||||
|
│ ├── TESTING-GUIDE.md # How to write tests
|
||||||
|
│ └── GIT-WORKFLOW.md # Branch and commit conventions
|
||||||
|
│
|
||||||
|
├── reference/ # Quick reference materials
|
||||||
|
│ ├── CODEBASE-MAP.md # Navigate the codebase
|
||||||
|
│ ├── NODE-PATTERNS.md # How to create nodes
|
||||||
|
│ └── COMMON-ISSUES.md # Troubleshooting guide
|
||||||
|
│
|
||||||
|
└── tasks/ # Task documentation
|
||||||
|
├── phase-1/ # Foundation tasks
|
||||||
|
│ ├── TASK-001-dependency-updates/
|
||||||
|
│ ├── TASK-002-typescript-cleanup/
|
||||||
|
│ └── ...
|
||||||
|
├── phase-2/ # Navigation & data tasks
|
||||||
|
└── phase-3/ # UX & integration tasks
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🚀 Getting Started
|
||||||
|
|
||||||
|
### For Cline Users
|
||||||
|
|
||||||
|
1. **Copy `.clinerules` to repo root**
|
||||||
|
```bash
|
||||||
|
cp dev-docs/.clinerules .clinerules
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Add custom instructions to Cline**
|
||||||
|
- Open VSCode → Cline extension settings
|
||||||
|
- Paste contents of `CLINE-INSTRUCTIONS.md` into Custom Instructions
|
||||||
|
|
||||||
|
3. **Pick a task**
|
||||||
|
- Browse `tasks/` folders
|
||||||
|
- Each task has its own folder with detailed instructions
|
||||||
|
- Start with Phase 1 tasks (they're prerequisites for later phases)
|
||||||
|
|
||||||
|
### For Human Contributors
|
||||||
|
|
||||||
|
1. Read `guidelines/CODING-STANDARDS.md`
|
||||||
|
2. Check `reference/CODEBASE-MAP.md` to understand the project
|
||||||
|
3. Pick a task from `tasks/` and follow its documentation
|
||||||
|
|
||||||
|
## 📋 Task Workflow
|
||||||
|
|
||||||
|
### Starting a Task
|
||||||
|
|
||||||
|
1. **Read the task documentation completely**
|
||||||
|
```
|
||||||
|
tasks/phase-X/TASK-XXX-name/
|
||||||
|
├── README.md # Full task description
|
||||||
|
├── CHECKLIST.md # Step-by-step checklist
|
||||||
|
├── CHANGELOG.md # Track your changes here
|
||||||
|
└── NOTES.md # Your working notes
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Create a branch**
|
||||||
|
```bash
|
||||||
|
git checkout -b task/XXX-short-name
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Follow the checklist**, checking off items as you go
|
||||||
|
|
||||||
|
4. **Document everything** in CHANGELOG.md
|
||||||
|
|
||||||
|
### Completing a Task
|
||||||
|
|
||||||
|
1. Ensure all checklist items are complete
|
||||||
|
2. Run tests: `npm run test:editor`
|
||||||
|
3. Run type check: `npx tsc --noEmit`
|
||||||
|
4. Update CHANGELOG.md with final summary
|
||||||
|
5. Create pull request with task ID in title
|
||||||
|
|
||||||
|
## 🎯 Current Priorities
|
||||||
|
|
||||||
|
### Phase 1: Foundation (Do First)
|
||||||
|
- [ ] TASK-001: Dependency Updates & Build Modernization
|
||||||
|
- [ ] TASK-002: TypeScript Cleanup & Type Safety
|
||||||
|
|
||||||
|
### Phase 2: Core Systems
|
||||||
|
- [ ] TASK-003: Navigation System Overhaul
|
||||||
|
- [ ] TASK-004: Data Nodes Modernization
|
||||||
|
|
||||||
|
### Phase 3: UX Polish
|
||||||
|
- [ ] TASK-005: Property Panel Overhaul
|
||||||
|
- [ ] TASK-006: Import/Export Redesign
|
||||||
|
- [ ] TASK-007: REST API Improvements
|
||||||
|
|
||||||
|
## 📚 Key Resources
|
||||||
|
|
||||||
|
| Resource | Description |
|
||||||
|
|----------|-------------|
|
||||||
|
| [Codebase Map](reference/CODEBASE-MAP.md) | Navigate the monorepo |
|
||||||
|
| [Coding Standards](guidelines/CODING-STANDARDS.md) | Style and patterns |
|
||||||
|
| [Node Patterns](reference/NODE-PATTERNS.md) | Creating new nodes |
|
||||||
|
| [Common Issues](reference/COMMON-ISSUES.md) | Troubleshooting |
|
||||||
|
|
||||||
|
## 🤝 Contributing
|
||||||
|
|
||||||
|
1. Pick an unassigned task or create a new one using `TASK-TEMPLATE.md`
|
||||||
|
2. Follow the task documentation precisely
|
||||||
|
3. Document all changes in the task's CHANGELOG.md
|
||||||
|
4. Submit PR with comprehensive description
|
||||||
|
|
||||||
|
## ❓ Questions?
|
||||||
|
|
||||||
|
- Check `reference/COMMON-ISSUES.md` first
|
||||||
|
- Search existing task documentation
|
||||||
|
- Open an issue on GitHub with the `question` label
|
||||||
101
dev-docs/SETUP-INSTRUCTIONS.md
Normal file
101
dev-docs/SETUP-INSTRUCTIONS.md
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
# OpenNoodl Dev Docs - Setup Instructions
|
||||||
|
|
||||||
|
## What's Included
|
||||||
|
|
||||||
|
This folder contains everything needed to set up AI-assisted development with Cline for the OpenNoodl project.
|
||||||
|
|
||||||
|
## Files to Add to Repository
|
||||||
|
|
||||||
|
Copy these to the **root** of your OpenNoodl repository:
|
||||||
|
|
||||||
|
```
|
||||||
|
OpenNoodl/
|
||||||
|
├── .clinerules ← Copy from dev-docs/.clinerules
|
||||||
|
├── .clineignore ← Copy from .clineignore (separate file)
|
||||||
|
└── dev-docs/ ← Copy entire folder
|
||||||
|
├── README.md
|
||||||
|
├── CLINE-INSTRUCTIONS.md
|
||||||
|
├── TASK-TEMPLATE.md
|
||||||
|
├── guidelines/
|
||||||
|
│ ├── CODING-STANDARDS.md
|
||||||
|
│ └── GIT-WORKFLOW.md
|
||||||
|
├── reference/
|
||||||
|
│ ├── CODEBASE-MAP.md
|
||||||
|
│ ├── NODE-PATTERNS.md
|
||||||
|
│ └── COMMON-ISSUES.md
|
||||||
|
└── tasks/
|
||||||
|
└── phase-1/
|
||||||
|
└── TASK-001-dependency-updates/
|
||||||
|
├── README.md
|
||||||
|
├── CHECKLIST.md
|
||||||
|
├── CHANGELOG.md
|
||||||
|
└── NOTES.md
|
||||||
|
```
|
||||||
|
|
||||||
|
## Setup Steps
|
||||||
|
|
||||||
|
### 1. Create Branch
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git checkout -b setup/dev-docs
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Copy Files
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Copy .clinerules to repo root
|
||||||
|
cp path/to/downloads/.clinerules .
|
||||||
|
|
||||||
|
# Copy .clineignore to repo root
|
||||||
|
cp path/to/downloads/.clineignore .
|
||||||
|
|
||||||
|
# Copy dev-docs folder to repo root
|
||||||
|
cp -r path/to/downloads/dev-docs .
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Configure Cline
|
||||||
|
|
||||||
|
1. Open VSCode with the OpenNoodl project
|
||||||
|
2. Click Cline extension settings (gear icon)
|
||||||
|
3. Find "Custom Instructions" field
|
||||||
|
4. Copy contents of `dev-docs/CLINE-INSTRUCTIONS.md` and paste
|
||||||
|
|
||||||
|
### 4. Commit
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git add .clinerules .clineignore dev-docs/
|
||||||
|
git commit -m "docs: add AI-assisted development documentation"
|
||||||
|
git push -u origin setup/dev-docs
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5. Start Working
|
||||||
|
|
||||||
|
1. Open a task: `dev-docs/tasks/phase-1/TASK-001-dependency-updates/`
|
||||||
|
2. Read the README.md
|
||||||
|
3. Follow the CHECKLIST.md
|
||||||
|
4. Track changes in CHANGELOG.md
|
||||||
|
5. Keep notes in NOTES.md
|
||||||
|
|
||||||
|
## File Purposes
|
||||||
|
|
||||||
|
| File | Purpose |
|
||||||
|
|------|---------|
|
||||||
|
| `.clinerules` | Project-specific rules Cline follows automatically |
|
||||||
|
| `.clineignore` | Files/folders Cline should ignore (like .gitignore) |
|
||||||
|
| `CLINE-INSTRUCTIONS.md` | Custom instructions to paste into Cline settings |
|
||||||
|
| `TASK-TEMPLATE.md` | Template for creating new task documentation |
|
||||||
|
| `guidelines/` | Development standards (coding, git workflow) |
|
||||||
|
| `reference/` | Quick references (codebase map, patterns, troubleshooting) |
|
||||||
|
| `tasks/` | Task documentation organized by phase |
|
||||||
|
|
||||||
|
## Creating New Tasks
|
||||||
|
|
||||||
|
1. Copy `TASK-TEMPLATE.md` sections to new folder
|
||||||
|
2. Follow naming: `TASK-XXX-short-name/`
|
||||||
|
3. Fill in all sections of README.md
|
||||||
|
4. Create the checklist specific to the task
|
||||||
|
5. Initialize empty CHANGELOG.md and NOTES.md
|
||||||
|
|
||||||
|
## Questions?
|
||||||
|
|
||||||
|
See `dev-docs/reference/COMMON-ISSUES.md` for troubleshooting.
|
||||||
273
dev-docs/TASK-TEMPLATE.md
Normal file
273
dev-docs/TASK-TEMPLATE.md
Normal file
@@ -0,0 +1,273 @@
|
|||||||
|
# Task Template
|
||||||
|
|
||||||
|
Use this template to create new task documentation. Copy the entire `TASK-XXX-template/` folder and rename it.
|
||||||
|
|
||||||
|
## Folder Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
tasks/phase-N/TASK-XXX-short-name/
|
||||||
|
├── README.md # Full task description (this template)
|
||||||
|
├── CHECKLIST.md # Step-by-step checklist
|
||||||
|
├── CHANGELOG.md # Track changes made
|
||||||
|
└── NOTES.md # Working notes and discoveries
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# README.md Template
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
# TASK-XXX: [Task Title]
|
||||||
|
|
||||||
|
## Metadata
|
||||||
|
|
||||||
|
| Field | Value |
|
||||||
|
|-------|-------|
|
||||||
|
| **ID** | TASK-XXX |
|
||||||
|
| **Phase** | Phase N |
|
||||||
|
| **Priority** | 🔴 Critical / 🟠 High / 🟡 Medium / 🟢 Low |
|
||||||
|
| **Difficulty** | 🔴 Hard / 🟡 Medium / 🟢 Easy |
|
||||||
|
| **Estimated Time** | X hours/days |
|
||||||
|
| **Prerequisites** | TASK-YYY, TASK-ZZZ |
|
||||||
|
| **Branch** | `task/XXX-short-name` |
|
||||||
|
|
||||||
|
## Objective
|
||||||
|
|
||||||
|
[One clear sentence describing what this task accomplishes]
|
||||||
|
|
||||||
|
## Background
|
||||||
|
|
||||||
|
[2-3 paragraphs explaining:
|
||||||
|
- Why this task is needed
|
||||||
|
- What problems it solves
|
||||||
|
- How it fits into the bigger picture]
|
||||||
|
|
||||||
|
## Current State
|
||||||
|
|
||||||
|
[Describe what exists today:
|
||||||
|
- Current behavior
|
||||||
|
- Known issues/bugs
|
||||||
|
- User pain points
|
||||||
|
- Technical debt]
|
||||||
|
|
||||||
|
## Desired State
|
||||||
|
|
||||||
|
[Describe the end goal:
|
||||||
|
- Expected behavior after completion
|
||||||
|
- User experience improvements
|
||||||
|
- Technical improvements]
|
||||||
|
|
||||||
|
## Scope
|
||||||
|
|
||||||
|
### In Scope
|
||||||
|
- [ ] Item 1
|
||||||
|
- [ ] Item 2
|
||||||
|
- [ ] Item 3
|
||||||
|
|
||||||
|
### Out of Scope
|
||||||
|
- Item A (reason)
|
||||||
|
- Item B (reason)
|
||||||
|
|
||||||
|
## Technical Approach
|
||||||
|
|
||||||
|
### Key Files to Modify
|
||||||
|
|
||||||
|
| File | Changes |
|
||||||
|
|------|---------|
|
||||||
|
| `path/to/file1.ts` | [What changes] |
|
||||||
|
| `path/to/file2.tsx` | [What changes] |
|
||||||
|
|
||||||
|
### New Files to Create
|
||||||
|
|
||||||
|
| File | Purpose |
|
||||||
|
|------|---------|
|
||||||
|
| `path/to/newfile.ts` | [Purpose] |
|
||||||
|
|
||||||
|
### Dependencies
|
||||||
|
|
||||||
|
- [ ] Requires TASK-XXX to be completed first
|
||||||
|
- [ ] New npm package: `package-name@version`
|
||||||
|
|
||||||
|
## Implementation Steps
|
||||||
|
|
||||||
|
### Step 1: [Name]
|
||||||
|
[Detailed description of what to do]
|
||||||
|
|
||||||
|
### Step 2: [Name]
|
||||||
|
[Detailed description of what to do]
|
||||||
|
|
||||||
|
### Step 3: [Name]
|
||||||
|
[Detailed description of what to do]
|
||||||
|
|
||||||
|
## Testing Plan
|
||||||
|
|
||||||
|
### Unit Tests
|
||||||
|
- [ ] Test: [Description]
|
||||||
|
- [ ] Test: [Description]
|
||||||
|
|
||||||
|
### Integration Tests
|
||||||
|
- [ ] Test: [Description]
|
||||||
|
|
||||||
|
### Manual Testing
|
||||||
|
- [ ] Scenario: [Description]
|
||||||
|
- [ ] Scenario: [Description]
|
||||||
|
|
||||||
|
## Success Criteria
|
||||||
|
|
||||||
|
- [ ] Criterion 1
|
||||||
|
- [ ] Criterion 2
|
||||||
|
- [ ] All tests pass
|
||||||
|
- [ ] No TypeScript errors
|
||||||
|
- [ ] Documentation updated
|
||||||
|
|
||||||
|
## Risks & Mitigations
|
||||||
|
|
||||||
|
| Risk | Mitigation |
|
||||||
|
|------|------------|
|
||||||
|
| [Risk 1] | [How to mitigate] |
|
||||||
|
| [Risk 2] | [How to mitigate] |
|
||||||
|
|
||||||
|
## Rollback Plan
|
||||||
|
|
||||||
|
[How to revert if something goes wrong]
|
||||||
|
|
||||||
|
## References
|
||||||
|
|
||||||
|
- [Link to relevant docs]
|
||||||
|
- [Link to related issues]
|
||||||
|
- [Link to design specs]
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# CHECKLIST.md Template
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
# TASK-XXX Checklist
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
- [ ] Read README.md completely
|
||||||
|
- [ ] Understand the scope and success criteria
|
||||||
|
- [ ] Create branch: `git checkout -b task/XXX-short-name`
|
||||||
|
- [ ] Verify build works: `npm run build:editor`
|
||||||
|
|
||||||
|
## Phase 1: Research & Planning
|
||||||
|
- [ ] Identify all files that need changes
|
||||||
|
- [ ] Review existing patterns in codebase
|
||||||
|
- [ ] List assumptions and validate them
|
||||||
|
- [ ] Update NOTES.md with findings
|
||||||
|
|
||||||
|
## Phase 2: Implementation
|
||||||
|
- [ ] Step 1: [Description]
|
||||||
|
- [ ] Sub-step A
|
||||||
|
- [ ] Sub-step B
|
||||||
|
- [ ] Document in CHANGELOG.md
|
||||||
|
- [ ] Step 2: [Description]
|
||||||
|
- [ ] Sub-step A
|
||||||
|
- [ ] Sub-step B
|
||||||
|
- [ ] Document in CHANGELOG.md
|
||||||
|
- [ ] Step 3: [Description]
|
||||||
|
- [ ] Sub-step A
|
||||||
|
- [ ] Sub-step B
|
||||||
|
- [ ] Document in CHANGELOG.md
|
||||||
|
|
||||||
|
## Phase 3: Testing
|
||||||
|
- [ ] Write unit tests
|
||||||
|
- [ ] Write integration tests
|
||||||
|
- [ ] Run full test suite: `npm run test:editor`
|
||||||
|
- [ ] Run type check: `npx tsc --noEmit`
|
||||||
|
- [ ] Manual testing scenarios
|
||||||
|
|
||||||
|
## Phase 4: Documentation
|
||||||
|
- [ ] Add JSDoc to new public functions
|
||||||
|
- [ ] Update README if behavior changed
|
||||||
|
- [ ] Complete CHANGELOG.md with summary
|
||||||
|
- [ ] Update dev-docs if needed
|
||||||
|
|
||||||
|
## Phase 5: Completion
|
||||||
|
- [ ] Self-review all changes
|
||||||
|
- [ ] Verify all success criteria met
|
||||||
|
- [ ] Clean up any debug code
|
||||||
|
- [ ] Create pull request
|
||||||
|
- [ ] Mark task as complete
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# CHANGELOG.md Template
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
# TASK-XXX Changelog
|
||||||
|
|
||||||
|
## [Date] - [Your Name/Handle]
|
||||||
|
|
||||||
|
### Summary
|
||||||
|
[Brief summary of what was accomplished]
|
||||||
|
|
||||||
|
### Files Modified
|
||||||
|
- `path/to/file.ts` - [What changed and why]
|
||||||
|
- `path/to/file2.tsx` - [What changed and why]
|
||||||
|
|
||||||
|
### Files Created
|
||||||
|
- `path/to/newfile.ts` - [Purpose]
|
||||||
|
|
||||||
|
### Files Deleted
|
||||||
|
- `path/to/oldfile.ts` - [Why removed]
|
||||||
|
|
||||||
|
### Breaking Changes
|
||||||
|
- [Any breaking changes and migration path]
|
||||||
|
|
||||||
|
### Testing Notes
|
||||||
|
- [What was tested]
|
||||||
|
- [Any edge cases discovered]
|
||||||
|
|
||||||
|
### Known Issues
|
||||||
|
- [Any remaining issues or follow-up needed]
|
||||||
|
|
||||||
|
### Notes
|
||||||
|
- [Any other relevant information]
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# NOTES.md Template
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
# TASK-XXX Working Notes
|
||||||
|
|
||||||
|
## Research
|
||||||
|
|
||||||
|
### Existing Patterns Found
|
||||||
|
- [Pattern 1]: Found in `path/to/file.ts`
|
||||||
|
- [Pattern 2]: Found in `path/to/file2.ts`
|
||||||
|
|
||||||
|
### Questions to Resolve
|
||||||
|
- [ ] Question 1?
|
||||||
|
- [ ] Question 2?
|
||||||
|
|
||||||
|
### Assumptions
|
||||||
|
- Assumption 1: [Description] - ✅ Validated / ❓ Pending
|
||||||
|
- Assumption 2: [Description] - ✅ Validated / ❓ Pending
|
||||||
|
|
||||||
|
## Implementation Notes
|
||||||
|
|
||||||
|
### Approach Decisions
|
||||||
|
- Decided to [approach] because [reason]
|
||||||
|
- Rejected [alternative] because [reason]
|
||||||
|
|
||||||
|
### Gotchas / Surprises
|
||||||
|
- [Something unexpected discovered]
|
||||||
|
|
||||||
|
### Useful Commands
|
||||||
|
```bash
|
||||||
|
# Commands that were helpful
|
||||||
|
grep -r "pattern" packages/
|
||||||
|
```
|
||||||
|
|
||||||
|
## Debug Log
|
||||||
|
|
||||||
|
### [Date/Time]
|
||||||
|
- Trying: [what you're attempting]
|
||||||
|
- Result: [what happened]
|
||||||
|
- Next: [what to try next]
|
||||||
|
```
|
||||||
474
dev-docs/guidelines/CODING-STANDARDS.md
Normal file
474
dev-docs/guidelines/CODING-STANDARDS.md
Normal file
@@ -0,0 +1,474 @@
|
|||||||
|
# OpenNoodl Coding Standards
|
||||||
|
|
||||||
|
This document defines the coding style and patterns for OpenNoodl development.
|
||||||
|
|
||||||
|
## TypeScript Standards
|
||||||
|
|
||||||
|
### Type Safety
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// ✅ DO: Explicit types
|
||||||
|
function processNode(node: NodeGraphNode): ProcessResult {
|
||||||
|
return { success: true, data: node.data };
|
||||||
|
}
|
||||||
|
|
||||||
|
// ❌ DON'T: Any types
|
||||||
|
function processNode(node: any): any {
|
||||||
|
return { success: true, data: node.data };
|
||||||
|
}
|
||||||
|
|
||||||
|
// ❌ DON'T: TSFixme
|
||||||
|
function processNode(node: TSFixme): TSFixme {
|
||||||
|
return { success: true, data: node.data };
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### When Type is Truly Unknown
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// ✅ DO: Use unknown and narrow
|
||||||
|
function handleData(data: unknown): string {
|
||||||
|
if (typeof data === 'string') {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
if (typeof data === 'object' && data !== null && 'message' in data) {
|
||||||
|
return String((data as { message: unknown }).message);
|
||||||
|
}
|
||||||
|
return String(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ✅ DO: Document why if using any (rare)
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
// Any required here because external library doesn't export types
|
||||||
|
function handleExternalLib(input: any): void {
|
||||||
|
externalLib.process(input);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Interface Definitions
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// ✅ DO: Define interfaces for data structures
|
||||||
|
interface NodeConfig {
|
||||||
|
name: string;
|
||||||
|
displayName: string;
|
||||||
|
category: string;
|
||||||
|
inputs: Record<string, InputDefinition>;
|
||||||
|
outputs: Record<string, OutputDefinition>;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ✅ DO: Use type for unions/aliases
|
||||||
|
type NodeColor = 'data' | 'logic' | 'visual' | 'component';
|
||||||
|
|
||||||
|
// ✅ DO: Export types from dedicated files
|
||||||
|
// types.ts
|
||||||
|
export interface MyComponentProps {
|
||||||
|
value: string;
|
||||||
|
onChange: (value: string) => void;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## React Standards
|
||||||
|
|
||||||
|
### Functional Components
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// ✅ DO: Functional components with typed props
|
||||||
|
interface ButtonProps {
|
||||||
|
label: string;
|
||||||
|
onClick: () => void;
|
||||||
|
disabled?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function Button({ label, onClick, disabled = false }: ButtonProps) {
|
||||||
|
return (
|
||||||
|
<button onClick={onClick} disabled={disabled}>
|
||||||
|
{label}
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ❌ DON'T: Class components (unless lifecycle methods required)
|
||||||
|
class Button extends React.Component<ButtonProps> {
|
||||||
|
render() {
|
||||||
|
return <button>{this.props.label}</button>;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Hooks Usage
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// ✅ DO: Proper hook dependencies
|
||||||
|
const handleChange = useCallback((value: string) => {
|
||||||
|
onChange(value);
|
||||||
|
onValidate?.(value);
|
||||||
|
}, [onChange, onValidate]);
|
||||||
|
|
||||||
|
// ✅ DO: Cleanup in effects
|
||||||
|
useEffect(() => {
|
||||||
|
const handler = (e: Event) => { /* ... */ };
|
||||||
|
window.addEventListener('resize', handler);
|
||||||
|
return () => window.removeEventListener('resize', handler);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
// ❌ DON'T: Missing dependencies
|
||||||
|
const handleChange = useCallback((value: string) => {
|
||||||
|
onChange(value); // onChange not in deps!
|
||||||
|
}, []);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Component Organization
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Component file structure
|
||||||
|
import React, { useState, useCallback, useEffect } from 'react';
|
||||||
|
|
||||||
|
// External imports
|
||||||
|
import classNames from 'classnames';
|
||||||
|
|
||||||
|
// Internal imports
|
||||||
|
import { Icon, IconName } from '@noodl-core-ui/components/common/Icon';
|
||||||
|
import { useModel } from '@noodl-utils/hooks';
|
||||||
|
|
||||||
|
// Relative imports
|
||||||
|
import { ButtonProps } from './types';
|
||||||
|
import { validateInput } from './utils';
|
||||||
|
|
||||||
|
// Styles last
|
||||||
|
import css from './Button.module.scss';
|
||||||
|
|
||||||
|
// Types (if not in separate file)
|
||||||
|
interface LocalState {
|
||||||
|
isHovered: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Component
|
||||||
|
export function Button({ label, onClick, variant = 'primary' }: ButtonProps) {
|
||||||
|
// Hooks first
|
||||||
|
const [state, setState] = useState<LocalState>({ isHovered: false });
|
||||||
|
const model = useModel(SomeModel.instance);
|
||||||
|
|
||||||
|
// Callbacks
|
||||||
|
const handleClick = useCallback(() => {
|
||||||
|
onClick();
|
||||||
|
}, [onClick]);
|
||||||
|
|
||||||
|
// Effects
|
||||||
|
useEffect(() => {
|
||||||
|
// Setup
|
||||||
|
return () => {
|
||||||
|
// Cleanup
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
// Render helpers
|
||||||
|
const buttonClass = classNames(css.Button, css[variant]);
|
||||||
|
|
||||||
|
// Render
|
||||||
|
return (
|
||||||
|
<button className={buttonClass} onClick={handleClick}>
|
||||||
|
{label}
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## File Organization
|
||||||
|
|
||||||
|
### Directory Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
feature/
|
||||||
|
├── index.ts # Public exports only
|
||||||
|
├── FeatureName.tsx # Main component
|
||||||
|
├── FeatureName.module.scss
|
||||||
|
├── FeatureName.test.ts
|
||||||
|
├── types.ts # Type definitions
|
||||||
|
├── utils.ts # Helper functions
|
||||||
|
└── hooks.ts # Custom hooks (if any)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Index Files (Barrel Exports)
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// index.ts - Export only public API
|
||||||
|
export { FeatureName } from './FeatureName';
|
||||||
|
export type { FeatureNameProps } from './types';
|
||||||
|
|
||||||
|
// DON'T export internal utilities
|
||||||
|
```
|
||||||
|
|
||||||
|
### Import Order
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// 1. React
|
||||||
|
import React, { useState, useEffect } from 'react';
|
||||||
|
|
||||||
|
// 2. External packages (alphabetical)
|
||||||
|
import classNames from 'classnames';
|
||||||
|
import { motion } from 'framer-motion';
|
||||||
|
|
||||||
|
// 3. Internal packages (alphabetical by alias)
|
||||||
|
import { Icon } from '@noodl-core-ui/components/common/Icon';
|
||||||
|
import { NodeGraphModel } from '@noodl-models/nodegraphmodel';
|
||||||
|
import { guid } from '@noodl-utils/utils';
|
||||||
|
|
||||||
|
// 4. Relative imports (parent first, then siblings)
|
||||||
|
import { ParentComponent } from '../ParentComponent';
|
||||||
|
import { SiblingComponent } from './SiblingComponent';
|
||||||
|
import { localHelper } from './utils';
|
||||||
|
|
||||||
|
// 5. Types (if separate import needed)
|
||||||
|
import type { MyComponentProps } from './types';
|
||||||
|
|
||||||
|
// 6. Styles
|
||||||
|
import css from './MyComponent.module.scss';
|
||||||
|
```
|
||||||
|
|
||||||
|
## Documentation Standards
|
||||||
|
|
||||||
|
### JSDoc for Public APIs
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
/**
|
||||||
|
* Processes a node and returns the computed result.
|
||||||
|
*
|
||||||
|
* @param node - The node to process
|
||||||
|
* @param options - Processing options
|
||||||
|
* @returns The computed result with output values
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* ```typescript
|
||||||
|
* const result = processNode(myNode, { validate: true });
|
||||||
|
* console.log(result.outputs);
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
export function processNode(
|
||||||
|
node: NodeGraphNode,
|
||||||
|
options: ProcessOptions = {}
|
||||||
|
): ProcessResult {
|
||||||
|
// Implementation
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### File Headers
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
/**
|
||||||
|
* NodeGraphModel - Manages the structure of a node graph.
|
||||||
|
*
|
||||||
|
* This model handles:
|
||||||
|
* - Node creation and deletion
|
||||||
|
* - Connection management
|
||||||
|
* - Graph traversal
|
||||||
|
*
|
||||||
|
* @module models/NodeGraphModel
|
||||||
|
*/
|
||||||
|
```
|
||||||
|
|
||||||
|
### Inline Comments
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// ✅ DO: Explain "why", not "what"
|
||||||
|
// We batch updates here to prevent cascading re-renders
|
||||||
|
// when multiple inputs change in the same frame
|
||||||
|
this.scheduleAfterInputsHaveUpdated(() => {
|
||||||
|
this.processAllInputs();
|
||||||
|
});
|
||||||
|
|
||||||
|
// ❌ DON'T: State the obvious
|
||||||
|
// Loop through items
|
||||||
|
for (const item of items) {
|
||||||
|
// Process item
|
||||||
|
process(item);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Naming Conventions
|
||||||
|
|
||||||
|
### Files
|
||||||
|
|
||||||
|
| Type | Convention | Example |
|
||||||
|
|------|------------|---------|
|
||||||
|
| React Component | PascalCase | `NodePicker.tsx` |
|
||||||
|
| Utility | camelCase | `formatUtils.ts` |
|
||||||
|
| Types | camelCase or PascalCase | `types.ts` or `NodeTypes.ts` |
|
||||||
|
| Test | Match source + `.test` | `NodePicker.test.ts` |
|
||||||
|
| Styles | Match component + `.module` | `NodePicker.module.scss` |
|
||||||
|
|
||||||
|
### Code
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Constants: UPPER_SNAKE_CASE
|
||||||
|
const MAX_RETRY_COUNT = 3;
|
||||||
|
const DEFAULT_TIMEOUT_MS = 5000;
|
||||||
|
|
||||||
|
// Functions/Methods: camelCase
|
||||||
|
function processNodeGraph() {}
|
||||||
|
function calculateOffset() {}
|
||||||
|
|
||||||
|
// Classes/Interfaces/Types: PascalCase
|
||||||
|
class NodeGraphModel {}
|
||||||
|
interface ProcessOptions {}
|
||||||
|
type NodeColor = 'data' | 'logic';
|
||||||
|
|
||||||
|
// Private members: underscore prefix
|
||||||
|
class MyClass {
|
||||||
|
private _internalState: State;
|
||||||
|
private _processInternal(): void {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Boolean variables: is/has/should prefix
|
||||||
|
const isEnabled = true;
|
||||||
|
const hasChildren = node.children.length > 0;
|
||||||
|
const shouldUpdate = isDirty && isVisible;
|
||||||
|
```
|
||||||
|
|
||||||
|
## Error Handling
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// ✅ DO: Specific error types
|
||||||
|
class NodeNotFoundError extends Error {
|
||||||
|
constructor(nodeId: string) {
|
||||||
|
super(`Node not found: ${nodeId}`);
|
||||||
|
this.name = 'NodeNotFoundError';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ✅ DO: Handle errors gracefully
|
||||||
|
async function fetchData(): Promise<Result> {
|
||||||
|
try {
|
||||||
|
const response = await api.fetch();
|
||||||
|
return { success: true, data: response };
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to fetch data:', error);
|
||||||
|
return { success: false, error: getErrorMessage(error) };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ✅ DO: Type-safe error messages
|
||||||
|
function getErrorMessage(error: unknown): string {
|
||||||
|
if (error instanceof Error) return error.message;
|
||||||
|
return String(error);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Testing Standards
|
||||||
|
|
||||||
|
### Test File Structure
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { render, screen, fireEvent } from '@testing-library/react';
|
||||||
|
import { MyComponent } from './MyComponent';
|
||||||
|
|
||||||
|
describe('MyComponent', () => {
|
||||||
|
// Group related tests
|
||||||
|
describe('rendering', () => {
|
||||||
|
it('should render with default props', () => {
|
||||||
|
render(<MyComponent />);
|
||||||
|
expect(screen.getByRole('button')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('interactions', () => {
|
||||||
|
it('should call onClick when clicked', () => {
|
||||||
|
const onClick = jest.fn();
|
||||||
|
render(<MyComponent onClick={onClick} />);
|
||||||
|
|
||||||
|
fireEvent.click(screen.getByRole('button'));
|
||||||
|
|
||||||
|
expect(onClick).toHaveBeenCalledTimes(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### Test Naming
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// ✅ DO: Descriptive test names
|
||||||
|
it('should display error message when validation fails', () => {});
|
||||||
|
it('should disable submit button while loading', () => {});
|
||||||
|
|
||||||
|
// ❌ DON'T: Vague names
|
||||||
|
it('works', () => {});
|
||||||
|
it('test 1', () => {});
|
||||||
|
```
|
||||||
|
|
||||||
|
## Git Commit Messages
|
||||||
|
|
||||||
|
### Format
|
||||||
|
|
||||||
|
```
|
||||||
|
type(scope): description
|
||||||
|
|
||||||
|
[optional body]
|
||||||
|
|
||||||
|
[optional footer]
|
||||||
|
```
|
||||||
|
|
||||||
|
### Types
|
||||||
|
|
||||||
|
- `feat`: New feature
|
||||||
|
- `fix`: Bug fix
|
||||||
|
- `refactor`: Code change that neither fixes bug nor adds feature
|
||||||
|
- `docs`: Documentation only
|
||||||
|
- `test`: Adding or updating tests
|
||||||
|
- `chore`: Build process or auxiliary tool changes
|
||||||
|
|
||||||
|
### Examples
|
||||||
|
|
||||||
|
```
|
||||||
|
feat(editor): add breakpoint support to connections
|
||||||
|
|
||||||
|
fix(runtime): resolve memory leak in collection listener
|
||||||
|
|
||||||
|
refactor(property-panel): convert to functional component
|
||||||
|
|
||||||
|
docs(readme): update installation instructions
|
||||||
|
|
||||||
|
test(nodes): add unit tests for REST node
|
||||||
|
```
|
||||||
|
|
||||||
|
## Performance Guidelines
|
||||||
|
|
||||||
|
### React Performance
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// ✅ DO: Memoize expensive computations
|
||||||
|
const sortedItems = useMemo(() => {
|
||||||
|
return items.sort((a, b) => a.name.localeCompare(b.name));
|
||||||
|
}, [items]);
|
||||||
|
|
||||||
|
// ✅ DO: Memoize callbacks passed to children
|
||||||
|
const handleChange = useCallback((value: string) => {
|
||||||
|
onChange(value);
|
||||||
|
}, [onChange]);
|
||||||
|
|
||||||
|
// ✅ DO: Use React.memo for pure components
|
||||||
|
export const ListItem = React.memo(function ListItem({ item }: Props) {
|
||||||
|
return <div>{item.name}</div>;
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### General Performance
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// ✅ DO: Batch DOM operations
|
||||||
|
function updateNodes(nodes: Node[]) {
|
||||||
|
// Collect all changes first
|
||||||
|
const changes = nodes.map(calculateChange);
|
||||||
|
|
||||||
|
// Apply in single batch
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
changes.forEach(applyChange);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// ✅ DO: Debounce frequent events
|
||||||
|
const debouncedSearch = useMemo(
|
||||||
|
() => debounce((query: string) => performSearch(query), 300),
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
```
|
||||||
332
dev-docs/guidelines/GIT-WORKFLOW.md
Normal file
332
dev-docs/guidelines/GIT-WORKFLOW.md
Normal file
@@ -0,0 +1,332 @@
|
|||||||
|
# Git Workflow Guide
|
||||||
|
|
||||||
|
How to manage branches, commits, and pull requests for OpenNoodl development.
|
||||||
|
|
||||||
|
## Branch Naming
|
||||||
|
|
||||||
|
### Format
|
||||||
|
|
||||||
|
```
|
||||||
|
type/id-short-description
|
||||||
|
```
|
||||||
|
|
||||||
|
### Types
|
||||||
|
|
||||||
|
| Type | Use For | Example |
|
||||||
|
|------|---------|---------|
|
||||||
|
| `task` | Task documentation work | `task/001-dependency-updates` |
|
||||||
|
| `feature` | New features | `feature/vercel-deployment` |
|
||||||
|
| `fix` | Bug fixes | `fix/page-router-scroll` |
|
||||||
|
| `refactor` | Code improvements | `refactor/property-panel-hooks` |
|
||||||
|
| `docs` | Documentation only | `docs/api-reference` |
|
||||||
|
| `test` | Test additions | `test/rest-node-coverage` |
|
||||||
|
|
||||||
|
### Examples
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Task branches (from dev-docs)
|
||||||
|
git checkout -b task/001-dependency-updates
|
||||||
|
git checkout -b task/002-typescript-cleanup
|
||||||
|
|
||||||
|
# Feature branches
|
||||||
|
git checkout -b feature/add-oauth-support
|
||||||
|
git checkout -b feature/multi-project-windows
|
||||||
|
|
||||||
|
# Fix branches
|
||||||
|
git checkout -b fix/nested-router-scroll
|
||||||
|
git checkout -b fix/array-change-tracking
|
||||||
|
|
||||||
|
# Refactor branches
|
||||||
|
git checkout -b refactor/remove-class-components
|
||||||
|
git checkout -b refactor/data-node-architecture
|
||||||
|
```
|
||||||
|
|
||||||
|
## Commit Messages
|
||||||
|
|
||||||
|
### Format
|
||||||
|
|
||||||
|
```
|
||||||
|
type(scope): short description
|
||||||
|
|
||||||
|
[optional longer description]
|
||||||
|
|
||||||
|
[optional footer with references]
|
||||||
|
```
|
||||||
|
|
||||||
|
### Types
|
||||||
|
|
||||||
|
- `feat` - New feature
|
||||||
|
- `fix` - Bug fix
|
||||||
|
- `refactor` - Code restructuring (no behavior change)
|
||||||
|
- `docs` - Documentation changes
|
||||||
|
- `test` - Test additions/changes
|
||||||
|
- `chore` - Build/tooling changes
|
||||||
|
- `style` - Formatting (no code change)
|
||||||
|
- `perf` - Performance improvement
|
||||||
|
|
||||||
|
### Scopes
|
||||||
|
|
||||||
|
Use the affected area:
|
||||||
|
|
||||||
|
- `editor` - Main editor code
|
||||||
|
- `runtime` - Runtime engine
|
||||||
|
- `viewer` - Viewer/preview
|
||||||
|
- `ui` - Core UI components
|
||||||
|
- `build` - Build system
|
||||||
|
- `deps` - Dependencies
|
||||||
|
|
||||||
|
### Examples
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Features
|
||||||
|
git commit -m "feat(editor): add connection breakpoints"
|
||||||
|
git commit -m "feat(runtime): implement retry logic for REST node"
|
||||||
|
|
||||||
|
# Fixes
|
||||||
|
git commit -m "fix(viewer): resolve scroll jumping in nested routers"
|
||||||
|
git commit -m "fix(editor): prevent crash when deleting connected node"
|
||||||
|
|
||||||
|
# Refactoring
|
||||||
|
git commit -m "refactor(ui): convert PropertyPanel to functional component"
|
||||||
|
git commit -m "refactor(runtime): simplify collection change tracking"
|
||||||
|
|
||||||
|
# Docs
|
||||||
|
git commit -m "docs(readme): update installation instructions"
|
||||||
|
git commit -m "docs(api): add JSDoc to public methods"
|
||||||
|
|
||||||
|
# Tests
|
||||||
|
git commit -m "test(runtime): add unit tests for REST node"
|
||||||
|
git commit -m "test(editor): add integration tests for import flow"
|
||||||
|
|
||||||
|
# Chores
|
||||||
|
git commit -m "chore(deps): update webpack to 5.101.3"
|
||||||
|
git commit -m "chore(build): enable source maps in development"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Multi-line Commits
|
||||||
|
|
||||||
|
For complex changes:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git commit -m "feat(editor): add AI-powered node suggestions
|
||||||
|
|
||||||
|
- Integrate with OpenAI API for code analysis
|
||||||
|
- Add suggestion UI in node picker
|
||||||
|
- Cache suggestions for performance
|
||||||
|
|
||||||
|
Closes #123"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Workflow
|
||||||
|
|
||||||
|
### Starting Work
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. Ensure main is up to date
|
||||||
|
git checkout main
|
||||||
|
git pull origin main
|
||||||
|
|
||||||
|
# 2. Create your branch
|
||||||
|
git checkout -b task/001-dependency-updates
|
||||||
|
|
||||||
|
# 3. Make your changes...
|
||||||
|
|
||||||
|
# 4. Stage and commit frequently
|
||||||
|
git add -A
|
||||||
|
git commit -m "feat(deps): update React to v19"
|
||||||
|
```
|
||||||
|
|
||||||
|
### During Development
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Check status often
|
||||||
|
git status
|
||||||
|
|
||||||
|
# View your changes
|
||||||
|
git diff
|
||||||
|
|
||||||
|
# Stage specific files
|
||||||
|
git add packages/noodl-editor/package.json
|
||||||
|
|
||||||
|
# Commit logical chunks
|
||||||
|
git commit -m "fix(deps): resolve peer dependency conflicts"
|
||||||
|
|
||||||
|
# Push to remote (first time)
|
||||||
|
git push -u origin task/001-dependency-updates
|
||||||
|
|
||||||
|
# Push subsequent commits
|
||||||
|
git push
|
||||||
|
```
|
||||||
|
|
||||||
|
### Keeping Up to Date
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# If main has changed, rebase your work
|
||||||
|
git fetch origin
|
||||||
|
git rebase origin/main
|
||||||
|
|
||||||
|
# Resolve any conflicts, then continue
|
||||||
|
git add .
|
||||||
|
git rebase --continue
|
||||||
|
|
||||||
|
# Force push after rebase (your branch only!)
|
||||||
|
git push --force-with-lease
|
||||||
|
```
|
||||||
|
|
||||||
|
### Creating Pull Request
|
||||||
|
|
||||||
|
1. Push your branch to remote
|
||||||
|
2. Go to GitHub repository
|
||||||
|
3. Click "New Pull Request"
|
||||||
|
4. Select your branch
|
||||||
|
5. Fill in the template:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
## Summary
|
||||||
|
Brief description of changes
|
||||||
|
|
||||||
|
## Task Reference
|
||||||
|
TASK-001: Dependency Updates
|
||||||
|
|
||||||
|
## Changes Made
|
||||||
|
- Updated React to v19
|
||||||
|
- Fixed peer dependency conflicts
|
||||||
|
- Migrated to createRoot API
|
||||||
|
|
||||||
|
## Testing
|
||||||
|
- [ ] All existing tests pass
|
||||||
|
- [ ] Manual testing completed
|
||||||
|
- [ ] New tests added (if applicable)
|
||||||
|
|
||||||
|
## Checklist
|
||||||
|
- [ ] Code follows style guidelines
|
||||||
|
- [ ] Documentation updated
|
||||||
|
- [ ] CHANGELOG.md updated
|
||||||
|
- [ ] No console.log statements
|
||||||
|
```
|
||||||
|
|
||||||
|
### After PR Merged
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Switch to main
|
||||||
|
git checkout main
|
||||||
|
|
||||||
|
# Pull the merged changes
|
||||||
|
git pull origin main
|
||||||
|
|
||||||
|
# Delete your local branch
|
||||||
|
git branch -d task/001-dependency-updates
|
||||||
|
|
||||||
|
# Delete remote branch (if not auto-deleted)
|
||||||
|
git push origin --delete task/001-dependency-updates
|
||||||
|
```
|
||||||
|
|
||||||
|
## Common Scenarios
|
||||||
|
|
||||||
|
### Oops, Wrong Branch
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Stash your changes
|
||||||
|
git stash
|
||||||
|
|
||||||
|
# Switch to correct branch
|
||||||
|
git checkout correct-branch
|
||||||
|
|
||||||
|
# Apply your changes
|
||||||
|
git stash pop
|
||||||
|
```
|
||||||
|
|
||||||
|
### Need to Undo Last Commit
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Undo commit but keep changes
|
||||||
|
git reset --soft HEAD~1
|
||||||
|
|
||||||
|
# Undo commit and discard changes
|
||||||
|
git reset --hard HEAD~1
|
||||||
|
```
|
||||||
|
|
||||||
|
### Need to Update Commit Message
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Most recent commit
|
||||||
|
git commit --amend -m "new message"
|
||||||
|
|
||||||
|
# Older commit (interactive rebase)
|
||||||
|
git rebase -i HEAD~3
|
||||||
|
# Change 'pick' to 'reword' for the commit
|
||||||
|
```
|
||||||
|
|
||||||
|
### Accidentally Committed to Main
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Create a branch with your commits
|
||||||
|
git branch my-feature
|
||||||
|
|
||||||
|
# Reset main to origin
|
||||||
|
git reset --hard origin/main
|
||||||
|
|
||||||
|
# Switch to your feature branch
|
||||||
|
git checkout my-feature
|
||||||
|
```
|
||||||
|
|
||||||
|
### Merge Conflicts
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# During rebase or merge, if conflicts occur:
|
||||||
|
|
||||||
|
# 1. Open conflicted files and resolve
|
||||||
|
# Look for <<<<<<< ======= >>>>>>> markers
|
||||||
|
|
||||||
|
# 2. Stage resolved files
|
||||||
|
git add resolved-file.ts
|
||||||
|
|
||||||
|
# 3. Continue the rebase/merge
|
||||||
|
git rebase --continue
|
||||||
|
# or
|
||||||
|
git merge --continue
|
||||||
|
```
|
||||||
|
|
||||||
|
## Branch Protection
|
||||||
|
|
||||||
|
The `main` branch has these protections:
|
||||||
|
|
||||||
|
- Requires pull request
|
||||||
|
- Requires passing CI checks
|
||||||
|
- Requires up-to-date branch
|
||||||
|
- No force pushes allowed
|
||||||
|
|
||||||
|
## Tips
|
||||||
|
|
||||||
|
### Useful Aliases
|
||||||
|
|
||||||
|
Add to your `~/.gitconfig`:
|
||||||
|
|
||||||
|
```ini
|
||||||
|
[alias]
|
||||||
|
st = status
|
||||||
|
co = checkout
|
||||||
|
br = branch
|
||||||
|
ci = commit
|
||||||
|
lg = log --oneline --graph --all
|
||||||
|
unstage = reset HEAD --
|
||||||
|
last = log -1 HEAD
|
||||||
|
branches = branch -a
|
||||||
|
```
|
||||||
|
|
||||||
|
### Before Every PR
|
||||||
|
|
||||||
|
1. Run tests: `npm run test:editor`
|
||||||
|
2. Run type check: `npx tsc --noEmit`
|
||||||
|
3. Run linter: `npx eslint packages/ --fix`
|
||||||
|
4. Review your diff: `git diff main`
|
||||||
|
5. Check commit history: `git log --oneline main..HEAD`
|
||||||
|
|
||||||
|
### Good Commit Hygiene
|
||||||
|
|
||||||
|
- Commit early and often
|
||||||
|
- Each commit should be atomic (one logical change)
|
||||||
|
- Commits should compile and pass tests
|
||||||
|
- Write meaningful commit messages
|
||||||
|
- Don't commit generated files
|
||||||
|
- Don't commit debug code
|
||||||
378
dev-docs/reference/CODEBASE-MAP.md
Normal file
378
dev-docs/reference/CODEBASE-MAP.md
Normal file
@@ -0,0 +1,378 @@
|
|||||||
|
# OpenNoodl Codebase Quick Navigation
|
||||||
|
|
||||||
|
## 🗺️ Package Map
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────────────────────────────────────────────┐
|
||||||
|
│ MONOREPO ROOT │
|
||||||
|
├─────────────────────────────────────────────────────────────────────────┤
|
||||||
|
│ package.json → Workspace config, global scripts │
|
||||||
|
│ lerna.json → Monorepo management │
|
||||||
|
│ scripts/ → Build and CI scripts │
|
||||||
|
└─────────────────────────────────────────────────────────────────────────┘
|
||||||
|
│
|
||||||
|
┌───────────────────────────┼───────────────────────────┐
|
||||||
|
▼ ▼ ▼
|
||||||
|
┌───────────────────┐ ┌───────────────────┐ ┌───────────────────┐
|
||||||
|
│ EDITOR (GPL) │ │ RUNTIME (MIT) │ │ UI LIBRARY │
|
||||||
|
│ noodl-editor │ │ noodl-runtime │ │ noodl-core-ui │
|
||||||
|
│ │ │ │ │ │
|
||||||
|
│ • Electron app │ │ • Node engine │ │ • React components│
|
||||||
|
│ • React UI │ │ • Data flow │ │ • Storybook │
|
||||||
|
│ • Property panels │ │ • Event system │ │ • Styling │
|
||||||
|
└───────────────────┘ └───────────────────┘ └───────────────────┘
|
||||||
|
│ │
|
||||||
|
│ ▼
|
||||||
|
│ ┌───────────────────┐
|
||||||
|
│ │ VIEWER (MIT) │
|
||||||
|
│ │ noodl-viewer-react│
|
||||||
|
│ │ │
|
||||||
|
│ │ • React runtime │
|
||||||
|
│ │ • Visual nodes │
|
||||||
|
│ │ • DOM handling │
|
||||||
|
│ └───────────────────┘
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
┌───────────────────────────────────────────────────────────────────────┐
|
||||||
|
│ PLATFORM LAYER │
|
||||||
|
├───────────────────┬───────────────────┬───────────────────────────────┤
|
||||||
|
│ noodl-platform │ platform-electron │ platform-node │
|
||||||
|
│ (abstraction) │ (desktop impl) │ (server impl) │
|
||||||
|
└───────────────────┴───────────────────┴───────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📁 Key Directories
|
||||||
|
|
||||||
|
### noodl-editor (Main Application)
|
||||||
|
|
||||||
|
```
|
||||||
|
packages/noodl-editor/src/
|
||||||
|
├── editor/src/
|
||||||
|
│ ├── models/ # 🎯 Business logic & data
|
||||||
|
│ │ ├── projectmodel.ts → Project state
|
||||||
|
│ │ ├── nodegraphmodel.ts → Graph structure
|
||||||
|
│ │ ├── componentmodel.ts → Components
|
||||||
|
│ │ ├── nodelibrary/ → Node type registry
|
||||||
|
│ │ ├── AiAssistant/ → AI features
|
||||||
|
│ │ └── sidebar/ → Sidebar state
|
||||||
|
│ │
|
||||||
|
│ ├── views/ # 🖥️ UI components
|
||||||
|
│ │ ├── nodegrapheditor.ts → Canvas/graph editor
|
||||||
|
│ │ ├── panels/ → Property panels
|
||||||
|
│ │ ├── NodePicker/ → Node creation UI
|
||||||
|
│ │ ├── documents/ → Document views
|
||||||
|
│ │ └── popups/ → Modal dialogs
|
||||||
|
│ │
|
||||||
|
│ ├── utils/ # 🔧 Utilities
|
||||||
|
│ │ ├── CodeEditor/ → Monaco integration
|
||||||
|
│ │ ├── filesystem.ts → File operations
|
||||||
|
│ │ └── projectimporter.js → Import/export
|
||||||
|
│ │
|
||||||
|
│ ├── store/ # 💾 Persistent state
|
||||||
|
│ │ └── AiAssistantStore.ts → AI settings
|
||||||
|
│ │
|
||||||
|
│ └── pages/ # 📄 Page components
|
||||||
|
│ └── EditorPage/ → Main editor page
|
||||||
|
│
|
||||||
|
├── main/ # ⚡ Electron main process
|
||||||
|
│ └── main.js → App entry point
|
||||||
|
│
|
||||||
|
└── shared/ # 🔗 Shared utilities
|
||||||
|
└── utils/
|
||||||
|
└── EventDispatcher.ts → Pub/sub system
|
||||||
|
```
|
||||||
|
|
||||||
|
### noodl-runtime (Execution Engine)
|
||||||
|
|
||||||
|
```
|
||||||
|
packages/noodl-runtime/
|
||||||
|
├── src/
|
||||||
|
│ ├── nodes/ # 📦 Node implementations
|
||||||
|
│ │ └── std-library/
|
||||||
|
│ │ ├── data/ → Data nodes (REST, DB, etc.)
|
||||||
|
│ │ ├── logic/ → Logic nodes
|
||||||
|
│ │ └── events/ → Event nodes
|
||||||
|
│ │
|
||||||
|
│ ├── node.js # Base node class
|
||||||
|
│ ├── nodedefinition.js # Node definition API
|
||||||
|
│ ├── noderegister.js # Node registry
|
||||||
|
│ ├── nodescope.js # Component scope
|
||||||
|
│ └── nodecontext.js # Runtime context
|
||||||
|
│
|
||||||
|
└── noodl-runtime.js # Main runtime entry
|
||||||
|
```
|
||||||
|
|
||||||
|
### noodl-viewer-react (React Runtime)
|
||||||
|
|
||||||
|
```
|
||||||
|
packages/noodl-viewer-react/src/
|
||||||
|
├── nodes/ # 🎨 Visual nodes
|
||||||
|
│ ├── basic/ → Group, Text, Image
|
||||||
|
│ ├── controls/ → Button, Input, Checkbox
|
||||||
|
│ ├── navigation/ → PageRouter, Page
|
||||||
|
│ └── std-library/ → Standard library nodes
|
||||||
|
│
|
||||||
|
└── react-component-node.js # React node wrapper
|
||||||
|
```
|
||||||
|
|
||||||
|
### noodl-core-ui (Component Library)
|
||||||
|
|
||||||
|
```
|
||||||
|
packages/noodl-core-ui/src/
|
||||||
|
├── components/
|
||||||
|
│ ├── common/ # 🧩 Basic components
|
||||||
|
│ │ ├── Icon/
|
||||||
|
│ │ └── ActivityIndicator/
|
||||||
|
│ │
|
||||||
|
│ ├── inputs/ # 📝 Form controls
|
||||||
|
│ │ ├── TextInput/
|
||||||
|
│ │ ├── PrimaryButton/
|
||||||
|
│ │ └── Checkbox/
|
||||||
|
│ │
|
||||||
|
│ ├── layout/ # 📐 Layout components
|
||||||
|
│ │ ├── Box/
|
||||||
|
│ │ ├── Container/
|
||||||
|
│ │ └── Tabs/
|
||||||
|
│ │
|
||||||
|
│ ├── popups/ # 💬 Dialogs & menus
|
||||||
|
│ │ ├── MenuDialog/
|
||||||
|
│ │ └── PopupToolbar/
|
||||||
|
│ │
|
||||||
|
│ └── ai/ # 🤖 AI UI components
|
||||||
|
│ ├── AiChatBox/
|
||||||
|
│ └── AiChatMessage/
|
||||||
|
│
|
||||||
|
└── styles/ # 🎨 Global styles
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔍 Finding Things
|
||||||
|
|
||||||
|
### Search Patterns
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Find a file by name
|
||||||
|
find packages/ -name "*NodeGraph*" -type f
|
||||||
|
|
||||||
|
# Find where a function is defined
|
||||||
|
grep -rn "function processNode" packages/
|
||||||
|
|
||||||
|
# Find where something is imported/used
|
||||||
|
grep -r "import.*from.*nodegraphmodel" packages/
|
||||||
|
|
||||||
|
# Find all usages of a component
|
||||||
|
grep -r "<NodeEditor" packages/ --include="*.tsx"
|
||||||
|
|
||||||
|
# Find TODO/FIXME comments
|
||||||
|
grep -rn "TODO\|FIXME" packages/noodl-editor/src
|
||||||
|
```
|
||||||
|
|
||||||
|
### Common Search Targets
|
||||||
|
|
||||||
|
| Looking for... | Search pattern |
|
||||||
|
|----------------|----------------|
|
||||||
|
| Node definitions | `packages/noodl-runtime/src/nodes/` |
|
||||||
|
| React visual nodes | `packages/noodl-viewer-react/src/nodes/` |
|
||||||
|
| UI components | `packages/noodl-core-ui/src/components/` |
|
||||||
|
| Models/state | `packages/noodl-editor/src/editor/src/models/` |
|
||||||
|
| Property panels | `packages/noodl-editor/src/editor/src/views/panels/` |
|
||||||
|
| Tests | `packages/noodl-editor/tests/` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🚀 Quick Commands
|
||||||
|
|
||||||
|
### Development
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Start everything
|
||||||
|
npm run dev
|
||||||
|
|
||||||
|
# Start just the editor (faster)
|
||||||
|
npm run start:editor
|
||||||
|
|
||||||
|
# Start Storybook (UI components)
|
||||||
|
npm run start:storybook
|
||||||
|
|
||||||
|
# Start viewer dev server
|
||||||
|
npm run start:viewer
|
||||||
|
```
|
||||||
|
|
||||||
|
### Building
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Build editor
|
||||||
|
npm run build:editor
|
||||||
|
|
||||||
|
# Create distributable package
|
||||||
|
npm run build:editor:pack
|
||||||
|
|
||||||
|
# Build cloud runtime
|
||||||
|
npm run build:cloud-runtime
|
||||||
|
```
|
||||||
|
|
||||||
|
### Testing
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Run all editor tests
|
||||||
|
npm run test:editor
|
||||||
|
|
||||||
|
# Run platform tests
|
||||||
|
npm run test:platform
|
||||||
|
```
|
||||||
|
|
||||||
|
### Code Quality
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Type check
|
||||||
|
npx tsc --noEmit
|
||||||
|
|
||||||
|
# Lint
|
||||||
|
npx eslint packages/noodl-editor/src
|
||||||
|
|
||||||
|
# Format
|
||||||
|
npx prettier --write "packages/**/*.{ts,tsx}"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔗 Key Files Reference
|
||||||
|
|
||||||
|
### Configuration
|
||||||
|
|
||||||
|
| File | Purpose |
|
||||||
|
|------|---------|
|
||||||
|
| `package.json` | Root workspace config |
|
||||||
|
| `lerna.json` | Monorepo settings |
|
||||||
|
| `tsconfig.json` | TypeScript config |
|
||||||
|
| `.eslintrc.js` | Linting rules |
|
||||||
|
| `.prettierrc` | Code formatting |
|
||||||
|
|
||||||
|
### Entry Points
|
||||||
|
|
||||||
|
| File | Purpose |
|
||||||
|
|------|---------|
|
||||||
|
| `noodl-editor/src/main/main.js` | Electron main process |
|
||||||
|
| `noodl-editor/src/editor/src/index.js` | Renderer entry |
|
||||||
|
| `noodl-runtime/noodl-runtime.js` | Runtime engine |
|
||||||
|
| `noodl-viewer-react/index.js` | React runtime |
|
||||||
|
|
||||||
|
### Core Models
|
||||||
|
|
||||||
|
| File | Purpose |
|
||||||
|
|------|---------|
|
||||||
|
| `projectmodel.ts` | Project state management |
|
||||||
|
| `nodegraphmodel.ts` | Graph data structure |
|
||||||
|
| `componentmodel.ts` | Component definitions |
|
||||||
|
| `nodelibrary.ts` | Node type registry |
|
||||||
|
|
||||||
|
### Important Views
|
||||||
|
|
||||||
|
| File | Purpose |
|
||||||
|
|------|---------|
|
||||||
|
| `nodegrapheditor.ts` | Main canvas editor |
|
||||||
|
| `EditorPage.tsx` | Main page layout |
|
||||||
|
| `NodePicker.tsx` | Node creation panel |
|
||||||
|
| `PropertyEditor/` | Property panels |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🏷️ Type System
|
||||||
|
|
||||||
|
### Key Types (global.d.ts)
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// TSFixme - Type escape hatch (TO BE REMOVED)
|
||||||
|
type TSFixme = any;
|
||||||
|
|
||||||
|
// Node colors
|
||||||
|
type NodeColor = 'data' | 'visual' | 'logic' | 'component' | 'javascript';
|
||||||
|
|
||||||
|
// CSS modules
|
||||||
|
declare module '*.scss' {
|
||||||
|
const styles: { readonly [key: string]: string };
|
||||||
|
export default styles;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Common Interfaces
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Node graph structures (nodegraphmodel.ts)
|
||||||
|
interface NodeGraphNode {
|
||||||
|
id: string;
|
||||||
|
type: string;
|
||||||
|
x: number;
|
||||||
|
y: number;
|
||||||
|
parameters: Record<string, any>;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Connection {
|
||||||
|
fromId: string;
|
||||||
|
fromPort: string;
|
||||||
|
toId: string;
|
||||||
|
toPort: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Component structure (componentmodel.ts)
|
||||||
|
interface ComponentModel {
|
||||||
|
name: string;
|
||||||
|
graph: NodeGraphModel;
|
||||||
|
metadata: Record<string, any>;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📝 Path Aliases
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Configured in tsconfig.json
|
||||||
|
@noodl-models/ → packages/noodl-editor/src/editor/src/models/
|
||||||
|
@noodl-utils/ → packages/noodl-editor/src/editor/src/utils/
|
||||||
|
@noodl-contexts/ → packages/noodl-editor/src/editor/src/contexts/
|
||||||
|
@noodl-hooks/ → packages/noodl-editor/src/editor/src/hooks/
|
||||||
|
@noodl-constants/ → packages/noodl-editor/src/editor/src/constants/
|
||||||
|
@noodl-core-ui/ → packages/noodl-core-ui/src/
|
||||||
|
@noodl/platform → packages/noodl-platform/src/
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🚨 Common Issues
|
||||||
|
|
||||||
|
### Build Problems
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Clear caches
|
||||||
|
rm -rf node_modules/.cache
|
||||||
|
rm -rf packages/*/node_modules/.cache
|
||||||
|
|
||||||
|
# Reinstall dependencies
|
||||||
|
rm -rf node_modules
|
||||||
|
npm install
|
||||||
|
```
|
||||||
|
|
||||||
|
### TypeScript Errors
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Check for circular dependencies
|
||||||
|
npx madge --circular packages/noodl-editor/src
|
||||||
|
```
|
||||||
|
|
||||||
|
### Electron Issues
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Clear app data (macOS)
|
||||||
|
rm -rf ~/Library/Application\ Support/OpenNoodl/
|
||||||
|
|
||||||
|
# Rebuild native modules
|
||||||
|
npm run rebuild
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*Quick reference card for OpenNoodl development. Print or pin to your IDE!*
|
||||||
253
dev-docs/reference/COMMON-ISSUES.md
Normal file
253
dev-docs/reference/COMMON-ISSUES.md
Normal file
@@ -0,0 +1,253 @@
|
|||||||
|
# Common Issues & Troubleshooting
|
||||||
|
|
||||||
|
Solutions to frequently encountered problems when developing OpenNoodl.
|
||||||
|
|
||||||
|
## Build Issues
|
||||||
|
|
||||||
|
### "Module not found" Errors
|
||||||
|
|
||||||
|
**Symptom**: Build fails with `Cannot find module '@noodl-xxx/...'`
|
||||||
|
|
||||||
|
**Solutions**:
|
||||||
|
1. Run `npm install` from root directory
|
||||||
|
2. Check if package exists in `packages/`
|
||||||
|
3. Verify tsconfig paths are correct
|
||||||
|
4. Try: `rm -rf node_modules && npm install`
|
||||||
|
|
||||||
|
### "Peer dependency" Warnings
|
||||||
|
|
||||||
|
**Symptom**: npm install shows peer dependency warnings
|
||||||
|
|
||||||
|
**Solutions**:
|
||||||
|
1. Check if versions are compatible
|
||||||
|
2. Update the conflicting package
|
||||||
|
3. Last resort: `npm install --legacy-peer-deps`
|
||||||
|
4. Document why in CHANGELOG.md
|
||||||
|
|
||||||
|
### TypeScript Errors After Update
|
||||||
|
|
||||||
|
**Symptom**: Types that worked before now fail
|
||||||
|
|
||||||
|
**Solutions**:
|
||||||
|
1. Run `npx tsc --noEmit` to see all errors
|
||||||
|
2. Check if `@types/*` packages need updating
|
||||||
|
3. Look for breaking changes in updated packages
|
||||||
|
4. Check `tsconfig.json` for configuration issues
|
||||||
|
|
||||||
|
### Webpack Build Hangs
|
||||||
|
|
||||||
|
**Symptom**: Build starts but never completes
|
||||||
|
|
||||||
|
**Solutions**:
|
||||||
|
1. Check for circular imports: `npx madge --circular packages/`
|
||||||
|
2. Increase Node memory: `NODE_OPTIONS=--max_old_space_size=4096`
|
||||||
|
3. Check for infinite loops in build scripts
|
||||||
|
4. Try building individual packages
|
||||||
|
|
||||||
|
## Runtime Issues
|
||||||
|
|
||||||
|
### Hot Reload Not Working
|
||||||
|
|
||||||
|
**Symptom**: Changes don't appear without full restart
|
||||||
|
|
||||||
|
**Solutions**:
|
||||||
|
1. Check webpack dev server is running
|
||||||
|
2. Verify file is being watched (check webpack config)
|
||||||
|
3. Clear browser cache
|
||||||
|
4. Check for syntax errors preventing reload
|
||||||
|
5. Restart dev server: `npm run dev`
|
||||||
|
|
||||||
|
### Node Not Appearing in Picker
|
||||||
|
|
||||||
|
**Symptom**: Created a node but it doesn't show up
|
||||||
|
|
||||||
|
**Solutions**:
|
||||||
|
1. Verify node is exported in `nodelibraryexport.js`
|
||||||
|
2. Check `category` is valid
|
||||||
|
3. Verify no JavaScript errors in node definition
|
||||||
|
4. Restart the editor
|
||||||
|
|
||||||
|
### "Cannot read property of undefined"
|
||||||
|
|
||||||
|
**Symptom**: Runtime error accessing object properties
|
||||||
|
|
||||||
|
**Solutions**:
|
||||||
|
1. Add null checks: `obj?.property`
|
||||||
|
2. Verify data is loaded before access
|
||||||
|
3. Check async timing issues
|
||||||
|
4. Add defensive initialization
|
||||||
|
|
||||||
|
### State Not Updating
|
||||||
|
|
||||||
|
**Symptom**: Changed input but output doesn't update
|
||||||
|
|
||||||
|
**Solutions**:
|
||||||
|
1. Verify `flagOutputDirty()` is called
|
||||||
|
2. Check if batching is interfering
|
||||||
|
3. Verify connection exists in graph
|
||||||
|
4. Check for conditional logic preventing update
|
||||||
|
|
||||||
|
## Editor Issues
|
||||||
|
|
||||||
|
### Preview Not Loading
|
||||||
|
|
||||||
|
**Symptom**: Preview panel is blank or shows error
|
||||||
|
|
||||||
|
**Solutions**:
|
||||||
|
1. Check browser console for errors
|
||||||
|
2. Verify viewer runtime is built
|
||||||
|
3. Check for JavaScript errors in project
|
||||||
|
4. Try creating a new empty project
|
||||||
|
|
||||||
|
### Property Panel Empty
|
||||||
|
|
||||||
|
**Symptom**: Selected node but no properties shown
|
||||||
|
|
||||||
|
**Solutions**:
|
||||||
|
1. Verify node has `inputs` defined
|
||||||
|
2. Check `group` values are set
|
||||||
|
3. Look for errors in property panel code
|
||||||
|
4. Verify node type is registered
|
||||||
|
|
||||||
|
### Canvas Performance Issues
|
||||||
|
|
||||||
|
**Symptom**: Node graph is slow/laggy
|
||||||
|
|
||||||
|
**Solutions**:
|
||||||
|
1. Reduce number of visible nodes
|
||||||
|
2. Check for expensive render operations
|
||||||
|
3. Verify no infinite update loops
|
||||||
|
4. Profile with Chrome DevTools
|
||||||
|
|
||||||
|
## Git Issues
|
||||||
|
|
||||||
|
### Merge Conflicts in package-lock.json
|
||||||
|
|
||||||
|
**Symptom**: Complex conflicts in lock file
|
||||||
|
|
||||||
|
**Solutions**:
|
||||||
|
1. Accept either version
|
||||||
|
2. Run `npm install` to regenerate
|
||||||
|
3. Commit the regenerated lock file
|
||||||
|
|
||||||
|
### Large File Warnings
|
||||||
|
|
||||||
|
**Symptom**: Git warns about large files
|
||||||
|
|
||||||
|
**Solutions**:
|
||||||
|
1. Check `.gitignore` includes build outputs
|
||||||
|
2. Verify `node_modules` not committed
|
||||||
|
3. Use Git LFS for large assets if needed
|
||||||
|
|
||||||
|
## Testing Issues
|
||||||
|
|
||||||
|
### Tests Timeout
|
||||||
|
|
||||||
|
**Symptom**: Tests hang or timeout
|
||||||
|
|
||||||
|
**Solutions**:
|
||||||
|
1. Check for unresolved promises
|
||||||
|
2. Verify mocks are set up correctly
|
||||||
|
3. Increase timeout if legitimately slow
|
||||||
|
4. Check for infinite loops
|
||||||
|
|
||||||
|
### Snapshot Tests Failing
|
||||||
|
|
||||||
|
**Symptom**: Snapshot doesn't match
|
||||||
|
|
||||||
|
**Solutions**:
|
||||||
|
1. Review the diff carefully
|
||||||
|
2. If change is intentional: `npm test -- -u`
|
||||||
|
3. If unexpected, investigate component changes
|
||||||
|
|
||||||
|
## Debugging Tips
|
||||||
|
|
||||||
|
### Enable Verbose Logging
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Add to see more info
|
||||||
|
console.log('[DEBUG]', variable);
|
||||||
|
|
||||||
|
// For node execution
|
||||||
|
this.context.debugLog('Message', data);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Use Chrome DevTools
|
||||||
|
|
||||||
|
1. Open editor
|
||||||
|
2. Press `Cmd+Option+I` (Mac) or `Ctrl+Shift+I` (Windows)
|
||||||
|
3. Check Console for errors
|
||||||
|
4. Use Sources for breakpoints
|
||||||
|
5. Use Network for API issues
|
||||||
|
|
||||||
|
### Inspect Node State
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// In browser console
|
||||||
|
const node = NoodlRuntime.instance.getNodeById('node-id');
|
||||||
|
console.log(node._internal);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Check Event Flow
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Add listener to see all events
|
||||||
|
model.on('*', (event, data) => {
|
||||||
|
console.log('Event:', event, data);
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
## Error Messages
|
||||||
|
|
||||||
|
### "Maximum call stack size exceeded"
|
||||||
|
|
||||||
|
**Cause**: Infinite recursion or circular dependency
|
||||||
|
|
||||||
|
**Fix**:
|
||||||
|
1. Check for circular imports
|
||||||
|
2. Add base case to recursive functions
|
||||||
|
3. Break dependency cycles
|
||||||
|
|
||||||
|
### "Cannot access before initialization"
|
||||||
|
|
||||||
|
**Cause**: Temporal dead zone with `let`/`const`
|
||||||
|
|
||||||
|
**Fix**:
|
||||||
|
1. Check import order
|
||||||
|
2. Move declaration before usage
|
||||||
|
3. Check for circular imports
|
||||||
|
|
||||||
|
### "Unexpected token"
|
||||||
|
|
||||||
|
**Cause**: Syntax error or wrong file type
|
||||||
|
|
||||||
|
**Fix**:
|
||||||
|
1. Check file extension matches content
|
||||||
|
2. Verify JSON is valid
|
||||||
|
3. Check for missing brackets/quotes
|
||||||
|
|
||||||
|
### "ENOENT: no such file or directory"
|
||||||
|
|
||||||
|
**Cause**: Missing file or wrong path
|
||||||
|
|
||||||
|
**Fix**:
|
||||||
|
1. Verify file exists
|
||||||
|
2. Check path is correct (case-sensitive)
|
||||||
|
3. Ensure build step completed
|
||||||
|
|
||||||
|
## Getting Help
|
||||||
|
|
||||||
|
1. Search this document first
|
||||||
|
2. Check existing task documentation
|
||||||
|
3. Search codebase for similar patterns
|
||||||
|
4. Check GitHub issues
|
||||||
|
5. Ask in community channels
|
||||||
|
|
||||||
|
## Contributing Solutions
|
||||||
|
|
||||||
|
Found a solution not listed here? Add it!
|
||||||
|
|
||||||
|
1. Edit this file
|
||||||
|
2. Follow the format: Symptom → Solutions
|
||||||
|
3. Include specific commands when helpful
|
||||||
|
4. Submit PR with your addition
|
||||||
446
dev-docs/reference/NODE-PATTERNS.md
Normal file
446
dev-docs/reference/NODE-PATTERNS.md
Normal file
@@ -0,0 +1,446 @@
|
|||||||
|
# Node Patterns Reference
|
||||||
|
|
||||||
|
How to create and modify nodes in OpenNoodl.
|
||||||
|
|
||||||
|
## Node Types
|
||||||
|
|
||||||
|
There are two main types of nodes:
|
||||||
|
|
||||||
|
1. **Runtime Nodes** (`noodl-runtime`) - Logic, data, utilities
|
||||||
|
2. **Visual Nodes** (`noodl-viewer-react`) - React components for UI
|
||||||
|
|
||||||
|
## Basic Node Structure
|
||||||
|
|
||||||
|
### Runtime Node (JavaScript)
|
||||||
|
|
||||||
|
Location: `packages/noodl-runtime/src/nodes/`
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const MyNode = {
|
||||||
|
// === METADATA ===
|
||||||
|
name: 'My.Custom.Node', // Unique identifier
|
||||||
|
displayName: 'My Custom Node', // Shown in UI
|
||||||
|
category: 'Custom', // Node picker category
|
||||||
|
color: 'data', // Node color theme
|
||||||
|
docs: 'https://docs.example.com', // Documentation link
|
||||||
|
|
||||||
|
// === INITIALIZATION ===
|
||||||
|
initialize() {
|
||||||
|
// Called when node is created
|
||||||
|
this._internal.myValue = '';
|
||||||
|
this._internal.callbacks = [];
|
||||||
|
},
|
||||||
|
|
||||||
|
// === INPUTS ===
|
||||||
|
inputs: {
|
||||||
|
// Simple input
|
||||||
|
textInput: {
|
||||||
|
type: 'string',
|
||||||
|
displayName: 'Text Input',
|
||||||
|
group: 'General',
|
||||||
|
default: '',
|
||||||
|
set(value) {
|
||||||
|
this._internal.textInput = value;
|
||||||
|
this.flagOutputDirty('result');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// Number with validation
|
||||||
|
numberInput: {
|
||||||
|
type: 'number',
|
||||||
|
displayName: 'Number',
|
||||||
|
group: 'General',
|
||||||
|
default: 0,
|
||||||
|
set(value) {
|
||||||
|
if (typeof value !== 'number') return;
|
||||||
|
this._internal.numberInput = value;
|
||||||
|
this.flagOutputDirty('result');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// Signal input (trigger)
|
||||||
|
doAction: {
|
||||||
|
type: 'signal',
|
||||||
|
displayName: 'Do Action',
|
||||||
|
group: 'Actions',
|
||||||
|
valueChangedToTrue() {
|
||||||
|
// Called when signal received
|
||||||
|
this.performAction();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// Boolean toggle
|
||||||
|
enabled: {
|
||||||
|
type: 'boolean',
|
||||||
|
displayName: 'Enabled',
|
||||||
|
group: 'General',
|
||||||
|
default: true,
|
||||||
|
set(value) {
|
||||||
|
this._internal.enabled = value;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// Dropdown/enum
|
||||||
|
mode: {
|
||||||
|
type: {
|
||||||
|
name: 'enum',
|
||||||
|
enums: [
|
||||||
|
{ value: 'mode1', label: 'Mode 1' },
|
||||||
|
{ value: 'mode2', label: 'Mode 2' }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
displayName: 'Mode',
|
||||||
|
group: 'General',
|
||||||
|
default: 'mode1',
|
||||||
|
set(value) {
|
||||||
|
this._internal.mode = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// === OUTPUTS ===
|
||||||
|
outputs: {
|
||||||
|
// Value output
|
||||||
|
result: {
|
||||||
|
type: 'string',
|
||||||
|
displayName: 'Result',
|
||||||
|
group: 'General',
|
||||||
|
getter() {
|
||||||
|
return this._internal.result;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// Signal output
|
||||||
|
completed: {
|
||||||
|
type: 'signal',
|
||||||
|
displayName: 'Completed',
|
||||||
|
group: 'Events'
|
||||||
|
},
|
||||||
|
|
||||||
|
// Error output
|
||||||
|
error: {
|
||||||
|
type: 'string',
|
||||||
|
displayName: 'Error',
|
||||||
|
group: 'Error',
|
||||||
|
getter() {
|
||||||
|
return this._internal.error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// === METHODS ===
|
||||||
|
methods: {
|
||||||
|
performAction() {
|
||||||
|
if (!this._internal.enabled) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Do something
|
||||||
|
this._internal.result = 'Success';
|
||||||
|
this.flagOutputDirty('result');
|
||||||
|
this.sendSignalOnOutput('completed');
|
||||||
|
} catch (e) {
|
||||||
|
this._internal.error = e.message;
|
||||||
|
this.flagOutputDirty('error');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// Called when node is deleted
|
||||||
|
_onNodeDeleted() {
|
||||||
|
// Cleanup
|
||||||
|
this._internal.callbacks = [];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// === INSPECTOR (Debug Panel) ===
|
||||||
|
getInspectInfo() {
|
||||||
|
return {
|
||||||
|
type: 'text',
|
||||||
|
value: `Current: ${this._internal.result}`
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
node: MyNode
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### Visual Node (React)
|
||||||
|
|
||||||
|
Location: `packages/noodl-viewer-react/src/nodes/`
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const { Node } = require('@noodl/noodl-runtime');
|
||||||
|
|
||||||
|
const MyVisualNode = {
|
||||||
|
name: 'My.Visual.Node',
|
||||||
|
displayName: 'My Visual Node',
|
||||||
|
category: 'UI Elements',
|
||||||
|
|
||||||
|
// Visual nodes need these
|
||||||
|
allowChildren: true, // Can have child nodes
|
||||||
|
allowChildrenWithCategory: ['UI Elements'], // Restrict child types
|
||||||
|
|
||||||
|
getReactComponent() {
|
||||||
|
return MyReactComponent;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Frame updates for animations
|
||||||
|
frame: {
|
||||||
|
// Called every frame if registered
|
||||||
|
update(context) {
|
||||||
|
// Animation logic
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
inputs: {
|
||||||
|
// Standard style inputs
|
||||||
|
backgroundColor: {
|
||||||
|
type: 'color',
|
||||||
|
displayName: 'Background Color',
|
||||||
|
group: 'Style',
|
||||||
|
default: 'transparent',
|
||||||
|
set(value) {
|
||||||
|
this.props.style.backgroundColor = value;
|
||||||
|
this.forceUpdate();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// Dimension with units
|
||||||
|
width: {
|
||||||
|
type: {
|
||||||
|
name: 'number',
|
||||||
|
units: ['px', '%', 'vw'],
|
||||||
|
defaultUnit: 'px'
|
||||||
|
},
|
||||||
|
displayName: 'Width',
|
||||||
|
group: 'Dimensions',
|
||||||
|
set(value) {
|
||||||
|
this.props.style.width = value.value + value.unit;
|
||||||
|
this.forceUpdate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
outputs: {
|
||||||
|
// DOM event outputs
|
||||||
|
onClick: {
|
||||||
|
type: 'signal',
|
||||||
|
displayName: 'Click',
|
||||||
|
group: 'Events'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
// Called when mounted
|
||||||
|
didMount() {
|
||||||
|
// Setup
|
||||||
|
},
|
||||||
|
|
||||||
|
// Called when unmounted
|
||||||
|
willUnmount() {
|
||||||
|
// Cleanup
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// React component
|
||||||
|
function MyReactComponent(props) {
|
||||||
|
const handleClick = () => {
|
||||||
|
props.noodlNode.sendSignalOnOutput('onClick');
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div style={props.style} onClick={handleClick}>
|
||||||
|
{props.children}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
node: MyVisualNode
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
## Common Patterns
|
||||||
|
|
||||||
|
### Scheduled Updates
|
||||||
|
|
||||||
|
Batch multiple input changes before processing:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
inputs: {
|
||||||
|
value1: {
|
||||||
|
set(value) {
|
||||||
|
this._internal.value1 = value;
|
||||||
|
this.scheduleProcess();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
value2: {
|
||||||
|
set(value) {
|
||||||
|
this._internal.value2 = value;
|
||||||
|
this.scheduleProcess();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
scheduleProcess() {
|
||||||
|
if (this._internal.scheduled) return;
|
||||||
|
this._internal.scheduled = true;
|
||||||
|
|
||||||
|
this.scheduleAfterInputsHaveUpdated(() => {
|
||||||
|
this._internal.scheduled = false;
|
||||||
|
this.processValues();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
processValues() {
|
||||||
|
// Process both values together
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Async Operations
|
||||||
|
|
||||||
|
Handle promises and async work:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
inputs: {
|
||||||
|
fetch: {
|
||||||
|
type: 'signal',
|
||||||
|
valueChangedToTrue() {
|
||||||
|
this.doFetch();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
async doFetch() {
|
||||||
|
try {
|
||||||
|
const response = await fetch(this._internal.url);
|
||||||
|
const data = await response.json();
|
||||||
|
|
||||||
|
this._internal.result = data;
|
||||||
|
this.flagOutputDirty('result');
|
||||||
|
this.sendSignalOnOutput('success');
|
||||||
|
} catch (error) {
|
||||||
|
this._internal.error = error.message;
|
||||||
|
this.flagOutputDirty('error');
|
||||||
|
this.sendSignalOnOutput('failure');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Collection/Model Binding
|
||||||
|
|
||||||
|
Work with Noodl's data system:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const Collection = require('../../../collection');
|
||||||
|
const Model = require('../../../model');
|
||||||
|
|
||||||
|
inputs: {
|
||||||
|
items: {
|
||||||
|
type: 'array',
|
||||||
|
set(value) {
|
||||||
|
this.bindCollection(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
bindCollection(collection) {
|
||||||
|
// Unbind previous
|
||||||
|
if (this._internal.collection) {
|
||||||
|
this._internal.collection.off('change', this._internal.onChange);
|
||||||
|
}
|
||||||
|
|
||||||
|
this._internal.collection = collection;
|
||||||
|
|
||||||
|
if (collection) {
|
||||||
|
this._internal.onChange = () => {
|
||||||
|
this.flagOutputDirty('count');
|
||||||
|
};
|
||||||
|
collection.on('change', this._internal.onChange);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Dynamic Ports
|
||||||
|
|
||||||
|
Add ports based on configuration:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
inputs: {
|
||||||
|
properties: {
|
||||||
|
type: { name: 'stringlist', allowEditOnly: true },
|
||||||
|
displayName: 'Properties',
|
||||||
|
set(value) {
|
||||||
|
// Register dynamic inputs/outputs based on list
|
||||||
|
value.forEach(prop => {
|
||||||
|
if (!this.hasInput('prop-' + prop)) {
|
||||||
|
this.registerInput('prop-' + prop, {
|
||||||
|
set(val) {
|
||||||
|
this._internal.values[prop] = val;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Input Types Reference
|
||||||
|
|
||||||
|
| Type | Description | Example |
|
||||||
|
|------|-------------|---------|
|
||||||
|
| `string` | Text input | `type: 'string'` |
|
||||||
|
| `number` | Numeric input | `type: 'number'` |
|
||||||
|
| `boolean` | Toggle | `type: 'boolean'` |
|
||||||
|
| `color` | Color picker | `type: 'color'` |
|
||||||
|
| `signal` | Trigger/event | `type: 'signal'` |
|
||||||
|
| `array` | Array/collection | `type: 'array'` |
|
||||||
|
| `object` | Object/model | `type: 'object'` |
|
||||||
|
| `component` | Component reference | `type: 'component'` |
|
||||||
|
| `enum` | Dropdown selection | `type: { name: 'enum', enums: [...] }` |
|
||||||
|
| `stringlist` | Editable list | `type: { name: 'stringlist' }` |
|
||||||
|
| `number` with units | Dimension | `type: { name: 'number', units: [...] }` |
|
||||||
|
|
||||||
|
## Node Colors
|
||||||
|
|
||||||
|
Available color themes for nodes:
|
||||||
|
|
||||||
|
- `data` - Blue (data operations)
|
||||||
|
- `logic` - Purple (logic/control)
|
||||||
|
- `visual` - Green (UI elements)
|
||||||
|
- `component` - Orange (component utilities)
|
||||||
|
- `default` - Gray
|
||||||
|
|
||||||
|
## Registering Nodes
|
||||||
|
|
||||||
|
Add to the node library export:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// In packages/noodl-runtime/src/nodelibraryexport.js
|
||||||
|
const MyNode = require('./nodes/my-node');
|
||||||
|
|
||||||
|
// Add to appropriate category in coreNodes array
|
||||||
|
```
|
||||||
|
|
||||||
|
## Testing Nodes
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Example test structure
|
||||||
|
describe('MyNode', () => {
|
||||||
|
it('should process input correctly', () => {
|
||||||
|
const node = createNode('My.Custom.Node');
|
||||||
|
node.setInput('textInput', 'hello');
|
||||||
|
|
||||||
|
expect(node.getOutput('result')).toBe('HELLO');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
```
|
||||||
140
dev-docs/tasks/phase-1/TASK-001-dependency-updates/CHANGELOG.md
Normal file
140
dev-docs/tasks/phase-1/TASK-001-dependency-updates/CHANGELOG.md
Normal file
@@ -0,0 +1,140 @@
|
|||||||
|
# TASK-001 Changelog
|
||||||
|
|
||||||
|
Track all changes made during this task. Update this file as you work.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## [Date] - [Your Name/Handle]
|
||||||
|
|
||||||
|
### Summary
|
||||||
|
[To be filled in as work progresses]
|
||||||
|
|
||||||
|
### Starting Point
|
||||||
|
- Based on branch: `12-upgrade-dependencies`
|
||||||
|
- Previous work by: [previous developer]
|
||||||
|
- Previous commits include:
|
||||||
|
- Package.json dependency updates
|
||||||
|
- "Update rendering to use non-deprecated react-dom calls"
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Dependency Fixes
|
||||||
|
|
||||||
|
### Package: [package-name]
|
||||||
|
- **Issue**: [What was wrong]
|
||||||
|
- **Fix**: [What was changed]
|
||||||
|
- **File**: `path/to/package.json`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## React 19 Migration
|
||||||
|
|
||||||
|
### File: [filename]
|
||||||
|
- **Before**: `ReactDOM.render(<App />, element)`
|
||||||
|
- **After**: `createRoot(element).render(<App />)`
|
||||||
|
- **Notes**: [Any relevant context]
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## react-instantsearch Migration
|
||||||
|
|
||||||
|
### File: HelpCenter.tsx
|
||||||
|
- **Before**: `import { ... } from 'react-instantsearch-hooks-web'`
|
||||||
|
- **After**: `import { ... } from 'react-instantsearch'`
|
||||||
|
- **API Changes**: [List any API differences encountered]
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Build Fixes
|
||||||
|
|
||||||
|
### Error: [Error message]
|
||||||
|
- **Cause**: [Why it happened]
|
||||||
|
- **Fix**: [What was changed]
|
||||||
|
- **File**: `path/to/file`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Build Optimizations
|
||||||
|
|
||||||
|
### Optimization: [Name]
|
||||||
|
- **Before**: Build time X seconds
|
||||||
|
- **After**: Build time Y seconds
|
||||||
|
- **Change**: [What was optimized]
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Files Modified
|
||||||
|
<!-- Update this list as you make changes -->
|
||||||
|
|
||||||
|
- [ ] `package.json` (root)
|
||||||
|
- [ ] `packages/noodl-editor/package.json`
|
||||||
|
- [ ] `packages/noodl-core-ui/package.json`
|
||||||
|
- [ ] `packages/noodl-viewer-react/package.json`
|
||||||
|
- [ ] `packages/noodl-editor/src/editor/src/views/HelpCenter/HelpCenter.tsx`
|
||||||
|
- [ ] [Add more as needed]
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Files Created
|
||||||
|
<!-- List any new files created -->
|
||||||
|
|
||||||
|
- None expected for this task
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Files Deleted
|
||||||
|
<!-- List any files removed -->
|
||||||
|
|
||||||
|
- None expected for this task
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Breaking Changes
|
||||||
|
|
||||||
|
- React 19 requires Node.js 18+ (documented in root package.json engines)
|
||||||
|
- [Add any other breaking changes discovered]
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Testing Notes
|
||||||
|
|
||||||
|
### Automated Tests
|
||||||
|
- `npm run test:editor`: [PASS/FAIL] - [Notes]
|
||||||
|
- `npm run test:platform`: [PASS/FAIL] - [Notes]
|
||||||
|
- `npx tsc --noEmit`: [PASS/FAIL] - [Notes]
|
||||||
|
|
||||||
|
### Manual Tests
|
||||||
|
- Dev server start: [PASS/FAIL]
|
||||||
|
- Create project: [PASS/FAIL]
|
||||||
|
- Node operations: [PASS/FAIL]
|
||||||
|
- Preview: [PASS/FAIL]
|
||||||
|
- Help Center search: [PASS/FAIL]
|
||||||
|
- Hot reload: [PASS/FAIL]
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Known Issues
|
||||||
|
|
||||||
|
<!-- Document any issues discovered that aren't fixed in this task -->
|
||||||
|
|
||||||
|
1. [Issue description] - [Will be addressed in TASK-XXX]
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Follow-up Tasks
|
||||||
|
|
||||||
|
<!-- Note any work that should be done in future tasks -->
|
||||||
|
|
||||||
|
1. [Follow-up item] - Suggested for TASK-XXX
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Final Summary
|
||||||
|
|
||||||
|
[To be completed when task is done]
|
||||||
|
|
||||||
|
**Total files modified**: X
|
||||||
|
**Total lines changed**: +X / -Y
|
||||||
|
**Build time**: Before X sec → After Y sec
|
||||||
|
**Tests**: All passing / X failures
|
||||||
|
**Confidence**: X/10
|
||||||
123
dev-docs/tasks/phase-1/TASK-001-dependency-updates/CHECKLIST.md
Normal file
123
dev-docs/tasks/phase-1/TASK-001-dependency-updates/CHECKLIST.md
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
# TASK-001 Checklist
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
- [ ] Read README.md completely
|
||||||
|
- [ ] Understand React 19 breaking changes
|
||||||
|
- [ ] Have Node.js 18+ installed
|
||||||
|
- [ ] Clone the repository fresh (or ensure clean state)
|
||||||
|
|
||||||
|
## Phase 1: Setup
|
||||||
|
- [ ] Checkout existing work: `git checkout 12-upgrade-dependencies`
|
||||||
|
- [ ] Create task branch: `git checkout -b task/001-dependency-updates`
|
||||||
|
- [ ] Delete node_modules: `rm -rf node_modules packages/*/node_modules`
|
||||||
|
- [ ] Clean install: `npm install`
|
||||||
|
- [ ] Document any install errors in NOTES.md
|
||||||
|
- [ ] Note: confidence level for this phase: __/10
|
||||||
|
|
||||||
|
## Phase 2: Dependency Conflicts
|
||||||
|
- [ ] List all peer dependency warnings
|
||||||
|
- [ ] Research each warning
|
||||||
|
- [ ] Fix conflicts in root package.json
|
||||||
|
- [ ] Fix conflicts in packages/noodl-editor/package.json
|
||||||
|
- [ ] Fix conflicts in packages/noodl-core-ui/package.json
|
||||||
|
- [ ] Fix conflicts in packages/noodl-viewer-react/package.json
|
||||||
|
- [ ] Fix conflicts in other packages as needed
|
||||||
|
- [ ] Verify clean `npm install`
|
||||||
|
- [ ] Document fixes in CHANGELOG.md
|
||||||
|
- [ ] Note: confidence level for this phase: __/10
|
||||||
|
|
||||||
|
## Phase 3: Build Errors
|
||||||
|
- [ ] Run `npm run build:editor`
|
||||||
|
- [ ] List all build errors
|
||||||
|
- [ ] Fix error 1: _______________
|
||||||
|
- [ ] Fix error 2: _______________
|
||||||
|
- [ ] Fix error 3: _______________
|
||||||
|
- [ ] (add more as needed)
|
||||||
|
- [ ] Verify clean build
|
||||||
|
- [ ] Document fixes in CHANGELOG.md
|
||||||
|
- [ ] Note: confidence level for this phase: __/10
|
||||||
|
|
||||||
|
## Phase 4: React 19 Migration
|
||||||
|
- [ ] Search for ReactDOM.render usage:
|
||||||
|
```bash
|
||||||
|
grep -rn "ReactDOM.render" packages/ --include="*.ts" --include="*.tsx" --include="*.js"
|
||||||
|
```
|
||||||
|
- [ ] List all files found: _______________
|
||||||
|
- [ ] Update file 1: _______________
|
||||||
|
- [ ] Update file 2: _______________
|
||||||
|
- [ ] (add more as needed)
|
||||||
|
- [ ] Search for ReactDOM.hydrate usage
|
||||||
|
- [ ] Search for ReactDOM.unmountComponentAtNode usage
|
||||||
|
- [ ] Update any found
|
||||||
|
- [ ] Verify no legacy ReactDOM usage remains
|
||||||
|
- [ ] Document changes in CHANGELOG.md
|
||||||
|
- [ ] Note: confidence level for this phase: __/10
|
||||||
|
|
||||||
|
## Phase 5: react-instantsearch Migration
|
||||||
|
- [ ] Open `packages/noodl-editor/src/editor/src/views/HelpCenter/HelpCenter.tsx`
|
||||||
|
- [ ] Update import from `react-instantsearch-hooks-web` to `react-instantsearch`
|
||||||
|
- [ ] Check all hooks used are still available
|
||||||
|
- [ ] Search for other files using old package:
|
||||||
|
```bash
|
||||||
|
grep -rn "react-instantsearch-hooks-web" packages/
|
||||||
|
```
|
||||||
|
- [ ] Update any other files found
|
||||||
|
- [ ] Test search functionality works
|
||||||
|
- [ ] Document changes in CHANGELOG.md
|
||||||
|
- [ ] Note: confidence level for this phase: __/10
|
||||||
|
|
||||||
|
## Phase 6: Build Optimization (Optional but Recommended)
|
||||||
|
- [ ] Measure current build time: ___ seconds
|
||||||
|
- [ ] Check webpack config for cache settings
|
||||||
|
- [ ] Enable persistent caching if not enabled
|
||||||
|
- [ ] Check for unnecessary rebuilds
|
||||||
|
- [ ] Measure new build time: ___ seconds
|
||||||
|
- [ ] Document optimizations in CHANGELOG.md
|
||||||
|
|
||||||
|
## Phase 7: Testing - Automated
|
||||||
|
- [ ] Run `npm run test:editor`
|
||||||
|
- [ ] All tests pass
|
||||||
|
- [ ] Note any failures: _______________
|
||||||
|
- [ ] Run `npm run test:platform`
|
||||||
|
- [ ] All tests pass
|
||||||
|
- [ ] Note any failures: _______________
|
||||||
|
- [ ] Run `npx tsc --noEmit`
|
||||||
|
- [ ] No TypeScript errors
|
||||||
|
- [ ] Note any errors: _______________
|
||||||
|
|
||||||
|
## Phase 8: Testing - Manual
|
||||||
|
- [ ] Start dev server: `npm run dev`
|
||||||
|
- [ ] Starts without errors
|
||||||
|
- [ ] No console warnings about deprecated APIs
|
||||||
|
- [ ] Create new project
|
||||||
|
- [ ] Add Group node to canvas
|
||||||
|
- [ ] Add Text node as child
|
||||||
|
- [ ] Connect nodes
|
||||||
|
- [ ] Open preview
|
||||||
|
- [ ] Edit text content, verify preview updates
|
||||||
|
- [ ] Save and reopen project
|
||||||
|
- [ ] Open Help Center, test search (react-instantsearch)
|
||||||
|
- [ ] Edit Function node code
|
||||||
|
- [ ] Change a file, verify hot reload works
|
||||||
|
- [ ] Build production: `npm run build:editor`
|
||||||
|
|
||||||
|
## Phase 9: Cleanup & Documentation
|
||||||
|
- [ ] Remove any debug console.logs added
|
||||||
|
- [ ] Review all changes for code quality
|
||||||
|
- [ ] Complete CHANGELOG.md with summary
|
||||||
|
- [ ] Update NOTES.md with learnings
|
||||||
|
- [ ] Self-review: confidence level __/10
|
||||||
|
|
||||||
|
## Phase 10: Completion
|
||||||
|
- [ ] All success criteria met (see README.md)
|
||||||
|
- [ ] Create pull request
|
||||||
|
- [ ] PR title: "TASK-001: Dependency Updates & Build Modernization"
|
||||||
|
- [ ] PR description includes:
|
||||||
|
- [ ] Summary of changes
|
||||||
|
- [ ] Testing performed
|
||||||
|
- [ ] Any known issues or follow-ups
|
||||||
|
- [ ] Mark task complete
|
||||||
|
|
||||||
|
## Final Confidence Check
|
||||||
|
- Overall confidence this task is complete and correct: __/10
|
||||||
|
- Remaining concerns: _______________
|
||||||
128
dev-docs/tasks/phase-1/TASK-001-dependency-updates/NOTES.md
Normal file
128
dev-docs/tasks/phase-1/TASK-001-dependency-updates/NOTES.md
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
# TASK-001 Working Notes
|
||||||
|
|
||||||
|
## Research
|
||||||
|
|
||||||
|
### Previous Developer's Work
|
||||||
|
|
||||||
|
**Branch**: `12-upgrade-dependencies`
|
||||||
|
|
||||||
|
**Commits found**:
|
||||||
|
1. Package.json updates across all packages
|
||||||
|
2. "Update rendering to use non-deprecated react-dom calls"
|
||||||
|
|
||||||
|
**What they changed**:
|
||||||
|
- React 17.0.2 → 19.0.0
|
||||||
|
- react-instantsearch-hooks-web → react-instantsearch
|
||||||
|
- Removed deprecated react-json-view, added @microlink/react-json-view
|
||||||
|
- Updated webpack 5.74.0 → 5.101.3
|
||||||
|
- Removed Node.js upper version cap (was <=18, now 16+)
|
||||||
|
- Removed Storybook 6.x packages
|
||||||
|
|
||||||
|
### React 19 Breaking Changes to Watch For
|
||||||
|
|
||||||
|
1. **Automatic Batching** - State updates are now automatically batched
|
||||||
|
2. **Concurrent Features** - May affect node graph rendering timing
|
||||||
|
3. **Strict Mode** - Double-renders effects for cleanup detection
|
||||||
|
4. **Removed APIs**:
|
||||||
|
- `ReactDOM.render()` → `createRoot()`
|
||||||
|
- `ReactDOM.hydrate()` → `hydrateRoot()`
|
||||||
|
- `ReactDOM.unmountComponentAtNode()` → `root.unmount()`
|
||||||
|
|
||||||
|
### react-instantsearch Changes
|
||||||
|
|
||||||
|
The package was renamed from `react-instantsearch-hooks-web` to `react-instantsearch`.
|
||||||
|
|
||||||
|
Most APIs are compatible, but verify:
|
||||||
|
- `useHits`
|
||||||
|
- `useSearchBox`
|
||||||
|
- `InstantSearch` component props
|
||||||
|
|
||||||
|
### Files to Search
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Find ReactDOM.render usage
|
||||||
|
grep -rn "ReactDOM.render" packages/ --include="*.ts" --include="*.tsx" --include="*.js"
|
||||||
|
|
||||||
|
# Find old instantsearch imports
|
||||||
|
grep -rn "react-instantsearch-hooks-web" packages/
|
||||||
|
|
||||||
|
# Find any remaining TSFixme (for awareness, not this task)
|
||||||
|
grep -rn "TSFixme" packages/ --include="*.ts" --include="*.tsx"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Assumptions
|
||||||
|
|
||||||
|
- [ ] Previous dev's changes are on `12-upgrade-dependencies` branch - **VERIFY**
|
||||||
|
- [ ] Build was working before their changes - **VERIFY by checking main**
|
||||||
|
- [ ] No other branches need to be merged first - **VERIFY**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Implementation Notes
|
||||||
|
|
||||||
|
### Approach Decisions
|
||||||
|
|
||||||
|
[To be filled in during work]
|
||||||
|
|
||||||
|
### Gotchas / Surprises
|
||||||
|
|
||||||
|
[To be filled in during work]
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Debug Log
|
||||||
|
|
||||||
|
### [Date/Time]
|
||||||
|
- **Trying**: [what you're attempting]
|
||||||
|
- **Result**: [what happened]
|
||||||
|
- **Next**: [what to try next]
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Useful Commands
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Clean install
|
||||||
|
rm -rf node_modules packages/*/node_modules
|
||||||
|
npm install
|
||||||
|
|
||||||
|
# Build editor
|
||||||
|
npm run build:editor
|
||||||
|
|
||||||
|
# Run tests
|
||||||
|
npm run test:editor
|
||||||
|
|
||||||
|
# Type check
|
||||||
|
npx tsc --noEmit
|
||||||
|
|
||||||
|
# Start dev server
|
||||||
|
npm run dev
|
||||||
|
|
||||||
|
# Find files with pattern
|
||||||
|
grep -rn "pattern" packages/ --include="*.ts" --include="*.tsx"
|
||||||
|
|
||||||
|
# Check git status
|
||||||
|
git status
|
||||||
|
git diff --stat
|
||||||
|
|
||||||
|
# Compare with main
|
||||||
|
git diff main..HEAD --stat
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Questions to Resolve
|
||||||
|
|
||||||
|
- [ ] Are there any other branches that should be merged first?
|
||||||
|
- [ ] Did the previous dev test the build?
|
||||||
|
- [ ] Are there any known issues documented anywhere?
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Links & Resources
|
||||||
|
|
||||||
|
- [React 19 Blog Post](https://react.dev/blog/2024/04/25/react-19)
|
||||||
|
- [React 19 Upgrade Guide](https://react.dev/blog/2024/04/25/react-19-upgrade-guide)
|
||||||
|
- [react-instantsearch Migration](https://www.algolia.com/doc/guides/building-search-ui/upgrade-guides/react/)
|
||||||
218
dev-docs/tasks/phase-1/TASK-001-dependency-updates/README.md
Normal file
218
dev-docs/tasks/phase-1/TASK-001-dependency-updates/README.md
Normal file
@@ -0,0 +1,218 @@
|
|||||||
|
# TASK-001: Dependency Updates & Build Modernization
|
||||||
|
|
||||||
|
## Metadata
|
||||||
|
|
||||||
|
| Field | Value |
|
||||||
|
|-------|-------|
|
||||||
|
| **ID** | TASK-001 |
|
||||||
|
| **Phase** | Phase 1 - Foundation |
|
||||||
|
| **Priority** | 🔴 Critical |
|
||||||
|
| **Difficulty** | 🟡 Medium |
|
||||||
|
| **Estimated Time** | 2-3 days |
|
||||||
|
| **Prerequisites** | None (this is the first task) |
|
||||||
|
| **Branch** | `task/001-dependency-updates` |
|
||||||
|
| **Related Branches** | `12-upgrade-dependencies` (previous dev work) |
|
||||||
|
|
||||||
|
## Objective
|
||||||
|
|
||||||
|
Complete and validate all dependency updates, fully migrate to React 19, and modernize the build pipeline for reliable, fast development.
|
||||||
|
|
||||||
|
## Background
|
||||||
|
|
||||||
|
A previous developer started this work on the `12-upgrade-dependencies` branch. They updated package.json files across the monorepo, including:
|
||||||
|
- React 17 → 19
|
||||||
|
- Various webpack, typescript, and tooling updates
|
||||||
|
- Removed Node.js version upper cap
|
||||||
|
|
||||||
|
They also made a commit "Update rendering to use non-deprecated react-dom calls" which addressed some React 19 breaking changes.
|
||||||
|
|
||||||
|
This task completes that work, validates everything works, and improves the overall build experience.
|
||||||
|
|
||||||
|
## Current State
|
||||||
|
|
||||||
|
### What Exists
|
||||||
|
- Branch `12-upgrade-dependencies` with package.json updates
|
||||||
|
- Some React 19 migration work done
|
||||||
|
- Build may have errors or warnings
|
||||||
|
|
||||||
|
### Known Issues
|
||||||
|
- `react-instantsearch-hooks-web` renamed to `react-instantsearch` (breaking API change)
|
||||||
|
- `ReactDOM.render()` deprecated in React 18+
|
||||||
|
- Potential peer dependency conflicts
|
||||||
|
- Hot reload may be unreliable
|
||||||
|
- Build times are slow
|
||||||
|
|
||||||
|
### Key Package Changes (from previous dev)
|
||||||
|
|
||||||
|
| Package | Old | New | Breaking Changes |
|
||||||
|
|---------|-----|-----|------------------|
|
||||||
|
| react | 17.0.2 | 19.0.0 | Yes - see below |
|
||||||
|
| react-dom | 17.0.0 | 19.0.0 | Yes - render API |
|
||||||
|
| react-instantsearch-hooks-web | 6.38.0 | react-instantsearch 7.16.2 | Yes - renamed |
|
||||||
|
| webpack | 5.74.0 | 5.101.3 | Minor |
|
||||||
|
| typescript | 4.8.3 | 4.9.5 | Minor |
|
||||||
|
|
||||||
|
## Desired State
|
||||||
|
|
||||||
|
After this task:
|
||||||
|
- All packages build without errors
|
||||||
|
- No deprecation warnings in console
|
||||||
|
- React 19 fully adopted (no legacy patterns)
|
||||||
|
- Hot reload works reliably
|
||||||
|
- Build completes in <60 seconds
|
||||||
|
- All existing tests pass
|
||||||
|
|
||||||
|
## Scope
|
||||||
|
|
||||||
|
### In Scope
|
||||||
|
- [x] Validate and fix dependency updates
|
||||||
|
- [x] Complete React 19 migration
|
||||||
|
- [x] Fix all build errors and warnings
|
||||||
|
- [x] Update react-instantsearch usage
|
||||||
|
- [x] Improve build performance
|
||||||
|
- [x] Fix hot reload issues
|
||||||
|
|
||||||
|
### Out of Scope
|
||||||
|
- Major refactoring (that's later tasks)
|
||||||
|
- New features
|
||||||
|
- TSFixme cleanup (TASK-002)
|
||||||
|
- Storybook 9 migration (can be separate task)
|
||||||
|
|
||||||
|
## Technical Approach
|
||||||
|
|
||||||
|
### Key Files to Modify
|
||||||
|
|
||||||
|
| File | Changes |
|
||||||
|
|------|---------|
|
||||||
|
| `package.json` (root) | Verify dependencies, fix conflicts |
|
||||||
|
| `packages/*/package.json` | Verify peer deps, fix conflicts |
|
||||||
|
| `packages/noodl-editor/src/editor/src/views/HelpCenter/HelpCenter.tsx` | Update react-instantsearch imports |
|
||||||
|
| Any file with `ReactDOM.render` | Migrate to createRoot |
|
||||||
|
| `packages/noodl-viewer-react/` | React 19 compatibility |
|
||||||
|
|
||||||
|
### React 19 Migration Points
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// OLD (React 17)
|
||||||
|
import ReactDOM from 'react-dom';
|
||||||
|
ReactDOM.render(<App />, document.getElementById('root'));
|
||||||
|
|
||||||
|
// NEW (React 19)
|
||||||
|
import { createRoot } from 'react-dom/client';
|
||||||
|
const root = createRoot(document.getElementById('root'));
|
||||||
|
root.render(<App />);
|
||||||
|
```
|
||||||
|
|
||||||
|
Search for these patterns:
|
||||||
|
```bash
|
||||||
|
grep -r "ReactDOM.render" packages/ --include="*.ts" --include="*.tsx" --include="*.js"
|
||||||
|
grep -r "ReactDOM.hydrate" packages/ --include="*.ts" --include="*.tsx" --include="*.js"
|
||||||
|
grep -r "ReactDOM.unmountComponentAtNode" packages/ --include="*.ts" --include="*.tsx" --include="*.js"
|
||||||
|
```
|
||||||
|
|
||||||
|
### react-instantsearch Migration
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// OLD
|
||||||
|
import { InstantSearch, Hits } from 'react-instantsearch-hooks-web';
|
||||||
|
|
||||||
|
// NEW
|
||||||
|
import { InstantSearch, Hits } from 'react-instantsearch';
|
||||||
|
```
|
||||||
|
|
||||||
|
The API is mostly compatible, but verify all hooks used still exist.
|
||||||
|
|
||||||
|
## Implementation Steps
|
||||||
|
|
||||||
|
### Step 1: Setup and Initial Validation
|
||||||
|
1. Checkout the existing branch: `git checkout 12-upgrade-dependencies`
|
||||||
|
2. Create our task branch: `git checkout -b task/001-dependency-updates`
|
||||||
|
3. Clean install: `rm -rf node_modules && npm install`
|
||||||
|
4. Document any install errors in NOTES.md
|
||||||
|
|
||||||
|
### Step 2: Fix Dependency Conflicts
|
||||||
|
1. Run `npm install` and note all peer dependency warnings
|
||||||
|
2. For each warning, determine the correct resolution
|
||||||
|
3. Update package.json files as needed
|
||||||
|
4. Repeat until `npm install` runs cleanly
|
||||||
|
|
||||||
|
### Step 3: Fix Build Errors
|
||||||
|
1. Run `npm run build:editor`
|
||||||
|
2. Fix each error one at a time
|
||||||
|
3. Document each fix in CHANGELOG.md
|
||||||
|
4. Repeat until build succeeds
|
||||||
|
|
||||||
|
### Step 4: React 19 Migration
|
||||||
|
1. Search for deprecated ReactDOM calls
|
||||||
|
2. Update each to use createRoot pattern
|
||||||
|
3. Check for class component lifecycle issues
|
||||||
|
4. Test each changed component
|
||||||
|
|
||||||
|
### Step 5: react-instantsearch Update
|
||||||
|
1. Update imports in HelpCenter.tsx
|
||||||
|
2. Verify all hooks/components still available
|
||||||
|
3. Test search functionality
|
||||||
|
|
||||||
|
### Step 6: Build Optimization
|
||||||
|
1. Analyze current build time
|
||||||
|
2. Check webpack configs for optimization opportunities
|
||||||
|
3. Enable caching if not already
|
||||||
|
4. Measure improvement
|
||||||
|
|
||||||
|
### Step 7: Validation
|
||||||
|
1. Run full test suite
|
||||||
|
2. Manual testing of key workflows
|
||||||
|
3. Verify hot reload works
|
||||||
|
4. Check for console warnings
|
||||||
|
|
||||||
|
## Testing Plan
|
||||||
|
|
||||||
|
### Automated Tests
|
||||||
|
- [ ] Run `npm run test:editor` - all pass
|
||||||
|
- [ ] Run `npm run test:platform` - all pass
|
||||||
|
- [ ] Run `npx tsc --noEmit` - no type errors
|
||||||
|
|
||||||
|
### Manual Testing Scenarios
|
||||||
|
- [ ] Start dev server: `npm run dev` - starts without errors
|
||||||
|
- [ ] Create new project - works
|
||||||
|
- [ ] Add nodes to canvas - works
|
||||||
|
- [ ] Connect nodes - works
|
||||||
|
- [ ] Preview project - works
|
||||||
|
- [ ] Edit code in Function node - works
|
||||||
|
- [ ] Hot reload when editing - works
|
||||||
|
- [ ] Search in Help Center - works (react-instantsearch)
|
||||||
|
- [ ] Build for production - works
|
||||||
|
|
||||||
|
## Success Criteria
|
||||||
|
|
||||||
|
- [ ] `npm install` completes with no errors
|
||||||
|
- [ ] `npm run build:editor` completes with no errors
|
||||||
|
- [ ] `npm run test:editor` all tests pass
|
||||||
|
- [ ] `npx tsc --noEmit` no TypeScript errors
|
||||||
|
- [ ] No deprecation warnings in browser console
|
||||||
|
- [ ] Hot reload works reliably
|
||||||
|
- [ ] All manual test scenarios pass
|
||||||
|
|
||||||
|
## Risks & Mitigations
|
||||||
|
|
||||||
|
| Risk | Mitigation |
|
||||||
|
|------|------------|
|
||||||
|
| React 19 breaks something subtle | Extensive manual testing, rollback plan ready |
|
||||||
|
| react-instantsearch API changes | Read migration guide, test search thoroughly |
|
||||||
|
| Build time regression | Measure before/after, optimize if needed |
|
||||||
|
| Peer dependency hell | Use `--legacy-peer-deps` as last resort, document why |
|
||||||
|
|
||||||
|
## Rollback Plan
|
||||||
|
|
||||||
|
If major issues discovered:
|
||||||
|
1. Checkout main branch
|
||||||
|
2. Cherry-pick any non-breaking fixes
|
||||||
|
3. Document issues for future attempt
|
||||||
|
4. Consider incremental approach (React 18 first, then 19)
|
||||||
|
|
||||||
|
## References
|
||||||
|
|
||||||
|
- [React 19 Release Notes](https://react.dev/blog/2024/04/25/react-19)
|
||||||
|
- [react-instantsearch v7 Migration](https://www.algolia.com/doc/guides/building-search-ui/upgrade-guides/react/)
|
||||||
|
- Previous dev branch: `12-upgrade-dependencies`
|
||||||
|
- Previous dev commit: "Update rendering to use non-deprecated react-dom calls"
|
||||||
Reference in New Issue
Block a user