diff --git a/tables/js/add-row.js b/tables/js/add-row.js
index d8b1f0f..ef791b9 100644
--- a/tables/js/add-row.js
+++ b/tables/js/add-row.js
@@ -1,12 +1,15 @@
-// add-row.js — inline new-row creation.
+// add-row.js — new-row creation.
//
-// Click "+ Add row" → append a draft row at the end of state.rows,
-// focus its first editable cell, accumulate user typing into the
-// drafts buffer like any other row. On row-blur, save.js detects the
-// row.isNew flag and POSTs to
/form.html (the form-create
-// endpoint). The 201 response carries the new row's Location; we swap
-// the synthetic url/yamlUrl for the real ones and the draft row
-// becomes a normal saved row.
+// Two paths, chosen by the table's schema:
+// - Record-tables (identity composed from required fields that aren't
+// columns — e.g. the risk register's tracking-number components): "+ Add
+// row" navigates to the compose form (/form.html), the only place
+// those components can be supplied. See needsComposeForm().
+// - Simple tables (all required fields are columns): "+ Add row" appends a
+// draft row at the end of state.rows, focuses its first editable cell, and
+// accumulates typing into the drafts buffer like any other row. On
+// row-blur, save.js detects row.isNew and POSTs to /form.html; the
+// 201 Location swaps the synthetic url and the draft becomes a saved row.
//
// Synthetic identity: each new row gets a temporary "__new-" url
// so rowKey() returns something unique for selection + draft tracking.
@@ -34,8 +37,29 @@
return dir + 'form.html';
}
- // Create-and-paint: the user-facing path.
+ // True when a new record's identity is composed from required fields that
+ // AREN'T table columns (e.g. the risk register's project/discipline/
+ // sequence tracking-number components). Such rows can't be created by
+ // typing into the grid — they need the compose form. Server mode only
+ // (the form handler is server-side).
+ function needsComposeForm() {
+ const ctx = app.context || {};
+ if (!app.state || app.state.source !== 'server') return false;
+ const req = (ctx.rowSchema && Array.isArray(ctx.rowSchema.required)) ? ctx.rowSchema.required : [];
+ if (!req.length) return false;
+ const colFields = {};
+ (ctx.columns || []).forEach(function (c) { if (c && c.field) colFields[c.field] = true; });
+ return req.some(function (f) { return !colFields[f]; });
+ }
+
+ // Create-and-paint: the user-facing path. Record-tables (composed identity)
+ // open the compose form directly — the grid can't supply their
+ // tracking-number components; simple tables append an inline draft row.
function invoke() {
+ if (needsComposeForm()) {
+ window.location.href = formCreateUrl();
+ return;
+ }
const key = createSilent();
if (typeof app.repaint === 'function') app.repaint();
focusNewRow(key);