Commit Graph

120 Commits

Author SHA1 Message Date
Claude
16a5225ee3 feat(executor): node pinned_input overrides upstream byPort on manual runs 2026-08-30 14:22:01 +00:00
Claude
e24bdb012b feat(executor): trigger pinned_output overrides triggerItems on manual runs 2026-08-30 14:17:29 +00:00
Claude
8a68b13a70 feat(executor): parse pinned_input/pinned_output on WorkflowNode + WrapPin helper 2026-08-30 14:11:03 +00:00
Claude
55cf372442 docs(plan): plan 6 — pinned node data implementation plan 2026-08-30 14:06:28 +00:00
Claude
8b48dd8bf8 docs(spec): pinned node data (n8n-style pin for manual test runs) 2026-08-30 14:00:27 +00:00
Claude
3e838ecf91 docs: plan 5 wrap-up — status, invariants, and re-numbered followups 2026-08-30 11:52:30 +00:00
Claude
80ac663989 test(e2e): smoke covers double-click dialog and label persistence 2026-08-30 11:49:42 +00:00
Claude
045cdb7b7e feat(editor): double-click opens node editor dialog; remove side panel 2026-08-30 11:46:42 +00:00
Claude
abc71e481e fix(editor): NodeEditorDialog — correct bracket-form path wrapping + focus trap on open 2026-08-30 11:43:51 +00:00
Claude
2649e09da9 feat(editor): NodeEditorDialog — three-column N8N-style modal
Left column shows the port-0 inputs as a clickable JsonTree that inserts
{input.<path>} at the last-focused parameter caret; middle column carries
the node label, optional connection dropdown, SchemaForm, WebhookUrlHint
(for http.webhook), Run/Delete/Done buttons; right column shows the
port-0 outputs read-only. ESC and backdrop-click both call onClose;
changes flow through onPatch so the parent still owns the toolbar Save.

Adds a `server` alias export to src/testing/msw so the dialog test file
can import the shared MSW server under the shorter name used by newer
tests without breaking the existing `mswServer` import sites.
2026-08-30 11:36:37 +00:00
Claude
1153e56cc5 feat(editor): findLatestIo helper for pulling a node's row out of an ExecutionDetail 2026-08-30 11:30:05 +00:00
Claude
abf6332855 fix(forms): keep native password input for format:password; drop dead forwardRef 2026-08-30 11:28:39 +00:00
Claude
df5a34ba33 feat(forms): SchemaForm renders every leaf as ExpressionField 2026-08-30 11:23:21 +00:00
Claude
6b0a25b0b0 fix(expr): ExpressionField — direct-DOM scroll sync + align overlay border-box with textarea 2026-08-30 11:21:03 +00:00
Claude
c502bdef03 feat(expr): ExpressionField with token highlight overlay and live preview 2026-08-30 11:16:57 +00:00
Claude
38aa05bc96 refactor(expr): JsonTree — un-pickable trees still expand + drop dead clickable var 2026-08-30 11:13:39 +00:00
Claude
6fd517c630 fix(expr): restore visual quotes around string leaves in JsonTree 2026-08-30 11:10:33 +00:00
Claude
0afeed8ee7 feat(expr): JsonTree with click-to-emit-path leaves 2026-08-30 11:08:52 +00:00
Claude
a131dbf198 fix(editor): restore build after toGraph signature change + client/backend numeric parity 2026-08-30 11:06:09 +00:00
Claude
b1dae49171 feat(editor): coerce literal number/boolean strings to typed JSON on save 2026-08-30 11:01:26 +00:00
Claude
85e2339c1d refactor(executor): use action.ConfigSchema directly + dispose transient JsonDocuments 2026-08-30 10:59:01 +00:00
Claude
70f556aff5 feat(executor): coerce templated string leaves to schema-declared primitive types 2026-08-30 10:54:26 +00:00
Claude
72e31e8ea5 fix(expr): own-property-only lookup and Int32-bound array index in TemplateEngine port 2026-08-30 10:49:14 +00:00
Claude
3fde792c53 feat(expr): client-side TemplateEngine port with parity tests 2026-08-30 10:44:28 +00:00
Claude
1e5fd42619 docs(plan): plan 5 — node editor dialog implementation plan 2026-08-30 10:41:28 +00:00
Claude
744e19e813 docs(spec): node editor dialog (N8N-style, 3-column, expressions) 2026-08-30 10:27:55 +00:00
Claude
c187300aa4 feat(editor): visible selection border on the selected node
Selected nodes get an indigo border + soft ring so the current
selection is obvious in the canvas.
2026-08-30 09:54:50 +00:00
Claude
46372e8e38 feat(executor): {input.foo} template interpolation on node config strings
Every action/terminal node's config string fields are now run through
TemplateEngine.Render before the node sees them, so operators can pull
values from the incoming item into any config field.

- {input}, {input.a.b}, {input.tags[0]}, {input["weird.key"]}
- {{ / }} escape to literal braces
- Missing paths / null input → empty string (no 500s on absent query params)
- Unrecognised / malformed placeholders pass through so typos are visible
- Strings render raw; numbers/bools stringified; objects/arrays compact JSON

Interpolation runs executor-side (Executor.RunNodeAsync walks ConfigJson
and rewrites string leaves), so every node opts in for free. 20 new tests
(17 TemplateEngine + 2 Executor + 1 end-to-end webhook→WebResponse).
2026-08-29 18:44:03 +00:00
Claude
bc682d8c9f feat(webhook): GET support — query string → JSON body, HEAD safe no-op
POST behaviour unchanged (JSON body). GET on the same URL now triggers the
workflow with the query string collapsed into a JSON object: /wh/wf/hi?a=1&name=x
becomes {"a":"1","name":"x"}, and repeated keys collapse into a string
array (?tag=a&tag=b → {"tag":["a","b"]}). No query string yields {} —
matches the empty-POST-body semantics.

HEAD returns 200 empty so Slack/Discord link previews don't fire the workflow
AND don't flag the URL as broken. Other verbs (PUT/PATCH/DELETE/OPTIONS) still
return 405 JSON with Allow: POST, GET.

Frontend WebhookUrlHint now advertises both verbs and drops the POST prefix
from the displayed URL so the raw URL is copy-and-clickable.

6 new xUnit tests cover: GET-unknown-404, GET-with-query, GET-repeated-keys,
GET-empty-query, HEAD-200, PUT-still-405 (updated Allow header).
2026-08-29 07:51:27 +00:00
Claude
a06e9e0e84 feat(connections): Test button — opens the provider round-trip and reports back
Backend: POST /api/connections/{id}/test decrypts the stored config, calls
provider.OpenAsync with a 10s CancellationTokenSource, closes the returned
handle in a finally, and returns {ok: bool, error?: string}. Always 200
unless the id is unknown (404) — the outcome of the round-trip belongs in
the body, not the status. 2 new xUnit tests cover the 404 path and the
"connection refused" failure path (points at 127.0.0.1:1).

