Skip to content

Blockly ts - #2354

Open
GermanBluefox wants to merge 29 commits into
masterfrom
blockly-ts
Open

Blockly ts#2354
GermanBluefox wants to merge 29 commits into
masterfrom
blockly-ts

Conversation

@GermanBluefox

Copy link
Copy Markdown
Contributor

No description provided.

GermanBluefox and others added 29 commits August 14, 2026 20:52
# Conflicts:
#	README.md
#	admin/assets/mf-entry-bootstrap-0-425e1f28.js
#	admin/assets/mf-entry-bootstrap-0-44cbc963.js
#	admin/assets/mf-entry-bootstrap-0-c61f5911.js
#	admin/mf-stats.json
#	admin/tab.html
- TriggerMessage: starts a rule from onMessage(), so a rule can be called
  from outside via messageTo(). Adds STANDARD_FUNCTION_MESSAGE(_ONCHANGE)
  and a getReplacesInText branch, so %s in the actions is the payload.
- ConditionFunction: a condition written in JavaScript, the counterpart to
  the "User function" action. The code is a function body and must return.
- ActionNotification: registerNotification(), optionally as an alert.
- ActionToggleState: switches a state between two arbitrary values. The
  current value is compared as text and written typed, so a number state
  recognises its own first value.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
TriggerFile subscribes with onFile() and starts the rule when a file of an
object is written or deleted - a new camera image, an edited vis project.

Both the object and the file name may contain *, the way the sandbox reads
them. The file content is deliberately not requested: a rule cannot use it,
and asking would read every changed file from disk for nothing. In the texts
of the actions %s is the file name and %id the object it belongs to.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- TriggerObject (onObject): reacts to the object itself instead of its
  value, so a rule can notice a datapoint appearing or disappearing. A
  deletion arrives without `obj`, which the "React on" filter uses.
- TriggerLog (onLog): reacts to entries in the ioBroker log. The sandbox
  drops this script's own output while the handler runs synchronously, so
  the plain case cannot loop; the text filter covers the rest.
- TriggerOnStop (onStop): runs the rule once more while it is stopped, for
  cleanup. Unlike the other hooks the adapter waits for this one, so the
  template is a plain function that reports back through `_done` instead of
  an async one - otherwise every stop would sit out its full timeout. The
  timeout is configurable, since the actions have to fit into it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The rule editor emits a JavaScript script that nothing ever parses - a block
with a stray quote or a broken comment takes the rule down at runtime, with
an error pointing at code the user never wrote. The blockly generator next
door has golden files for exactly that; the rules had nothing.

33 cases compile real rules with the real blocks and check the result twice:
that it parses (wrapped in the async IIFE `createVM` puts around every
script), and that the pieces carrying the meaning are in it - the %s
substitutions, the object/log/file filters, the typed literals of the toggle,
and that `onStop` reaches its done callback on the error path too.

Verified by mutation: dropping the escaping in ActionToggleState.literal
fails exactly the two tests that cover it, both on the parse check.

vitest.config.ts had to repeat the "@" alias - it does not read
vite.config.ts, and StandardBlocks imports through the alias.

Note that no workflow runs `vitest` yet, so this suite - and the 13 AiChat
ones next to it - only run when started by hand in src-editor.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The editor is its own package, and the root "npm test" is declarations plus
mocha - so nothing ever started its 486 vitest tests. They only ran when
somebody remembered to run them by hand in src-editor.

A job of its own rather than a step in "build": a failing test should not be
reported as a broken build, and it runs in parallel instead of in front of
the adapter tests. "auto-merge" now waits for it too, otherwise a red editor
test would still merge.

Only the editor's own dependencies are installed - a scan over all 167 source
files confirms every package they import is declared in src-editor's
package.json, so nothing falls back to the root node_modules.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
ActionHTTPCall emitted `request(url)`. That was a global back when the adapter
bundled the package of that name; it is gone, and the VM context is exactly
the sandbox object (`runInNewContext(sandbox, ...)` in main.ts), so every rule
using this block ended in "ReferenceError: request is not defined" - and took
the rest of the rule down with it.

