mirror of
https://github.com/The-Low-Code-Foundation/OpenNoodl.git
synced 2026-03-08 10:03:31 +01:00
220 lines
7.3 KiB
Markdown
220 lines
7.3 KiB
Markdown
# Phase 2B: Inline Property Expressions - COMPLETE ✅
|
|
|
|
**Started:** 2026-01-10
|
|
**Completed:** 2026-01-16
|
|
**Status:** ✅ COMPLETE
|
|
|
|
---
|
|
|
|
## Summary
|
|
|
|
Inline property expressions are now fully functional! Users can set property values using JavaScript expressions that reference Noodl.Variables, Noodl.Objects, and Noodl.Arrays. Expressions update reactively when their dependencies change.
|
|
|
|
---
|
|
|
|
## ✅ What Was Implemented
|
|
|
|
### 1. ExpressionInput Component - COMPLETE ✅
|
|
|
|
**Files Created:**
|
|
|
|
- `packages/noodl-core-ui/src/components/property-panel/ExpressionInput/ExpressionInput.tsx`
|
|
- `packages/noodl-core-ui/src/components/property-panel/ExpressionInput/ExpressionInput.module.scss`
|
|
|
|
**Features:**
|
|
|
|
- Monospace input field with "fx" badge
|
|
- Expression mode toggle
|
|
- Expand button to open full editor modal
|
|
- Error state display
|
|
|
|
---
|
|
|
|
### 2. ExpressionEditorModal - COMPLETE ✅
|
|
|
|
**Files Created:**
|
|
|
|
- `packages/noodl-editor/src/editor/src/views/panels/propertyeditor/ExpressionEditorModal/ExpressionEditorModal.tsx`
|
|
- `packages/noodl-editor/src/editor/src/views/panels/propertyeditor/ExpressionEditorModal/ExpressionEditorModal.module.scss`
|
|
- `packages/noodl-editor/src/editor/src/views/panels/propertyeditor/ExpressionEditorModal/index.ts`
|
|
|
|
**Features:**
|
|
|
|
- Full-screen modal for editing complex expressions
|
|
- Uses JavaScriptEditor (CodeMirror) for syntax highlighting
|
|
- Help documentation showing available globals (Noodl.Variables, etc.)
|
|
- Apply/Cancel buttons
|
|
|
|
---
|
|
|
|
### 3. PropertyPanelInput Integration - COMPLETE ✅
|
|
|
|
**Files Modified:**
|
|
|
|
- `packages/noodl-core-ui/src/components/property-panel/PropertyPanelInput/PropertyPanelInput.tsx`
|
|
|
|
**Features:**
|
|
|
|
- Added expression-related props (supportsExpression, expressionMode, expression, etc.)
|
|
- Conditional rendering: expression input vs fixed input
|
|
- Mode change handlers
|
|
|
|
---
|
|
|
|
### 4. PropertyPanelInputWithExpressionModal Wrapper - COMPLETE ✅
|
|
|
|
**Files Created:**
|
|
|
|
- `packages/noodl-editor/src/editor/src/views/panels/propertyeditor/components/PropertyPanelInputWithExpressionModal.tsx`
|
|
|
|
**Features:**
|
|
|
|
- Combines PropertyPanelInput with ExpressionEditorModal
|
|
- Manages modal open/close state
|
|
- Handles expression expand functionality
|
|
|
|
---
|
|
|
|
### 5. BasicType Property Editor Wiring - COMPLETE ✅
|
|
|
|
**Files Modified:**
|
|
|
|
- `packages/noodl-editor/src/editor/src/views/panels/propertyeditor/DataTypes/BasicType.ts`
|
|
|
|
**Features:**
|
|
|
|
- Uses React for rendering via createRoot
|
|
- Supports expression mode toggle
|
|
- Integrates with ExpressionParameter model
|
|
- Uses ParameterValueResolver for safe value display
|
|
|
|
---
|
|
|
|
### 6. Runtime Reactive Subscriptions - COMPLETE ✅
|
|
|
|
**Files Modified:**
|
|
|
|
- `packages/noodl-runtime/src/node.js`
|
|
|
|
**Features:**
|
|
|
|
- `_evaluateExpressionParameter()` now sets up reactive subscriptions
|
|
- Uses `detectDependencies()` to find referenced Variables/Objects/Arrays
|
|
- Uses `subscribeToChanges()` to listen for dependency updates
|
|
- Re-queues input when dependencies change
|
|
- Cleanup in `_onNodeDeleted()`
|
|
|
|
---
|
|
|
|
## 🎯 How It Works
|
|
|
|
### User Experience
|
|
|
|
1. Select a node with text/number properties
|
|
2. Click the "fx" button to toggle expression mode
|
|
3. Enter an expression like `Noodl.Variables.userName`
|
|
4. The value updates automatically when the variable changes
|
|
5. Click the expand button for a full code editor modal
|
|
|
|
### Supported Expressions
|
|
|
|
```javascript
|
|
// Simple variable access
|
|
Noodl.Variables.userName;
|
|
|
|
// Math operations
|
|
Noodl.Variables.count * 2 + 1;
|
|
|
|
// Ternary conditionals
|
|
Noodl.Variables.isLoggedIn ? 'Logout' : 'Login';
|
|
|
|
// String concatenation
|
|
'Hello, ' + Noodl.Variables.userName + '!';
|
|
|
|
// Math helpers
|
|
min(Noodl.Variables.price, 100);
|
|
max(10, Noodl.Variables.quantity);
|
|
round(Noodl.Variables.total);
|
|
|
|
// Object/Array access
|
|
Noodl.Objects['user'].name;
|
|
Noodl.Arrays['items'].length;
|
|
```
|
|
|
|
---
|
|
|
|
## 📁 Files Changed
|
|
|
|
### Created
|
|
|
|
- `packages/noodl-core-ui/src/components/property-panel/ExpressionInput/ExpressionInput.tsx`
|
|
- `packages/noodl-core-ui/src/components/property-panel/ExpressionInput/ExpressionInput.module.scss`
|
|
- `packages/noodl-editor/src/editor/src/views/panels/propertyeditor/ExpressionEditorModal/ExpressionEditorModal.tsx`
|
|
- `packages/noodl-editor/src/editor/src/views/panels/propertyeditor/ExpressionEditorModal/ExpressionEditorModal.module.scss`
|
|
- `packages/noodl-editor/src/editor/src/views/panels/propertyeditor/ExpressionEditorModal/index.ts`
|
|
- `packages/noodl-editor/src/editor/src/views/panels/propertyeditor/components/PropertyPanelInputWithExpressionModal.tsx`
|
|
|
|
### Modified
|
|
|
|
- `packages/noodl-core-ui/src/components/property-panel/PropertyPanelInput/PropertyPanelInput.tsx`
|
|
- `packages/noodl-editor/src/editor/src/views/panels/propertyeditor/DataTypes/BasicType.ts`
|
|
- `packages/noodl-runtime/src/node.js` (added reactive subscriptions)
|
|
|
|
---
|
|
|
|
## 🐛 Bug Fixes (2026-01-16)
|
|
|
|
### Modal Showing Stale Expression
|
|
|
|
**Problem:** When editing an expression in the inline input field and then opening the modal, the modal showed the old expression text instead of the current one.
|
|
|
|
**Root Cause:** `BasicType.ts` was not re-rendering after `onExpressionChange`, so the modal component never received the updated expression prop.
|
|
|
|
**Fix:** Added `setTimeout(() => this.renderReact(), 0)` at the end of `onExpressionChange` in `BasicType.ts` to ensure the React tree updates with the new expression value.
|
|
|
|
### Variable Changes Not Updating Node Values
|
|
|
|
**Problem:** When using an expression like `Noodl.Variables.label_text`, changing the variable value didn't update the node's property until the expression was manually saved again.
|
|
|
|
**Root Cause:** The subscription callback in `node.js` captured the old `paramValue` object in a closure. When the subscription fired, it re-queued the old expression, not the current one stored in `_inputValues`.
|
|
|
|
**Fix:** Updated subscription management in `_evaluateExpressionParameter()`:
|
|
|
|
- Subscriptions now track both the unsubscribe function AND the expression string
|
|
- When expression changes, old subscription is unsubscribed before creating a new one
|
|
- The callback now reads from `this._inputValues[portName]` (current value) instead of using a closure
|
|
|
|
**Files Modified:**
|
|
|
|
- `packages/noodl-editor/src/editor/src/views/panels/propertyeditor/DataTypes/BasicType.ts`
|
|
- `packages/noodl-runtime/src/node.js`
|
|
|
|
---
|
|
|
|
## 🎓 Key Learnings
|
|
|
|
### Context Issue
|
|
|
|
The `evaluateExpression()` function in expression-evaluator.js expects either `undefined` or a Model scope as the second parameter. Passing `this.context` (the runtime context with editorConnection, styles, etc.) caused "scope.get is not a function" errors. **Solution:** Pass `undefined` to use the global Model.
|
|
|
|
### Reactive Updates
|
|
|
|
The expression-evaluator module already had `detectDependencies()` and `subscribeToChanges()` functions. We just needed to wire them into `_evaluateExpressionParameter()` in node.js to enable reactive updates.
|
|
|
|
### Value Display
|
|
|
|
Expression parameters are objects (`{ mode: 'expression', expression: '...', fallback: ... }`). When displaying the value in the properties panel, we need to extract the fallback value, not display the object. The `ParameterValueResolver.toString()` helper handles this.
|
|
|
|
---
|
|
|
|
## 🚀 Future Enhancements
|
|
|
|
1. **Canvas rendering** - Show expression indicator on node ports (TASK-006B)
|
|
2. **More property types** - Extend to color, enum, and other types
|
|
3. **Expression autocomplete** - IntelliSense for Noodl.Variables names
|
|
4. **Expression validation** - Real-time syntax checking
|
|
|
|
---
|
|
|
|
**Last Updated:** 2026-01-16
|