mirror of
https://github.com/The-Low-Code-Foundation/OpenNoodl.git
synced 2026-01-11 06:42:57 +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