It now calls `httpGet`, which the sandbox does provide. Called back rather
than awaited, so the rule carries on while the request runs, the way the block
behaved while it still worked. The callback reports the status code, or the
error, back to the editor's debug view; the sandbox logs a failed request by
itself, so the block does not log it twice.

The URL is now written with JSON.stringify instead of quoting by hand, which
also covers a backslash, and the comment line no longer takes a line break
from the URL.

Four tests cover it, one of them asserting that `request(` is gone.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- TriggerEnumMembers (onEnumMembers): starts the rule when any state of a
  room or function changes. The state trigger needs one block per datapoint,
  which does not survive "any window on the ground floor"; this follows the
  enum, so a device added to the room later is included without touching the
  rule. Its callback is an ordinary state subscription, so it reuses the
  state templates and joins that branch of getReplacesInText - %s and %id
  mean there what they mean everywhere else.

- ActionMessageTo (messageTo): the other half of the "On message" trigger.
  Rules could be called by a script but could never call one, so a rule could
  not be used as a building block by another rule.

- ActionSetStateChanged (setStateChangedAsync): writes only when the value
  differs. Every write is an event, and a rule on a schedule writing the same
  value every minute keeps history, logging and every subscriber busy for
  nothing.

The last one derives from ActionSetState rather than copying its 350 lines of
object picker and type aware value field - the difference is one call in
compile(). For that, ActionSetState now passes `new.target` to the base
constructor instead of hardcoding itself, so a derived block describes itself
with its own name and icon. A test covers exactly that.

14 tests, all against the real blocks; suite is at 50 for the rule editor.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The surface under the rule was a photograph with a flat colour laid over it,
and every theme had to pick its own opacity for that overlay. In the blue
themes the overlay was #ffffff00 - fully transparent - so the photo simply was
the background: a saturated navy-to-cyan diagonal behind translucent cards.

Each theme now names its own background instead, as one token holding the
whole value, so a theme can be flat or a gradient without the stylesheet
caring. The gradients travel little and sit at 160deg, deliberately not
aligned with the horizontal bands, so they do not read as a fourth band and
the 6% rail washes stay visible - they were drowned by the photo before.

Contrast of the card text, composited through the translucent card onto both
gradient stops: blue 6.9-7.5:1, dark 5.8-6.0:1, modernDark 14.9:1,
modernLight 17.6:1. The blue theme measured 7.7-10.2:1 over the photo, so it
gives up some headroom at the bright end and gets one predictable value
instead of a range that depended on where a card happened to sit.

The image was referenced from this one rule only, so src/Components/assets is
rid of it. public/back.jpg and its build copy are untouched.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
# Conflicts:
#	admin/assets/AiChatPanel-BcMfnHrz.js
#	admin/assets/AiChatPanel-C4kuqP2U.js
#	admin/assets/AiChatPanel-M1b4cNWQ.js
#	admin/assets/RulesEditor-ByjgEaVo.js
#	admin/assets/index-BvPVHv3P.js
#	admin/assets/mf-entry-bootstrap-0-425e1f28.js
#	admin/assets/mf-entry-bootstrap-0-a03ecebd.js
#	admin/assets/mf-entry-bootstrap-0-e7c9e343.js
#	admin/mf-stats.json
#	admin/tab.html
#	src-editor/src/Components/RulesEditor/components/StandardBlocks/index.tsx
#	src-editor/src/Components/RulesEditor/helpers/MaterialDynamicIcon.tsx
#	src-editor/src/i18n/de.json
#	src-editor/src/i18n/en.json
#	src-editor/src/i18n/es.json
#	src-editor/src/i18n/fr.json
#	src-editor/src/i18n/it.json
#	src-editor/src/i18n/nl.json
#	src-editor/src/i18n/pl.json
#	src-editor/src/i18n/pt.json
#	src-editor/src/i18n/ru.json
#	src-editor/src/i18n/uk.json
#	src-editor/src/i18n/zh-cn.json
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant