Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions .claude/skills/mendix/write-microflows.md
Original file line number Diff line number Diff line change
Expand Up @@ -420,6 +420,18 @@ commit $Product with events refresh;

**Best Practice**: Use `with events` when you want before/after commit event handlers to execute. Use `refresh` when the committed object is displayed in the client and you want the UI to update immediately.

## List Operations

```mdl
-- Existing variable form
add $Item to $Items;

-- Expression-valued add, useful when round-tripping Studio Pro list-add values
add head($SourceItems) to $Items;
```

Use expression-valued `add` only when the expression returns an object compatible with the target list element type.

## Database Operations

### RETRIEVE Statement
Expand Down
6 changes: 6 additions & 0 deletions cmd/mxcli/tui/watcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"os"
"path/filepath"
"sync"
"sync/atomic"
"time"

tea "github.com/charmbracelet/bubbletea"
Expand Down Expand Up @@ -78,6 +79,7 @@ func newWatcher(mprPath, contentsDir string, sender MsgSender) (*Watcher, error)

func (w *Watcher) run(sender MsgSender) {
var debounceTimer *time.Timer
var debounceSeq atomic.Uint64

for {
select {
Expand Down Expand Up @@ -110,7 +112,11 @@ func (w *Watcher) run(sender MsgSender) {
if debounceTimer != nil {
debounceTimer.Stop()
}
seq := debounceSeq.Add(1)
debounceTimer = time.AfterFunc(watchDebounce, func() {
if debounceSeq.Load() != seq {
return
}
sender.Send(MprChangedMsg{})
})

Expand Down
5 changes: 3 additions & 2 deletions cmd/mxcli/tui/watcher_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,11 @@ func TestWatcherDebounce(t *testing.T) {
}
defer w.Close()

// Rapidly write 5 times — should debounce into a single message
// Rapidly write 5 times — should debounce into a single message.
// Keep the burst tighter than the debounce window so slow CI machines do
// not accidentally let an intermediate timer fire.
for i := range 5 {
_ = os.WriteFile(unitFile, []byte{byte('a' + i)}, 0644)
time.Sleep(50 * time.Millisecond)
}

// Wait for debounce to fire (500ms + margin)
Expand Down
1 change: 1 addition & 0 deletions docs/01-project/MDL_QUICK_REFERENCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,7 @@ authentication basic, session
| Rollback | `rollback $entity [refresh];` | Reverts uncommitted changes |
| Retrieve (DB) | `retrieve $Var from Module.Entity [where condition];` | Database XPath retrieve |
| Retrieve (Assoc) | `retrieve $list from $Parent/Module.AssocName;` | Retrieve by association |
| Add to list | `add expression to $list;` | Also accepts existing `add $item to $list;` form |
| Call microflow | `$Result = call microflow Module.Name (Param = $value);` | |
| Call nanoflow | `$Result = call nanoflow Module.Name (Param = $value);` | |
| Call JS action | `$Result = call javascript action Module.Name (Param = $value);` | JavaScript action (nanoflow/microflow) |
Expand Down
33 changes: 33 additions & 0 deletions docs/11-proposals/PROPOSAL_microflow_add_expression_to_list.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Proposal: Microflow ADD Expression To List

Status: Draft

## Summary

Allow `add` microflow statements to use any expression as the value being added to a list:

```mdl
add if $UseFirst then $FirstItem else $SecondItem to $TargetList;
```

The existing variable-only form remains valid:

```mdl
add $Item to $TargetList;
```

## Motivation

Studio Pro stores the value of a list-add action as an expression string. Existing models can therefore contain a list-add value that is not a bare variable. MDL previously parsed only `add $Item to $List`, so describe/exec round-trips could not preserve expression-valued list additions.

## Semantics

The parser stores the add value as an expression. For compatibility, a bare variable expression also populates the legacy `Item` field in the AST. The builder writes the expression source to the Mendix `ChangeListAction.Value` field and falls back to the legacy item variable only when no expression is present.

## Tests And Examples

`mdl-examples/doctype-tests/add_expression_to_list.mdl` demonstrates adding an object-valued conditional expression to another list. Go regression tests cover parser behavior and builder output for both expression and simple-variable forms.

## Open Questions

- Should validation infer the list element type and reject expressions that cannot produce an object compatible with the target list?
1 change: 1 addition & 0 deletions docs/11-proposals/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ BSON schema Registry ◄──── multi-version Support
| [XPath Gaps](xpath-gaps-proposal.md) | Partial | XPath constraint support gap analysis. ~85% complete, association paths and nested predicates remain | — |
| [Microflow ENUM SPLIT Statement](PROPOSAL_microflow_enum_split_statement.md) | Implemented | Enumeration decision splits via `case $Var when Value then … end case;` | — |
| [Microflow CHANGE Refresh Modifier](PROPOSAL_microflow_change_refresh_modifier.md) | Draft | Preserve `RefreshInClient` on change-object actions | — |
| [Microflow ADD Expression To List](PROPOSAL_microflow_add_expression_to_list.md) | Draft | Preserve expression-valued list-add actions in microflow round-trips | — |
| [LLM MDL Assistance](PROPOSAL_llm_mdl_assistance.md) | Proposed | Enhanced error messages with examples, reorganized skills by use case | — |

### Testing & Evaluation
Expand Down
Loading
Loading