@nanobpm/urban 0.79.0 → 0.80.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -31,6 +31,8 @@ import type { EngineClient } from "../host.ts";
31
31
  import { html, json, type Route } from "../router.ts";
32
32
  import { cancelInstanceReconciling, type CancelInstanceResult } from "./cancel.ts";
33
33
  import { apiDocsPath } from "./api.ts";
34
+ import { FORMJS_JS } from "./formjs.gen.ts";
35
+ import { completeUserTaskResponse, resolveFormResponse } from "./forms.ts";
34
36
  import { quoteIdent } from "./gateway.ts";
35
37
  import { RENDERER_JS } from "./runtime.gen.ts";
36
38
 
@@ -545,6 +547,28 @@ export function createPagesRoutes(opts: PagesOptions, deps: PagesDeps): Route[]
545
547
  },
546
548
  });
547
549
 
550
+ // ── GET /app/actions/form & POST /app/actions/complete (ADR 0026, #457) ───
551
+ // Engine-declared forms in a `dataGrid` detail drawer. A grid whose `detail`
552
+ // opts into `engineForm` resolves the selected row's `form_key` here and
553
+ // completes the row's user task here — the SAME two seams the `taskInbox`
554
+ // surface uses, reused (not forked) via `forms.ts` so the resolution gate and
555
+ // the completion contract can't drift between the two surfaces. This closes the
556
+ // form-duplication drift class: the grid renders the authoritative deployed
557
+ // `.form` rather than a hand-authored page-local `detail.form` copy.
558
+ routes.push({
559
+ method: "GET",
560
+ path: "/app/actions/form",
561
+ source: "surface:pages",
562
+ handler: (req) =>
563
+ resolveFormResponse(engine, req.query.get("formKey") ?? undefined, req.query.get("formId") ?? undefined),
564
+ });
565
+ routes.push({
566
+ method: "POST",
567
+ path: "/app/actions/complete",
568
+ source: "surface:pages",
569
+ handler: async (req) => completeUserTaskResponse(engine, await req.text()),
570
+ });
571
+
548
572
  // ── nested (multi-appView) sidecars (#442) ──────────────────────────────
549
573
  // An app with more than one `appView` cannot share the four FLAT sidecar names above:
550
574
  // each view ships its own SUBDIR sidecar — e.g. `pages/cockpit.page.json` →
@@ -668,6 +692,7 @@ function rendererShell(homePage: string, apiDocsPath?: string): string {
668
692
  </head>
669
693
  <body>${apiDocsBadge}
670
694
  <main id="page" data-home="${escapeAttr(homePage)}"><p class="pc-empty">Loading…</p></main>
695
+ <script>${FORMJS_JS}</script>
671
696
  <script type="module" src=".${RUNTIME_JS_PATH}"></script>
672
697
  </body>
673
698
  </html>`;
@@ -736,6 +761,19 @@ body { margin:0; font:15px/1.5 system-ui,sans-serif; padding:2rem; max-width:64r
736
761
  .pc-field-check input { width:auto; padding:0; accent-color:var(--nano-accent); cursor:pointer; }
737
762
  .pc-btn { padding:.5rem .9rem; border:0; border-radius:.4rem; background:var(--nano-accent); color:var(--nano-on-accent); font:inherit; cursor:pointer; }
738
763
  .pc-btn:disabled { opacity:.5; cursor:default; }
764
+ /* The shared engine-form renderer (NanoFormJs, ADR 0026/#457) styled to match the
765
+ page runtime's native detail controls. njf-* are its stable class names; both
766
+ this surface and the taskInbox page style the same renderer output. */
767
+ .njf-form { display:flex; flex-direction:column; gap:.4rem; margin-top:.5rem; }
768
+ .njf-heading { font-size:1rem; margin:0 0 .25rem; }
769
+ .njf-text { color:var(--nano-text-muted); margin:.25rem 0; }
770
+ .njf-field { display:flex; flex-direction:column; gap:.25rem; }
771
+ .njf-field label { font-size:.8rem; color:var(--nano-text-muted); }
772
+ .njf-field input:not([type=checkbox]):not([type=radio]), .njf-field textarea, .njf-field select { padding:.5rem .6rem; border:1px solid var(--nano-edge); border-radius:.4rem; font:inherit; background:var(--nano-inset); color:var(--nano-text); max-width:24rem; }
773
+ .njf-actions { display:flex; gap:.5rem; margin-top:.4rem; }
774
+ .njf-actions button { padding:.5rem .9rem; border:0; border-radius:.4rem; background:var(--nano-accent); color:var(--nano-on-accent); font:inherit; cursor:pointer; }
775
+ .njf-msg { font-size:.85rem; margin-top:.35rem; }
776
+ .njf-msg.err { color:var(--nano-danger); }
739
777
  .pc-msg { font-size:.85rem; margin-top:.5rem; min-height:1.2em; }
740
778
  .pc-msg.err { color:var(--nano-danger); }
741
779
  .pc-msg.ok { color:var(--nano-ok); }