feat: Phase 5 BYOB foundation + Phase 3 GitHub integration

Phase 5 - BYOB Backend (TASK-007A/B):
- LocalSQL Adapter with full CloudStore API compatibility
- QueryBuilder translates Parse-style queries to SQL
- SchemaManager with PostgreSQL/Supabase export
- LocalBackendServer with REST endpoints
- BackendManager with IPC handlers for Electron
- In-memory fallback when better-sqlite3 unavailable

Phase 3 - GitHub Panel (GIT-004):
- Issues tab with list/detail views
- Pull Requests tab with list/detail views
- GitHub API client with OAuth support
- Repository info hook integration

Phase 3 - Editor UX Bugfixes (TASK-013):
- Legacy runtime detection banners
- Read-only enforcement for legacy projects
- Code editor modal close improvements
- Property panel stuck state fix
- Blockly node deletion and UI polish

Phase 11 - Cloud Functions Planning:
- Architecture documentation for workflow automation
- Execution history storage schema design
- Canvas overlay concept for debugging

Docs: Updated LEARNINGS.md and COMMON-ISSUES.md
This commit is contained in:
Richard Osborne
2026-01-15 17:37:15 +01:00
parent dd73b1339b
commit ddcb9cd02e
86 changed files with 17408 additions and 1873 deletions

View File

@@ -731,6 +731,60 @@ const NoodlRuntime = require('../../noodl-runtime'); // 2 levels from src/api/
---
### 🔴 GOTCHA #8: Port Properties Must Be Inside `type` Object (Jan 2026)
**THE BUG:**
```javascript
// Port-level properties are NOT passed to property panel
generatedCode: {
type: {
name: 'string',
codeeditor: 'javascript'
},
readOnly: true // ❌ Not accessible in property panel!
}
```
**WHY IT BREAKS:**
- Port object only contains: `['name', 'type', 'plug', 'group', 'displayName', 'index']`
- Custom properties like `readOnly` at port level are NOT included in this list
- Property panel accesses ports via `port.type.propertyName`, not `port.propertyName`
- Result: `port.readOnly` is `undefined`, property panel ignores the flag
**THE FIX:**
```javascript
// ✅ CORRECT - Put custom properties inside type object
generatedCode: {
type: {
name: 'string',
codeeditor: 'javascript',
readOnly: true // ✅ Accessible as port.type.readOnly
},
displayName: 'Generated code',
group: 'Advanced'
}
```
**DEBUGGING TIP:**
Add logging to see what properties are actually available:
```javascript
console.log('Port properties:', {
name: p.name,
readOnly: p.readOnly, // undefined ❌
typeReadOnly: p.type?.readOnly, // true ✅
allKeys: Object.keys(p) // Shows actual properties
});
```
**RULE:** Any custom property you want accessible in the property panel must be inside the `type` object.
---
## Complete Working Pattern (HTTP Node Reference)
Here's the proven pattern from the HTTP node that handles all gotchas:

View File

@@ -1205,6 +1205,136 @@ if (sourceType === 'any' || targetType === 'any') return true;
---
## ⚠️ Permanent Warning Patterns: Banner + Toast Dual-Layer (Jan 2026)
### The Dismissable Problem: Why One Warning Layer Isn't Enough
**Context**: TASK-001D Legacy Read-Only Enforcement - Users needed constant reminder they're in read-only mode, but banner alone was insufficient (dismissable) and toast alone was intrusive (blocks view).
**CRITICAL PRINCIPLE**: For critical mode warnings (read-only, offline, unsaved changes), use BOTH a dismissable banner AND a permanent toast to balance UX with safety.
**The Problem**: Single-layer warnings fail:
- **Banner only**: User dismisses it, forgets mode, loses work
- **Toast only**: Blocks UI permanently, user frustrated but can't clear it
- **Temporary warnings**: Disappear, user forgets critical mode
**The Solution** - Dual-layer warning system:
```typescript
// Layer 1: EditorBanner (Top) - Dismissable, high visibility
<EditorBanner
onDismiss={handleDismiss} // ✅ User CAN close to clear workspace
message="Legacy Project (React 17) - Read-Only Mode"
description="Return to the launcher to migrate it before editing"
style={{
background: '#1a1a1a', // Solid black for maximum visibility
borderBottom: '2px solid var(--theme-color-warning)'
}}
/>;
// Layer 2: Toast (Bottom Right) - Permanent, subtle reminder
ToastLayer.showError(
'READ-ONLY MODE - No changes will be saved',
Infinity // ✅ Stays forever
);
// NO close button - truly permanent
```
**Toast Permanence Pattern**:
```typescript
// ❌ WRONG - User can dismiss critical warning
showError(message, {
duration: 10000, // Disappears after 10s
onClose: () => toast.dismiss(id) // Has close button
});
// ✅ RIGHT - Permanent reminder
showError(message, {
duration: Infinity // Never auto-dismisses
// No onClose callback = no close button
});
```
**Banner Visibility Pattern**:
```scss
// ❌ WRONG - Semi-transparent, hard to see
.EditorBanner {
background: rgba(255, 193, 7, 0.15); // Transparent yellow
pointer-events: none; // Can't interact!
}
// ✅ RIGHT - Solid color, highly visible
.EditorBanner {
background: #1a1a1a; // Solid black
border-bottom: 2px solid var(--theme-color-warning);
pointer-events: auto; // Fully interactive
}
```
**Why This Works**:
**Banner Advantages:**
- Large, prominent at top of viewport
- Can include detailed instructions
- User can dismiss to clear workspace when needed
- Shows mode on initial project open
**Toast Advantages:**
- Small, non-intrusive in corner
- Always visible (can't dismiss)
- Constant reminder even after banner closed
- Doesn't block UI when user understands the mode
**User Flow**:
1. User opens project → Banner + Toast appear
2. User reads banner, understands mode
3. User closes banner to work (needs space)
4. **Toast remains**: Constant reminder in corner
5. User forgets after 30 minutes → **Toast still there!**
**Critical Rules**:
1. **NEVER** rely on banner alone for critical modes (user will dismiss)
2. **NEVER** make toast the only warning (too intrusive)
3. **ALWAYS** use `duration: Infinity` for permanent toasts
4. **NEVER** add close button to critical toasts (remove onClose callback)
5. **ALWAYS** use solid backgrounds on banners (visibility)
**Applies To**:
- Read-only mode warnings
- Offline mode indicators
- Unsaved changes warnings
- Beta feature warnings
- Migration required notices
- Any critical persistent state
**Common Mistakes**:
1. Using toast with 10-second duration (disappears, user forgets)
2. Banner only (user closes it, forgets critical mode)
3. Making toast undismissable with close button (confusing UX)
4. Transparent banner backgrounds (low visibility)
5. Blocking all interactions when warnings show
**Time Saved**: This pattern prevents data loss scenarios and support tickets. Clear, persistent warnings = fewer user mistakes.
**Location**:
- Implemented in: TASK-001D Legacy Read-Only Enforcement
- Files: `EditorBanner.tsx`, `ToastLayer.tsx`, `ProjectsPage.tsx`
- Documentation: `TASK-001D/CHANGELOG.md`
**Keywords**: permanent toast, dismissable banner, dual-layer warnings, read-only mode, critical warnings, user safety, Infinity duration, banner visibility, UX balance
---
## 🔥 CRITICAL: Electron Blocks window.prompt() and window.confirm() (Dec 2025)
### The Silent Dialog: Native Dialogs Don't Work in Electron