Frontend: Plug icon on each ConnectionsPage row. Click → animated icon
during the round-trip, then an inline pill: 'Connected' (green check) on
success or the truncated error (red X, full text on hover) on failure.
Auto-clears after 6s. Row state is tracked per-id in a plain useState;
the shared react-query cache stays untouched. 1 new Vitest covers both
outcomes via MSW handlers.
2026-08-29 07:41:19 +00:00
Claude
1a1f519144 fix(webhook): GET on /wh/* returns 405 helper page instead of SPA fallback
Previously a browser click on the webhook URL fell through the POST-only
handler to MapFallbackToFile('index.html'), landing the user on the
workflows page and looking like a bug. Now non-POST verbs on the same
route return 405 with Allow: POST — GETs render a small HTML page showing
the correct curl invocation, other methods get JSON. Two new xUnit tests
cover the HTML and JSON branches and assert we don't hand back the SPA.
2026-08-28 20:16:07 +00:00
Claude
5d04c0a2d4 feat(editor): visible feedback for Test run — status pill + View link
Before, the Test run button fired and returned an execution id but there was
no on-screen confirmation, so users assumed nothing happened. Adds an inline
status bar under the toolbar that shows 'Running…', then either 'Started
execution <id> · View execution →' (auto-clears in 6s) or 'Test run failed:
<msg>' (auto-clears in 8s).
2026-08-28 19:53:34 +00:00
Claude
c705f58531 feat(editor): show composed webhook URL + Copy button on Webhook nodes
When the selected node is http.webhook, the config panel now shows the full
POST URL (${origin}/wh/${workflowId}/${path}) with a one-click Copy button
and an active-workflow reminder. Removes the guesswork of assembling the
URL by hand from the design spec.
2026-08-28 19:52:38 +00:00
Claude
8c2d630af5 fix(editor): Delete/Backspace key removes selected node + orphan edges
React Flow's built-in keyboard handling was silently no-op'd because
deleteKeyCode wasn't set (v12 defaults it to null when the prop is absent
in the strict TS types we consume). Set it to ['Delete', 'Backspace'] and
add an onNodesDelete handler that filters edges whose endpoints just
vanished — applyNodeChanges only touches nodes, so without this the graph
kept dangling edges.

Also fixes a tsc regression the same touch caught in ConnectionsPage.test
where a request.json() cast leaked 'never' back into a later access.
2026-08-28 19:51:37 +00:00
Claude
cd5827cca7 chore: untrack plan-4-kickoff-prompt.md (user's local prompt notes, not repo content) 2026-08-28 19:50:25 +00:00
Claude
4b30d4a44e feat(connections): edit connections via PUT — backend + UI + blank-secret merge
Backend: PUT /api/connections/{id} with UpdateConnectionRequest {Name, Config}.
Provider is immutable; a secret field left blank in the incoming config is
merged from the stored row so users can rename or rotate non-secret fields
without re-typing every credential. Invalidates the ConnectionInstanceRegistry
cache on update so the next GetConnection() re-opens with the fresh config.
409 on unique-name-per-provider collision, 404 on unknown id, 400 on non-
object config. 6 new xUnit tests cover the merge, overwrite, 404, 409, 400
paths plus the happy-path round-trip.

Frontend: ConnectionsPage gains an Edit pencil per row. The form is shared
between create and edit modes; provider select is disabled in edit; secret
fields render blank with an inline hint that leaving them blank keeps the
stored value. One new Vitest covers the edit flow.
2026-08-28 19:50:08 +00:00
Claude
d12581ad12 docs: fix Plan-4 order — push to origin BEFORE triggering Coolify deploy 2026-08-28 19:20:22 +00:00
Claude
bbb76b5920 docs: pin Plan-4 close-out head SHA 2026-08-28 19:11:43 +00:00
Claude
d237cc06e4 docs: close out Plan 4 — live at core.tes.gd, clear Plan-4 follow-ups 2026-08-28 19:11:33 +00:00
Claude
c41d0f9216 docs: add Plan 4 — Container + Coolify deploy 2026-08-28 19:11:33 +00:00
Claude
b6943c0e69 chore: gitignore deploy.json before populating 2026-08-28 19:07:03 +00:00
Claude
d82705d8ab feat(deploy): coolify docker-compose — expose:8080, /data volume, SERVICE_FQDN_APP_8080 2026-08-28 19:06:15 +00:00
Claude
a5d76e109f feat(docker): multi-stage Dockerfile — pnpm SPA build + dotnet publish + aspnet:9.0 runtime 2026-08-28 19:03:27 +00:00
Claude
32a2b2ee53 chore(docker): add .dockerignore excluding bin/obj/node_modules/wwwroot 2026-08-28 18:57:44 +00:00
Claude
6ffc59870c fix(auth): heal legacy plaintext admin.password_hash_source on boot 2026-08-28 18:54:35 +00:00
Claude
3d9df50f20 feat(api): honour X-Forwarded-Proto so Secure cookies flip on behind Traefik 2026-08-28 18:48:30 +00:00
Claude
7854cb02ec chore(frontend): exclude e2e/ from Vitest discovery 2026-08-28 16:40:16 +00:00
Claude
2a1b90c731 docs: close out Plan 3 — React SPA live 2026-08-28 16:38:55 +00:00
Claude
294bd57317 test(e2e): playwright smoke — login/create/edit/save happy path 2026-08-28 16:37:26 +00:00
Claude
03de45cf8e feat(api): serve SPA from wwwroot + SPA fallback for client-side routes 2026-08-28 16:32:16 +00:00