@validation-os/dashboard 0.7.1 → 0.8.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.
- package/dist/index.d.ts +315 -108
- package/dist/index.js +699 -130
- package/dist/index.js.map +1 -1
- package/dist/styles.css +117 -0
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -506,11 +506,12 @@ var area = (key, label) => ({
|
|
|
506
506
|
label,
|
|
507
507
|
kind: "textarea"
|
|
508
508
|
});
|
|
509
|
-
var num2 = (key, label) => ({
|
|
509
|
+
var num2 = (key, label, range = {}) => ({
|
|
510
510
|
key,
|
|
511
511
|
label,
|
|
512
512
|
kind: "number",
|
|
513
|
-
nullable: true
|
|
513
|
+
nullable: true,
|
|
514
|
+
...range
|
|
514
515
|
});
|
|
515
516
|
var sel = (key, label, options, nullable = false) => ({ key, label, kind: "select", options, nullable });
|
|
516
517
|
var READING_RUNGS = [
|
|
@@ -528,7 +529,11 @@ var EDITORS = {
|
|
|
528
529
|
assumptions: [
|
|
529
530
|
t("Title", "Assumption"),
|
|
530
531
|
area("Description", "Description"),
|
|
531
|
-
|
|
532
|
+
// The only hand-scored number in the registry (`registry-schema.md`) — a
|
|
533
|
+
// 0–100 severity-if-false seed. Every other number (Confidence, Derived
|
|
534
|
+
// Impact, Risk, Strength, Source quality, Completeness %) is computed on
|
|
535
|
+
// write and deliberately absent from this list.
|
|
536
|
+
num2("Impact", "Impact", { min: 0, max: 100 }),
|
|
532
537
|
sel("Status", "Status", ["Draft", "Live", "Invalidated"]),
|
|
533
538
|
t("Lens", "Lens"),
|
|
534
539
|
area("Scoring justification", "Scoring justification")
|
|
@@ -601,6 +606,28 @@ function coerce(field, raw) {
|
|
|
601
606
|
function norm(value) {
|
|
602
607
|
return value === void 0 || value === "" ? null : value;
|
|
603
608
|
}
|
|
609
|
+
function fieldError(field, raw) {
|
|
610
|
+
if (field.kind !== "number") return null;
|
|
611
|
+
const str5 = String(raw ?? "").trim();
|
|
612
|
+
if (str5 === "") return null;
|
|
613
|
+
const n = Number(str5);
|
|
614
|
+
if (Number.isNaN(n)) return `${field.label} must be a number.`;
|
|
615
|
+
if (field.min !== void 0 && n < field.min) {
|
|
616
|
+
return `${field.label} must be at least ${field.min}.`;
|
|
617
|
+
}
|
|
618
|
+
if (field.max !== void 0 && n > field.max) {
|
|
619
|
+
return `${field.label} must be at most ${field.max}.`;
|
|
620
|
+
}
|
|
621
|
+
return null;
|
|
622
|
+
}
|
|
623
|
+
function draftErrors(register, draft) {
|
|
624
|
+
const errors = {};
|
|
625
|
+
for (const field of editableFields(register)) {
|
|
626
|
+
const message = fieldError(field, draft[field.key] ?? "");
|
|
627
|
+
if (message) errors[field.key] = message;
|
|
628
|
+
}
|
|
629
|
+
return errors;
|
|
630
|
+
}
|
|
604
631
|
function buildPatch(register, original, draft) {
|
|
605
632
|
const patch = { version: original.version };
|
|
606
633
|
for (const field of editableFields(register)) {
|
|
@@ -1113,6 +1140,154 @@ function derivedLabel(key) {
|
|
|
1113
1140
|
return DERIVED_LABEL[key] ?? fieldLabel(key);
|
|
1114
1141
|
}
|
|
1115
1142
|
|
|
1143
|
+
// src/detail-fields.ts
|
|
1144
|
+
var META_FIELDS = /* @__PURE__ */ new Set([
|
|
1145
|
+
"id",
|
|
1146
|
+
"version",
|
|
1147
|
+
"createdAt",
|
|
1148
|
+
"updatedAt",
|
|
1149
|
+
"derived"
|
|
1150
|
+
]);
|
|
1151
|
+
var SUPPRESSED_FIELDS = /* @__PURE__ */ new Set(["barLineAssumptionIds"]);
|
|
1152
|
+
var RELATION_TARGET = {
|
|
1153
|
+
dependsOnIds: "assumptions",
|
|
1154
|
+
enablesIds: "assumptions",
|
|
1155
|
+
contradictsIds: "assumptions",
|
|
1156
|
+
readingIds: "readings",
|
|
1157
|
+
assumptionId: "assumptions",
|
|
1158
|
+
experimentId: "experiments",
|
|
1159
|
+
basedOnIds: "assumptions",
|
|
1160
|
+
resolvesIds: "assumptions"
|
|
1161
|
+
};
|
|
1162
|
+
var OWNER_FIELDS = /* @__PURE__ */ new Set(["Owner", "Agreed by"]);
|
|
1163
|
+
function relatedList(related, register) {
|
|
1164
|
+
return related[register] ?? [];
|
|
1165
|
+
}
|
|
1166
|
+
function resolveItem(related, register, id) {
|
|
1167
|
+
const hit = relatedList(related, register).find((r) => r.id === id);
|
|
1168
|
+
return { id, register, title: hit ? primaryLabel(hit) : id };
|
|
1169
|
+
}
|
|
1170
|
+
function idsOf(value) {
|
|
1171
|
+
if (Array.isArray(value)) {
|
|
1172
|
+
return value.filter((v) => typeof v === "string");
|
|
1173
|
+
}
|
|
1174
|
+
return typeof value === "string" && value ? [value] : [];
|
|
1175
|
+
}
|
|
1176
|
+
function ownerNames(value) {
|
|
1177
|
+
if (!Array.isArray(value)) return [];
|
|
1178
|
+
return value.map((v) => {
|
|
1179
|
+
if (v && typeof v === "object") {
|
|
1180
|
+
const name = v.name;
|
|
1181
|
+
if (typeof name === "string" && name) return name;
|
|
1182
|
+
const id = v.id;
|
|
1183
|
+
return typeof id === "string" ? id : "\u2014";
|
|
1184
|
+
}
|
|
1185
|
+
return typeof v === "string" ? v : "\u2014";
|
|
1186
|
+
});
|
|
1187
|
+
}
|
|
1188
|
+
function resolveBarLines(bars, related) {
|
|
1189
|
+
return bars.map((b) => ({
|
|
1190
|
+
rightIf: b.rightIf ?? "",
|
|
1191
|
+
wrongIf: b.wrongIf ?? null,
|
|
1192
|
+
plannedRung: b.plannedRung ?? "",
|
|
1193
|
+
barVerdict: b.barVerdict ?? null,
|
|
1194
|
+
assumption: b.assumptionId ? resolveItem(related, "assumptions", b.assumptionId) : null
|
|
1195
|
+
}));
|
|
1196
|
+
}
|
|
1197
|
+
function detailRows(register, record, related = {}) {
|
|
1198
|
+
const keys = Object.keys(record).filter(
|
|
1199
|
+
(k) => !META_FIELDS.has(k) && !SUPPRESSED_FIELDS.has(k)
|
|
1200
|
+
);
|
|
1201
|
+
return keys.map((key) => {
|
|
1202
|
+
const value = record[key];
|
|
1203
|
+
const label = fieldLabel(key);
|
|
1204
|
+
const target = RELATION_TARGET[key];
|
|
1205
|
+
if (target) {
|
|
1206
|
+
const items = idsOf(value).map((id) => resolveItem(related, target, id));
|
|
1207
|
+
return { key, label, kind: "relation", items };
|
|
1208
|
+
}
|
|
1209
|
+
if (OWNER_FIELDS.has(key)) {
|
|
1210
|
+
return { key, label, kind: "owner", names: ownerNames(value) };
|
|
1211
|
+
}
|
|
1212
|
+
if (key === "barLines" && Array.isArray(value)) {
|
|
1213
|
+
return {
|
|
1214
|
+
key,
|
|
1215
|
+
label,
|
|
1216
|
+
kind: "bar-lines",
|
|
1217
|
+
bars: resolveBarLines(value, related)
|
|
1218
|
+
};
|
|
1219
|
+
}
|
|
1220
|
+
return { key, label, kind: "text", text: formatValue(value) };
|
|
1221
|
+
});
|
|
1222
|
+
}
|
|
1223
|
+
|
|
1224
|
+
// src/edit-fields.tsx
|
|
1225
|
+
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
1226
|
+
function EditFields({
|
|
1227
|
+
register,
|
|
1228
|
+
draft,
|
|
1229
|
+
errors,
|
|
1230
|
+
onField
|
|
1231
|
+
}) {
|
|
1232
|
+
return /* @__PURE__ */ jsx2("div", { className: "vos-field-stack", children: editableFields(register).map((field) => /* @__PURE__ */ jsx2(
|
|
1233
|
+
FieldInput,
|
|
1234
|
+
{
|
|
1235
|
+
field,
|
|
1236
|
+
value: draft[field.key],
|
|
1237
|
+
error: errors?.[field.key],
|
|
1238
|
+
onChange: (v) => onField(field.key, v)
|
|
1239
|
+
},
|
|
1240
|
+
field.key
|
|
1241
|
+
)) });
|
|
1242
|
+
}
|
|
1243
|
+
function FieldInput({
|
|
1244
|
+
field,
|
|
1245
|
+
value,
|
|
1246
|
+
error,
|
|
1247
|
+
onChange
|
|
1248
|
+
}) {
|
|
1249
|
+
const id = `field-${field.key.replace(/\s+/g, "-")}`;
|
|
1250
|
+
return /* @__PURE__ */ jsxs2("div", { className: "vos-field", children: [
|
|
1251
|
+
/* @__PURE__ */ jsx2("label", { htmlFor: id, children: field.label }),
|
|
1252
|
+
field.kind === "textarea" ? /* @__PURE__ */ jsx2(
|
|
1253
|
+
"textarea",
|
|
1254
|
+
{
|
|
1255
|
+
id,
|
|
1256
|
+
value: String(value ?? ""),
|
|
1257
|
+
onChange: (e) => onChange(e.target.value),
|
|
1258
|
+
rows: 3,
|
|
1259
|
+
className: "vos-input",
|
|
1260
|
+
"aria-invalid": error ? true : void 0
|
|
1261
|
+
}
|
|
1262
|
+
) : field.kind === "select" ? /* @__PURE__ */ jsxs2(
|
|
1263
|
+
"select",
|
|
1264
|
+
{
|
|
1265
|
+
id,
|
|
1266
|
+
value: String(value ?? ""),
|
|
1267
|
+
onChange: (e) => onChange(e.target.value),
|
|
1268
|
+
className: "vos-input",
|
|
1269
|
+
children: [
|
|
1270
|
+
field.nullable ? /* @__PURE__ */ jsx2("option", { value: "", children: "\u2014" }) : null,
|
|
1271
|
+
field.options?.map((opt) => /* @__PURE__ */ jsx2("option", { value: opt, children: opt }, opt))
|
|
1272
|
+
]
|
|
1273
|
+
}
|
|
1274
|
+
) : /* @__PURE__ */ jsx2(
|
|
1275
|
+
"input",
|
|
1276
|
+
{
|
|
1277
|
+
id,
|
|
1278
|
+
type: field.kind === "number" ? "number" : "text",
|
|
1279
|
+
min: field.kind === "number" ? field.min : void 0,
|
|
1280
|
+
max: field.kind === "number" ? field.max : void 0,
|
|
1281
|
+
value: String(value ?? ""),
|
|
1282
|
+
onChange: (e) => onChange(e.target.value),
|
|
1283
|
+
className: "vos-input",
|
|
1284
|
+
"aria-invalid": error ? true : void 0
|
|
1285
|
+
}
|
|
1286
|
+
),
|
|
1287
|
+
error ? /* @__PURE__ */ jsx2("p", { role: "alert", className: "vos-field-error", children: error }) : null
|
|
1288
|
+
] });
|
|
1289
|
+
}
|
|
1290
|
+
|
|
1116
1291
|
// src/glossary-text.tsx
|
|
1117
1292
|
import { Fragment as Fragment2 } from "react";
|
|
1118
1293
|
|
|
@@ -1193,7 +1368,7 @@ function toGlossaryTerms(records) {
|
|
|
1193
1368
|
}
|
|
1194
1369
|
|
|
1195
1370
|
// src/glossary-text.tsx
|
|
1196
|
-
import { Fragment as Fragment3, jsx as
|
|
1371
|
+
import { Fragment as Fragment3, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
1197
1372
|
var PILL_CLASS = {
|
|
1198
1373
|
good: "vos-pill vos-pill-good",
|
|
1199
1374
|
warn: "vos-pill vos-pill-warn",
|
|
@@ -1208,8 +1383,8 @@ function GlossaryText({
|
|
|
1208
1383
|
onOpenTerm
|
|
1209
1384
|
}) {
|
|
1210
1385
|
const nodes = linkify(text, terms, { selfId });
|
|
1211
|
-
return /* @__PURE__ */
|
|
1212
|
-
(node, i) => node.kind === "text" ? /* @__PURE__ */
|
|
1386
|
+
return /* @__PURE__ */ jsx3(Fragment3, { children: nodes.map(
|
|
1387
|
+
(node, i) => node.kind === "text" ? /* @__PURE__ */ jsx3(Fragment2, { children: node.text }, i) : /* @__PURE__ */ jsx3(
|
|
1213
1388
|
TermLink,
|
|
1214
1389
|
{
|
|
1215
1390
|
text: node.text,
|
|
@@ -1225,8 +1400,8 @@ function TermLink({
|
|
|
1225
1400
|
term,
|
|
1226
1401
|
onOpenTerm
|
|
1227
1402
|
}) {
|
|
1228
|
-
return /* @__PURE__ */
|
|
1229
|
-
/* @__PURE__ */
|
|
1403
|
+
return /* @__PURE__ */ jsxs3("span", { className: "vos-gloss", children: [
|
|
1404
|
+
/* @__PURE__ */ jsx3(
|
|
1230
1405
|
"button",
|
|
1231
1406
|
{
|
|
1232
1407
|
type: "button",
|
|
@@ -1235,15 +1410,15 @@ function TermLink({
|
|
|
1235
1410
|
children: text
|
|
1236
1411
|
}
|
|
1237
1412
|
),
|
|
1238
|
-
/* @__PURE__ */
|
|
1239
|
-
/* @__PURE__ */
|
|
1240
|
-
/* @__PURE__ */
|
|
1241
|
-
/* @__PURE__ */
|
|
1413
|
+
/* @__PURE__ */ jsxs3("span", { className: "vos-gloss-pop", role: "tooltip", children: [
|
|
1414
|
+
/* @__PURE__ */ jsxs3("span", { className: "vos-gloss-pop-head", children: [
|
|
1415
|
+
/* @__PURE__ */ jsx3("b", { children: term.title }),
|
|
1416
|
+
/* @__PURE__ */ jsx3("span", { className: PILL_CLASS[statusTone(term.status)], children: term.status })
|
|
1242
1417
|
] }),
|
|
1243
|
-
/* @__PURE__ */
|
|
1244
|
-
term.dontConfuseWith.length ? /* @__PURE__ */
|
|
1245
|
-
/* @__PURE__ */
|
|
1246
|
-
term.dontConfuseWith.map((n) => /* @__PURE__ */
|
|
1418
|
+
/* @__PURE__ */ jsx3("span", { className: "vos-gloss-pop-def", children: term.definition || "\u2014" }),
|
|
1419
|
+
term.dontConfuseWith.length ? /* @__PURE__ */ jsxs3("span", { className: "vos-gloss-pop-neighbours", children: [
|
|
1420
|
+
/* @__PURE__ */ jsx3("span", { className: "vos-gloss-pop-label", children: "Don't confuse with" }),
|
|
1421
|
+
term.dontConfuseWith.map((n) => /* @__PURE__ */ jsx3(
|
|
1247
1422
|
"button",
|
|
1248
1423
|
{
|
|
1249
1424
|
type: "button",
|
|
@@ -1261,7 +1436,7 @@ function TermLink({
|
|
|
1261
1436
|
// src/journey.ts
|
|
1262
1437
|
import {
|
|
1263
1438
|
assumptionCompleteness as assumptionCompleteness2,
|
|
1264
|
-
toReadingInput as
|
|
1439
|
+
toReadingInput as toReadingInput3
|
|
1265
1440
|
} from "@validation-os/core";
|
|
1266
1441
|
import {
|
|
1267
1442
|
assembleJourney,
|
|
@@ -1302,6 +1477,97 @@ function isTesting(a, experiments) {
|
|
|
1302
1477
|
);
|
|
1303
1478
|
}
|
|
1304
1479
|
|
|
1480
|
+
// src/cycles.ts
|
|
1481
|
+
import {
|
|
1482
|
+
toReadingInput as toReadingInput2
|
|
1483
|
+
} from "@validation-os/core";
|
|
1484
|
+
import { confidenceAttribution } from "@validation-os/core/derivation";
|
|
1485
|
+
var DIRECT_CYCLE_KEY = "direct";
|
|
1486
|
+
function readingDate(r) {
|
|
1487
|
+
return str3(r.Date);
|
|
1488
|
+
}
|
|
1489
|
+
function toCycleReading(r) {
|
|
1490
|
+
return {
|
|
1491
|
+
id: r.id,
|
|
1492
|
+
date: readingDate(r),
|
|
1493
|
+
result: r.Result ?? null
|
|
1494
|
+
};
|
|
1495
|
+
}
|
|
1496
|
+
function sortByDate(readings) {
|
|
1497
|
+
return [...readings].sort((a, b) => {
|
|
1498
|
+
if (a.date === b.date) return 0;
|
|
1499
|
+
if (a.date === null) return 1;
|
|
1500
|
+
if (b.date === null) return -1;
|
|
1501
|
+
return a.date < b.date ? -1 : 1;
|
|
1502
|
+
});
|
|
1503
|
+
}
|
|
1504
|
+
function barVerdictFor(exp, assumptionId) {
|
|
1505
|
+
const bars = exp.barLines ?? [];
|
|
1506
|
+
const line = bars.find((b) => b.assumptionId === assumptionId);
|
|
1507
|
+
return line?.barVerdict ?? null;
|
|
1508
|
+
}
|
|
1509
|
+
function buildCycles(assumptionId, readings, experiments) {
|
|
1510
|
+
const mine = readings.filter((r) => r.assumptionId === assumptionId);
|
|
1511
|
+
const { movers } = confidenceAttribution(mine.map(toReadingInput2));
|
|
1512
|
+
const moverByKey = new Map(movers.map((m) => [m.key, m]));
|
|
1513
|
+
const byExperiment = /* @__PURE__ */ new Map();
|
|
1514
|
+
const direct = [];
|
|
1515
|
+
for (const r of mine) {
|
|
1516
|
+
const expId = str3(r.experimentId);
|
|
1517
|
+
if (expId) {
|
|
1518
|
+
const bucket = byExperiment.get(expId) ?? [];
|
|
1519
|
+
bucket.push(r);
|
|
1520
|
+
byExperiment.set(expId, bucket);
|
|
1521
|
+
} else {
|
|
1522
|
+
direct.push(r);
|
|
1523
|
+
}
|
|
1524
|
+
}
|
|
1525
|
+
const experimentsById = new Map(experiments.map((e) => [e.id, e]));
|
|
1526
|
+
const experimentIds = /* @__PURE__ */ new Set([
|
|
1527
|
+
...experiments.filter((e) => testsAssumption(e, assumptionId)).map((e) => e.id),
|
|
1528
|
+
...byExperiment.keys()
|
|
1529
|
+
]);
|
|
1530
|
+
const cycles = [...experimentIds].map((id) => {
|
|
1531
|
+
const exp = experimentsById.get(id);
|
|
1532
|
+
const readingViews = sortByDate((byExperiment.get(id) ?? []).map(toCycleReading));
|
|
1533
|
+
const mover = moverByKey.get(id);
|
|
1534
|
+
const date = (exp ? str3(exp.Date) : null) ?? readingViews[0]?.date ?? null;
|
|
1535
|
+
return {
|
|
1536
|
+
key: id,
|
|
1537
|
+
kind: "experiment",
|
|
1538
|
+
title: exp ? str3(exp.Title) : null,
|
|
1539
|
+
status: exp ? str3(exp.Status) : null,
|
|
1540
|
+
date,
|
|
1541
|
+
barVerdict: exp ? barVerdictFor(exp, assumptionId) : null,
|
|
1542
|
+
readings: readingViews,
|
|
1543
|
+
contribution: mover?.contribution ?? 0,
|
|
1544
|
+
magnitude: mover?.magnitude ?? 0
|
|
1545
|
+
};
|
|
1546
|
+
});
|
|
1547
|
+
if (direct.length > 0) {
|
|
1548
|
+
const readingViews = sortByDate(direct.map(toCycleReading));
|
|
1549
|
+
const mover = moverByKey.get(DIRECT_CYCLE_KEY);
|
|
1550
|
+
cycles.push({
|
|
1551
|
+
key: DIRECT_CYCLE_KEY,
|
|
1552
|
+
kind: "direct",
|
|
1553
|
+
title: null,
|
|
1554
|
+
status: null,
|
|
1555
|
+
date: readingViews[0]?.date ?? null,
|
|
1556
|
+
barVerdict: null,
|
|
1557
|
+
readings: readingViews,
|
|
1558
|
+
contribution: mover?.contribution ?? 0,
|
|
1559
|
+
magnitude: mover?.magnitude ?? 0
|
|
1560
|
+
});
|
|
1561
|
+
}
|
|
1562
|
+
cycles.sort((a, b) => {
|
|
1563
|
+
if (a.date === b.date) return a.key.localeCompare(b.key);
|
|
1564
|
+
if (a.date === null) return 1;
|
|
1565
|
+
if (b.date === null) return -1;
|
|
1566
|
+
return a.date < b.date ? -1 : 1;
|
|
1567
|
+
});
|
|
1568
|
+
return cycles;
|
|
1569
|
+
}
|
|
1570
|
+
|
|
1305
1571
|
// src/journey.ts
|
|
1306
1572
|
function str4(v) {
|
|
1307
1573
|
return typeof v === "string" ? v : "";
|
|
@@ -1368,18 +1634,20 @@ function buildJourney(assumptionId, records, now) {
|
|
|
1368
1634
|
createdAt: str4(belief2.createdAt) || null,
|
|
1369
1635
|
impactScored: belief2.Impact != null
|
|
1370
1636
|
},
|
|
1371
|
-
readings: myReadings.map(
|
|
1637
|
+
readings: myReadings.map(toReadingInput3),
|
|
1372
1638
|
experiments: myExperiments,
|
|
1373
1639
|
now
|
|
1374
1640
|
}).map((event) => ({ ...event, label: labelFor(event) }));
|
|
1375
1641
|
const nextMove2 = rankNextMoves(toNextMoveInput(records)).find(
|
|
1376
1642
|
(m) => m.assumptionId === assumptionId
|
|
1377
1643
|
) ?? null;
|
|
1644
|
+
const cycles = buildCycles(assumptionId, records.readings, records.experiments);
|
|
1378
1645
|
return {
|
|
1379
1646
|
id: assumptionId,
|
|
1380
1647
|
statement: str4(belief2.Title),
|
|
1381
1648
|
stage,
|
|
1382
1649
|
events,
|
|
1650
|
+
cycles,
|
|
1383
1651
|
nextMove: nextMove2,
|
|
1384
1652
|
resolved: resolvedKind(belief2)
|
|
1385
1653
|
};
|
|
@@ -1393,7 +1661,7 @@ import { useState as useState3 } from "react";
|
|
|
1393
1661
|
|
|
1394
1662
|
// src/drawer-shell.tsx
|
|
1395
1663
|
import { useEffect as useEffect2, useRef } from "react";
|
|
1396
|
-
import { Fragment as Fragment4, jsx as
|
|
1664
|
+
import { Fragment as Fragment4, jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
1397
1665
|
function DrawerShell({
|
|
1398
1666
|
open,
|
|
1399
1667
|
onClose,
|
|
@@ -1411,8 +1679,8 @@ function DrawerShell({
|
|
|
1411
1679
|
return () => document.removeEventListener("keydown", onKey);
|
|
1412
1680
|
}, [open, onClose]);
|
|
1413
1681
|
if (!open) return null;
|
|
1414
|
-
return /* @__PURE__ */
|
|
1415
|
-
/* @__PURE__ */
|
|
1682
|
+
return /* @__PURE__ */ jsxs4(Fragment4, { children: [
|
|
1683
|
+
/* @__PURE__ */ jsx4(
|
|
1416
1684
|
"button",
|
|
1417
1685
|
{
|
|
1418
1686
|
type: "button",
|
|
@@ -1421,7 +1689,7 @@ function DrawerShell({
|
|
|
1421
1689
|
className: "vos-scrim"
|
|
1422
1690
|
}
|
|
1423
1691
|
),
|
|
1424
|
-
/* @__PURE__ */
|
|
1692
|
+
/* @__PURE__ */ jsx4(
|
|
1425
1693
|
"aside",
|
|
1426
1694
|
{
|
|
1427
1695
|
ref: panelRef,
|
|
@@ -1436,65 +1704,6 @@ function DrawerShell({
|
|
|
1436
1704
|
] });
|
|
1437
1705
|
}
|
|
1438
1706
|
|
|
1439
|
-
// src/edit-fields.tsx
|
|
1440
|
-
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
1441
|
-
function EditFields({
|
|
1442
|
-
register,
|
|
1443
|
-
draft,
|
|
1444
|
-
onField
|
|
1445
|
-
}) {
|
|
1446
|
-
return /* @__PURE__ */ jsx4("div", { className: "vos-field-stack", children: editableFields(register).map((field) => /* @__PURE__ */ jsx4(
|
|
1447
|
-
FieldInput,
|
|
1448
|
-
{
|
|
1449
|
-
field,
|
|
1450
|
-
value: draft[field.key],
|
|
1451
|
-
onChange: (v) => onField(field.key, v)
|
|
1452
|
-
},
|
|
1453
|
-
field.key
|
|
1454
|
-
)) });
|
|
1455
|
-
}
|
|
1456
|
-
function FieldInput({
|
|
1457
|
-
field,
|
|
1458
|
-
value,
|
|
1459
|
-
onChange
|
|
1460
|
-
}) {
|
|
1461
|
-
const id = `field-${field.key.replace(/\s+/g, "-")}`;
|
|
1462
|
-
return /* @__PURE__ */ jsxs4("div", { className: "vos-field", children: [
|
|
1463
|
-
/* @__PURE__ */ jsx4("label", { htmlFor: id, children: field.label }),
|
|
1464
|
-
field.kind === "textarea" ? /* @__PURE__ */ jsx4(
|
|
1465
|
-
"textarea",
|
|
1466
|
-
{
|
|
1467
|
-
id,
|
|
1468
|
-
value: String(value ?? ""),
|
|
1469
|
-
onChange: (e) => onChange(e.target.value),
|
|
1470
|
-
rows: 3,
|
|
1471
|
-
className: "vos-input"
|
|
1472
|
-
}
|
|
1473
|
-
) : field.kind === "select" ? /* @__PURE__ */ jsxs4(
|
|
1474
|
-
"select",
|
|
1475
|
-
{
|
|
1476
|
-
id,
|
|
1477
|
-
value: String(value ?? ""),
|
|
1478
|
-
onChange: (e) => onChange(e.target.value),
|
|
1479
|
-
className: "vos-input",
|
|
1480
|
-
children: [
|
|
1481
|
-
field.nullable ? /* @__PURE__ */ jsx4("option", { value: "", children: "\u2014" }) : null,
|
|
1482
|
-
field.options?.map((opt) => /* @__PURE__ */ jsx4("option", { value: opt, children: opt }, opt))
|
|
1483
|
-
]
|
|
1484
|
-
}
|
|
1485
|
-
) : /* @__PURE__ */ jsx4(
|
|
1486
|
-
"input",
|
|
1487
|
-
{
|
|
1488
|
-
id,
|
|
1489
|
-
type: field.kind === "number" ? "number" : "text",
|
|
1490
|
-
value: String(value ?? ""),
|
|
1491
|
-
onChange: (e) => onChange(e.target.value),
|
|
1492
|
-
className: "vos-input"
|
|
1493
|
-
}
|
|
1494
|
-
)
|
|
1495
|
-
] });
|
|
1496
|
-
}
|
|
1497
|
-
|
|
1498
1707
|
// src/field-styles.ts
|
|
1499
1708
|
var FIELD_LABEL_CLASS = "vos-field-label";
|
|
1500
1709
|
var FIELD_CONTROL_CLASS = "vos-input";
|
|
@@ -2012,18 +2221,18 @@ function StatTile({
|
|
|
2012
2221
|
|
|
2013
2222
|
// src/understanding.ts
|
|
2014
2223
|
import {
|
|
2015
|
-
toReadingInput as
|
|
2224
|
+
toReadingInput as toReadingInput4
|
|
2016
2225
|
} from "@validation-os/core";
|
|
2017
2226
|
import {
|
|
2018
|
-
confidenceAttribution,
|
|
2227
|
+
confidenceAttribution as confidenceAttribution2,
|
|
2019
2228
|
confidenceTrajectory,
|
|
2020
2229
|
experimentProgress,
|
|
2021
2230
|
isConcluded as isConcluded2
|
|
2022
2231
|
} from "@validation-os/core/derivation";
|
|
2023
2232
|
function buildUnderstanding(assumption, readings, experiments) {
|
|
2024
2233
|
const mine = readings.filter((r) => r.assumptionId === assumption.id);
|
|
2025
|
-
const inputs = mine.map(
|
|
2026
|
-
const { confidence: confidence2, movers } =
|
|
2234
|
+
const inputs = mine.map(toReadingInput4);
|
|
2235
|
+
const { confidence: confidence2, movers } = confidenceAttribution2(inputs);
|
|
2027
2236
|
const experimentsById = new Map(experiments.map((e) => [e.id, e]));
|
|
2028
2237
|
const moverByExperiment = new Map(
|
|
2029
2238
|
movers.filter((m) => m.kind === "experiment").map((m) => [m.experimentId, m])
|
|
@@ -2268,6 +2477,10 @@ function BeliefJourney({
|
|
|
2268
2477
|
`${event.kind}-${event.refId ?? i}`
|
|
2269
2478
|
)) })
|
|
2270
2479
|
] }),
|
|
2480
|
+
journey.cycles.length > 0 ? /* @__PURE__ */ jsxs8("section", { children: [
|
|
2481
|
+
/* @__PURE__ */ jsx8("div", { className: "vos-why-section-title", children: "Round by round" }),
|
|
2482
|
+
/* @__PURE__ */ jsx8(CycleTimeline, { cycles: journey.cycles })
|
|
2483
|
+
] }) : null,
|
|
2271
2484
|
/* @__PURE__ */ jsxs8("section", { children: [
|
|
2272
2485
|
/* @__PURE__ */ jsx8("div", { className: "vos-why-section-title", children: "What moved the number" }),
|
|
2273
2486
|
/* @__PURE__ */ jsx8(UnderstandingPanel, { assumption, basePath })
|
|
@@ -2413,6 +2626,62 @@ function EventRow({
|
|
|
2413
2626
|
) : null
|
|
2414
2627
|
] });
|
|
2415
2628
|
}
|
|
2629
|
+
function readingDotTone(result) {
|
|
2630
|
+
if (result === "Validated") return "good";
|
|
2631
|
+
if (result === "Invalidated") return "crit";
|
|
2632
|
+
return "neutral";
|
|
2633
|
+
}
|
|
2634
|
+
var BAR_VERDICT_PILL = {
|
|
2635
|
+
Validated: "vos-pill vos-pill-good",
|
|
2636
|
+
Invalidated: "vos-pill vos-pill-crit",
|
|
2637
|
+
Inconclusive: "vos-pill vos-pill-neutral"
|
|
2638
|
+
};
|
|
2639
|
+
function CycleTimeline({ cycles }) {
|
|
2640
|
+
const maxMagnitude = Math.max(...cycles.map((c) => c.magnitude), 0.01);
|
|
2641
|
+
return /* @__PURE__ */ jsx8("ol", { className: "vos-cyc-list", children: cycles.map((cycle, i) => /* @__PURE__ */ jsx8(CycleCard, { cycle, n: i + 1, max: maxMagnitude }, cycle.key)) });
|
|
2642
|
+
}
|
|
2643
|
+
function CycleCard({
|
|
2644
|
+
cycle,
|
|
2645
|
+
n,
|
|
2646
|
+
max
|
|
2647
|
+
}) {
|
|
2648
|
+
const up = cycle.contribution >= 0;
|
|
2649
|
+
const moving = cycle.magnitude > 0;
|
|
2650
|
+
const width = Math.round(cycle.magnitude / max * 50);
|
|
2651
|
+
const fill = up ? { left: "50%", width: `${width}%`, background: "var(--vos-good)" } : { right: "50%", width: `${width}%`, background: "var(--vos-crit)" };
|
|
2652
|
+
return /* @__PURE__ */ jsxs8("li", { className: "vos-cyc-card", children: [
|
|
2653
|
+
/* @__PURE__ */ jsxs8("div", { className: "vos-cyc-head", children: [
|
|
2654
|
+
/* @__PURE__ */ jsxs8("span", { className: "vos-cyc-num", children: [
|
|
2655
|
+
"Round ",
|
|
2656
|
+
n
|
|
2657
|
+
] }),
|
|
2658
|
+
cycle.date ? /* @__PURE__ */ jsx8("span", { className: "vos-cyc-date", children: cycle.date }) : null
|
|
2659
|
+
] }),
|
|
2660
|
+
/* @__PURE__ */ jsx8("div", { className: "vos-cyc-title", children: cycle.kind === "direct" ? "Direct evidence" : cycle.title ?? "Untitled experiment" }),
|
|
2661
|
+
cycle.readings.length > 0 ? /* @__PURE__ */ jsx8(
|
|
2662
|
+
"div",
|
|
2663
|
+
{
|
|
2664
|
+
className: "vos-cyc-dots",
|
|
2665
|
+
role: "img",
|
|
2666
|
+
"aria-label": `${cycle.readings.length} reading${cycle.readings.length === 1 ? "" : "s"}`,
|
|
2667
|
+
children: cycle.readings.map((r) => /* @__PURE__ */ jsx8(
|
|
2668
|
+
"span",
|
|
2669
|
+
{
|
|
2670
|
+
className: `vos-jny-dot ${DOT_CLASS[readingDotTone(r.result)]}`
|
|
2671
|
+
},
|
|
2672
|
+
r.id
|
|
2673
|
+
))
|
|
2674
|
+
}
|
|
2675
|
+
) : /* @__PURE__ */ jsx8("span", { className: "vos-hint", children: "No readings yet" }),
|
|
2676
|
+
/* @__PURE__ */ jsxs8("div", { className: "vos-cyc-foot", children: [
|
|
2677
|
+
cycle.barVerdict ? /* @__PURE__ */ jsx8("span", { className: BAR_VERDICT_PILL[cycle.barVerdict], children: cycle.barVerdict }) : cycle.kind === "experiment" ? /* @__PURE__ */ jsx8("span", { className: "vos-hint", children: cycle.status === "Closed" ? "No bar line" : "Bar pending" }) : null,
|
|
2678
|
+
moving ? /* @__PURE__ */ jsxs8("span", { className: "vos-cyc-push", children: [
|
|
2679
|
+
/* @__PURE__ */ jsx8("span", { className: "vos-track vos-signed vos-cyc-track", children: /* @__PURE__ */ jsx8("i", { style: fill }) }),
|
|
2680
|
+
/* @__PURE__ */ jsx8("span", { className: up ? "vos-text-good" : "vos-text-crit", children: formatSigned(cycle.contribution) })
|
|
2681
|
+
] }) : null
|
|
2682
|
+
] })
|
|
2683
|
+
] });
|
|
2684
|
+
}
|
|
2416
2685
|
function NextMoveCard({
|
|
2417
2686
|
move,
|
|
2418
2687
|
resolved,
|
|
@@ -3073,9 +3342,62 @@ function RecordPage({
|
|
|
3073
3342
|
lists.experiments.refresh();
|
|
3074
3343
|
lists.readings.refresh();
|
|
3075
3344
|
lists.decisions.refresh();
|
|
3345
|
+
lists.glossary.refresh();
|
|
3076
3346
|
};
|
|
3077
3347
|
const terms = toGlossaryTerms(related.glossary ?? []);
|
|
3078
3348
|
const openTerm = (id) => onNavigate({ name: "record", id });
|
|
3349
|
+
const [editing, setEditing] = useState5(false);
|
|
3350
|
+
const [draft, setDraft] = useState5({});
|
|
3351
|
+
const [baseline, setBaseline] = useState5(null);
|
|
3352
|
+
const { save, saving, conflict, error: saveError, reset } = useUpdate(
|
|
3353
|
+
register ?? backRegister,
|
|
3354
|
+
basePath
|
|
3355
|
+
);
|
|
3356
|
+
function startEditing() {
|
|
3357
|
+
if (!record || !register) return;
|
|
3358
|
+
setBaseline(record);
|
|
3359
|
+
setDraft(draftFrom(register, record));
|
|
3360
|
+
reset();
|
|
3361
|
+
setEditing(true);
|
|
3362
|
+
}
|
|
3363
|
+
function cancelEditing() {
|
|
3364
|
+
setEditing(false);
|
|
3365
|
+
reset();
|
|
3366
|
+
}
|
|
3367
|
+
async function onSaveEdit() {
|
|
3368
|
+
if (!record || !register || !baseline) return;
|
|
3369
|
+
if (Object.keys(draftErrors(register, draft)).length > 0) return;
|
|
3370
|
+
const patch = buildPatch(register, baseline, draft);
|
|
3371
|
+
patch.version = record.version;
|
|
3372
|
+
if (Object.keys(patch).length <= 1) {
|
|
3373
|
+
setEditing(false);
|
|
3374
|
+
return;
|
|
3375
|
+
}
|
|
3376
|
+
const result = await save(record.id, patch);
|
|
3377
|
+
if (result.ok) {
|
|
3378
|
+
setEditing(false);
|
|
3379
|
+
refreshAll();
|
|
3380
|
+
}
|
|
3381
|
+
}
|
|
3382
|
+
function reloadLatest() {
|
|
3383
|
+
reset();
|
|
3384
|
+
refreshAll();
|
|
3385
|
+
}
|
|
3386
|
+
const setField = (key, value) => setDraft((d) => ({ ...d, [key]: value }));
|
|
3387
|
+
const editErrors = editing && register ? draftErrors(register, draft) : {};
|
|
3388
|
+
const edit = {
|
|
3389
|
+
editing,
|
|
3390
|
+
draft,
|
|
3391
|
+
errors: editErrors,
|
|
3392
|
+
saving,
|
|
3393
|
+
conflict,
|
|
3394
|
+
saveError,
|
|
3395
|
+
onEdit: startEditing,
|
|
3396
|
+
onCancel: cancelEditing,
|
|
3397
|
+
onSave: onSaveEdit,
|
|
3398
|
+
onReload: reloadLatest,
|
|
3399
|
+
onField: setField
|
|
3400
|
+
};
|
|
3079
3401
|
return /* @__PURE__ */ jsxs9("div", { children: [
|
|
3080
3402
|
/* @__PURE__ */ jsxs9("nav", { className: "vos-crumbs", "aria-label": "Breadcrumb", children: [
|
|
3081
3403
|
/* @__PURE__ */ jsx9(
|
|
@@ -3108,7 +3430,8 @@ function RecordPage({
|
|
|
3108
3430
|
basePath,
|
|
3109
3431
|
journey,
|
|
3110
3432
|
onJourneyChanged: refreshAll,
|
|
3111
|
-
onNavigate
|
|
3433
|
+
onNavigate,
|
|
3434
|
+
edit
|
|
3112
3435
|
}
|
|
3113
3436
|
)
|
|
3114
3437
|
] });
|
|
@@ -3126,11 +3449,13 @@ function RecordBody({
|
|
|
3126
3449
|
basePath,
|
|
3127
3450
|
journey,
|
|
3128
3451
|
onJourneyChanged,
|
|
3129
|
-
onNavigate
|
|
3452
|
+
onNavigate,
|
|
3453
|
+
edit
|
|
3130
3454
|
}) {
|
|
3131
3455
|
const page = buildRecordPage(register, record, related, { asOf });
|
|
3132
3456
|
const activeTab = page.tabs.includes(tab) ? tab : "overview";
|
|
3133
3457
|
const description = typeof record.Description === "string" ? record.Description : "";
|
|
3458
|
+
const hasErrors = Object.keys(edit.errors).length > 0;
|
|
3134
3459
|
return /* @__PURE__ */ jsxs9(Fragment8, { children: [
|
|
3135
3460
|
/* @__PURE__ */ jsxs9("div", { className: "vos-head vos-record-head", children: [
|
|
3136
3461
|
/* @__PURE__ */ jsxs9("div", { children: [
|
|
@@ -3142,7 +3467,16 @@ function RecordBody({
|
|
|
3142
3467
|
/* @__PURE__ */ jsxs9("span", { className: "vos-verbadge", children: [
|
|
3143
3468
|
"v",
|
|
3144
3469
|
formatValue(record.version)
|
|
3145
|
-
] })
|
|
3470
|
+
] }),
|
|
3471
|
+
!edit.editing ? /* @__PURE__ */ jsx9(
|
|
3472
|
+
"button",
|
|
3473
|
+
{
|
|
3474
|
+
type: "button",
|
|
3475
|
+
onClick: edit.onEdit,
|
|
3476
|
+
className: "vos-btn vos-btn-ghost vos-btn-sm",
|
|
3477
|
+
children: "Edit"
|
|
3478
|
+
}
|
|
3479
|
+
) : null
|
|
3146
3480
|
] }),
|
|
3147
3481
|
/* @__PURE__ */ jsx9("div", { className: "vos-tabs", role: "tablist", "aria-label": "Record sections", children: page.tabs.map((t2) => /* @__PURE__ */ jsx9(
|
|
3148
3482
|
"button",
|
|
@@ -3166,36 +3500,74 @@ function RecordBody({
|
|
|
3166
3500
|
},
|
|
3167
3501
|
m.key
|
|
3168
3502
|
)) }),
|
|
3169
|
-
|
|
3170
|
-
/* @__PURE__ */ jsx9("h3", { className: "vos-section-title", children: "
|
|
3171
|
-
/* @__PURE__ */ jsx9(
|
|
3172
|
-
|
|
3503
|
+
edit.editing ? /* @__PURE__ */ jsxs9("section", { className: "vos-record-editor", children: [
|
|
3504
|
+
/* @__PURE__ */ jsx9("h3", { className: "vos-section-title", children: "Edit" }),
|
|
3505
|
+
edit.conflict ? /* @__PURE__ */ jsx9(ConflictBanner, { message: edit.conflict, onReload: edit.onReload }) : null,
|
|
3506
|
+
edit.saveError ? /* @__PURE__ */ jsx9("p", { role: "alert", className: "vos-error", children: edit.saveError }) : null,
|
|
3507
|
+
/* @__PURE__ */ jsx9(
|
|
3508
|
+
EditFields,
|
|
3173
3509
|
{
|
|
3174
|
-
|
|
3175
|
-
|
|
3176
|
-
|
|
3177
|
-
|
|
3510
|
+
register,
|
|
3511
|
+
draft: edit.draft,
|
|
3512
|
+
errors: edit.errors,
|
|
3513
|
+
onField: edit.onField
|
|
3178
3514
|
}
|
|
3179
|
-
)
|
|
3180
|
-
|
|
3181
|
-
|
|
3182
|
-
|
|
3183
|
-
|
|
3184
|
-
|
|
3185
|
-
|
|
3186
|
-
|
|
3187
|
-
|
|
3515
|
+
),
|
|
3516
|
+
/* @__PURE__ */ jsxs9("footer", { className: "vos-drawer-footer", children: [
|
|
3517
|
+
/* @__PURE__ */ jsx9(
|
|
3518
|
+
"button",
|
|
3519
|
+
{
|
|
3520
|
+
type: "button",
|
|
3521
|
+
onClick: edit.onCancel,
|
|
3522
|
+
disabled: edit.saving,
|
|
3523
|
+
className: "vos-btn vos-btn-ghost vos-btn-sm",
|
|
3524
|
+
children: "Cancel"
|
|
3525
|
+
}
|
|
3526
|
+
),
|
|
3527
|
+
/* @__PURE__ */ jsx9(
|
|
3528
|
+
"button",
|
|
3529
|
+
{
|
|
3530
|
+
type: "button",
|
|
3531
|
+
onClick: edit.onSave,
|
|
3532
|
+
disabled: edit.saving || hasErrors,
|
|
3533
|
+
title: hasErrors ? "Fix the highlighted field before saving" : void 0,
|
|
3534
|
+
className: "vos-btn vos-btn-sm",
|
|
3535
|
+
children: edit.saving ? "Saving\u2026" : "Save"
|
|
3536
|
+
}
|
|
3537
|
+
)
|
|
3538
|
+
] })
|
|
3539
|
+
] }) : /* @__PURE__ */ jsxs9(Fragment8, { children: [
|
|
3540
|
+
description ? /* @__PURE__ */ jsxs9("section", { className: "vos-record-prose", children: [
|
|
3541
|
+
/* @__PURE__ */ jsx9("h3", { className: "vos-section-title", children: "Description" }),
|
|
3188
3542
|
/* @__PURE__ */ jsx9("p", { children: /* @__PURE__ */ jsx9(
|
|
3189
3543
|
GlossaryText,
|
|
3190
3544
|
{
|
|
3191
|
-
text:
|
|
3545
|
+
text: description,
|
|
3192
3546
|
terms,
|
|
3193
3547
|
selfId: register === "glossary" ? record.id : void 0,
|
|
3194
3548
|
onOpenTerm
|
|
3195
3549
|
}
|
|
3196
3550
|
) })
|
|
3197
|
-
] },
|
|
3198
|
-
|
|
3551
|
+
] }) : null,
|
|
3552
|
+
page.humanText.length ? /* @__PURE__ */ jsxs9("section", { className: "vos-record-prose", children: [
|
|
3553
|
+
/* @__PURE__ */ jsxs9("h3", { className: "vos-section-title", children: [
|
|
3554
|
+
"From a human ",
|
|
3555
|
+
/* @__PURE__ */ jsx9("span", { className: "vos-hint", children: "\u2014 not computed" })
|
|
3556
|
+
] }),
|
|
3557
|
+
page.humanText.map((h) => /* @__PURE__ */ jsxs9("div", { className: "vos-human-field", children: [
|
|
3558
|
+
/* @__PURE__ */ jsx9("div", { className: "vos-detail-k", children: h.label }),
|
|
3559
|
+
/* @__PURE__ */ jsx9("p", { children: /* @__PURE__ */ jsx9(
|
|
3560
|
+
GlossaryText,
|
|
3561
|
+
{
|
|
3562
|
+
text: h.text,
|
|
3563
|
+
terms,
|
|
3564
|
+
selfId: register === "glossary" ? record.id : void 0,
|
|
3565
|
+
onOpenTerm
|
|
3566
|
+
}
|
|
3567
|
+
) })
|
|
3568
|
+
] }, h.key))
|
|
3569
|
+
] }) : null
|
|
3570
|
+
] })
|
|
3199
3571
|
] }) : null,
|
|
3200
3572
|
activeTab === "evidence" ? /* @__PURE__ */ jsx9(
|
|
3201
3573
|
EvidenceTab,
|
|
@@ -3244,6 +3616,15 @@ function RecordBody({
|
|
|
3244
3616
|
function PillView({ pill }) {
|
|
3245
3617
|
return /* @__PURE__ */ jsx9("span", { className: PILL_CLASS3[pill.tone], children: pill.label });
|
|
3246
3618
|
}
|
|
3619
|
+
function ConflictBanner({
|
|
3620
|
+
message,
|
|
3621
|
+
onReload
|
|
3622
|
+
}) {
|
|
3623
|
+
return /* @__PURE__ */ jsxs9("div", { role: "alert", className: "vos-banner vos-banner-warn", children: [
|
|
3624
|
+
/* @__PURE__ */ jsx9("div", { className: "vos-banner-body", children: /* @__PURE__ */ jsx9("span", { children: message }) }),
|
|
3625
|
+
/* @__PURE__ */ jsx9("button", { type: "button", onClick: onReload, children: "Review the latest" })
|
|
3626
|
+
] });
|
|
3627
|
+
}
|
|
3247
3628
|
function MeterView({
|
|
3248
3629
|
meter,
|
|
3249
3630
|
assumption,
|
|
@@ -3333,14 +3714,26 @@ function EvidenceTab({
|
|
|
3333
3714
|
if (register === "assumptions") {
|
|
3334
3715
|
return /* @__PURE__ */ jsx9("section", { className: "vos-why-panel", children: /* @__PURE__ */ jsx9(UnderstandingPanel, { assumption: record, basePath }) });
|
|
3335
3716
|
}
|
|
3336
|
-
const bars =
|
|
3717
|
+
const bars = resolveBarLines(
|
|
3718
|
+
record.barLines ?? [],
|
|
3719
|
+
related
|
|
3720
|
+
);
|
|
3337
3721
|
const mine = (related.readings ?? []).filter((r) => r.experimentId === record.id);
|
|
3338
3722
|
const nested = nestReadingsByPlan(mine, [record]);
|
|
3339
3723
|
return /* @__PURE__ */ jsxs9("div", { className: "vos-record-cols", children: [
|
|
3340
3724
|
/* @__PURE__ */ jsxs9("section", { children: [
|
|
3341
3725
|
/* @__PURE__ */ jsx9("h3", { className: "vos-section-title", children: "Bar lines" }),
|
|
3342
3726
|
bars.length === 0 ? /* @__PURE__ */ jsx9("p", { className: "vos-hint", children: "No pre-registered bars." }) : /* @__PURE__ */ jsx9("ul", { className: "vos-bars", children: bars.map((b, i) => /* @__PURE__ */ jsxs9("li", { className: "vos-bar-line", children: [
|
|
3343
|
-
/* @__PURE__ */ jsx9("span", { className: "vos-bar-if", children: b.rightIf
|
|
3727
|
+
/* @__PURE__ */ jsx9("span", { className: "vos-bar-if", children: b.rightIf || "\u2014" }),
|
|
3728
|
+
b.assumption ? /* @__PURE__ */ jsx9(
|
|
3729
|
+
"button",
|
|
3730
|
+
{
|
|
3731
|
+
type: "button",
|
|
3732
|
+
className: "vos-inline-link",
|
|
3733
|
+
onClick: () => onOpenRecord(b.assumption.id),
|
|
3734
|
+
children: b.assumption.title
|
|
3735
|
+
}
|
|
3736
|
+
) : null,
|
|
3344
3737
|
/* @__PURE__ */ jsx9(
|
|
3345
3738
|
"span",
|
|
3346
3739
|
{
|
|
@@ -3444,7 +3837,6 @@ function Cell({
|
|
|
3444
3837
|
// src/record-drawer.tsx
|
|
3445
3838
|
import { useEffect as useEffect3, useState as useState6 } from "react";
|
|
3446
3839
|
import { Fragment as Fragment9, jsx as jsx11, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
3447
|
-
var META_FIELDS = /* @__PURE__ */ new Set(["id", "version", "createdAt", "updatedAt", "derived"]);
|
|
3448
3840
|
var DERIVED_SUB = {
|
|
3449
3841
|
confidence: "Signed average of concluded readings",
|
|
3450
3842
|
risk: "Impact \xD7 (1 \u2212 Confidence\u207A/100)",
|
|
@@ -3463,6 +3855,8 @@ function RecordDrawer({
|
|
|
3463
3855
|
basePath,
|
|
3464
3856
|
onChanged,
|
|
3465
3857
|
onOpenFull,
|
|
3858
|
+
onOpenRecord,
|
|
3859
|
+
related,
|
|
3466
3860
|
children
|
|
3467
3861
|
}) {
|
|
3468
3862
|
const [editing, setEditing] = useState6(false);
|
|
@@ -3481,7 +3875,7 @@ function RecordDrawer({
|
|
|
3481
3875
|
reset();
|
|
3482
3876
|
}, [recordId, reset]);
|
|
3483
3877
|
const derived = record && record.derived && typeof record.derived === "object" ? record.derived : null;
|
|
3484
|
-
const
|
|
3878
|
+
const rows = record ? detailRows(register, record, related ?? {}) : [];
|
|
3485
3879
|
function startEditing() {
|
|
3486
3880
|
if (!record) return;
|
|
3487
3881
|
setBaseline(record);
|
|
@@ -3495,6 +3889,7 @@ function RecordDrawer({
|
|
|
3495
3889
|
}
|
|
3496
3890
|
async function onSave() {
|
|
3497
3891
|
if (!record || !baseline) return;
|
|
3892
|
+
if (Object.keys(draftErrors(register, draft)).length > 0) return;
|
|
3498
3893
|
const patch = buildPatch(register, baseline, draft);
|
|
3499
3894
|
patch.version = record.version;
|
|
3500
3895
|
if (Object.keys(patch).length <= 1) {
|
|
@@ -3512,6 +3907,8 @@ function RecordDrawer({
|
|
|
3512
3907
|
onChanged?.();
|
|
3513
3908
|
}
|
|
3514
3909
|
const setField = (key, value) => setDraft((d) => ({ ...d, [key]: value }));
|
|
3910
|
+
const errors = editing ? draftErrors(register, draft) : {};
|
|
3911
|
+
const hasErrors = Object.keys(errors).length > 0;
|
|
3515
3912
|
return /* @__PURE__ */ jsxs11(
|
|
3516
3913
|
DrawerShell,
|
|
3517
3914
|
{
|
|
@@ -3578,19 +3975,24 @@ function RecordDrawer({
|
|
|
3578
3975
|
] }),
|
|
3579
3976
|
"confidence" in derived && why ? /* @__PURE__ */ jsx11("div", { className: "vos-why-panel", children: /* @__PURE__ */ jsx11(UnderstandingPanel, { assumption: record, basePath }) }) : null
|
|
3580
3977
|
] }) : null,
|
|
3581
|
-
conflict ? /* @__PURE__ */ jsx11(
|
|
3978
|
+
conflict ? /* @__PURE__ */ jsx11(ConflictBanner2, { message: conflict, onReload: reloadLatest }) : null,
|
|
3582
3979
|
saveError ? /* @__PURE__ */ jsx11("p", { role: "alert", className: "vos-banner vos-banner-crit", children: saveError }) : null,
|
|
3583
3980
|
editing ? /* @__PURE__ */ jsx11(
|
|
3584
3981
|
EditFields,
|
|
3585
3982
|
{
|
|
3586
3983
|
register,
|
|
3587
3984
|
draft,
|
|
3985
|
+
errors,
|
|
3588
3986
|
onField: setField
|
|
3589
3987
|
}
|
|
3590
|
-
) : /* @__PURE__ */ jsx11("div", { className: "vos-detail-list", children:
|
|
3591
|
-
|
|
3592
|
-
|
|
3593
|
-
|
|
3988
|
+
) : /* @__PURE__ */ jsx11("div", { className: "vos-detail-list", children: rows.map((row) => /* @__PURE__ */ jsx11(
|
|
3989
|
+
DetailRowView,
|
|
3990
|
+
{
|
|
3991
|
+
row,
|
|
3992
|
+
onOpenRecord
|
|
3993
|
+
},
|
|
3994
|
+
row.key
|
|
3995
|
+
)) })
|
|
3594
3996
|
] }) }),
|
|
3595
3997
|
record && !loading && !error && !editing ? children : null,
|
|
3596
3998
|
record && editing ? /* @__PURE__ */ jsxs11("footer", { className: "vos-drawer-footer", children: [
|
|
@@ -3609,7 +4011,8 @@ function RecordDrawer({
|
|
|
3609
4011
|
{
|
|
3610
4012
|
type: "button",
|
|
3611
4013
|
onClick: onSave,
|
|
3612
|
-
disabled: saving,
|
|
4014
|
+
disabled: saving || hasErrors,
|
|
4015
|
+
title: hasErrors ? "Fix the highlighted field before saving" : void 0,
|
|
3613
4016
|
className: "vos-btn vos-btn-sm",
|
|
3614
4017
|
children: saving ? "Saving\u2026" : "Save"
|
|
3615
4018
|
}
|
|
@@ -3623,6 +4026,56 @@ function RecordDrawer({
|
|
|
3623
4026
|
}
|
|
3624
4027
|
);
|
|
3625
4028
|
}
|
|
4029
|
+
function DetailRowView({
|
|
4030
|
+
row,
|
|
4031
|
+
onOpenRecord
|
|
4032
|
+
}) {
|
|
4033
|
+
return /* @__PURE__ */ jsxs11("div", { className: "vos-detail-row", children: [
|
|
4034
|
+
/* @__PURE__ */ jsx11("span", { className: "vos-detail-k", children: row.label }),
|
|
4035
|
+
/* @__PURE__ */ jsx11("span", { className: "vos-detail-v", children: row.kind === "relation" ? row.items && row.items.length ? /* @__PURE__ */ jsx11(RelationLinks, { items: row.items, onOpenRecord }) : "\u2014" : row.kind === "owner" ? row.names && row.names.length ? row.names.join(", ") : "\u2014" : row.kind === "bar-lines" ? row.bars && row.bars.length ? /* @__PURE__ */ jsx11("ul", { className: "vos-bars", children: row.bars.map((b, i) => /* @__PURE__ */ jsxs11("li", { className: "vos-bar-line", children: [
|
|
4036
|
+
/* @__PURE__ */ jsx11("span", { className: "vos-bar-if", children: b.rightIf || "\u2014" }),
|
|
4037
|
+
b.assumption ? /* @__PURE__ */ jsx11(
|
|
4038
|
+
InlineLink,
|
|
4039
|
+
{
|
|
4040
|
+
id: b.assumption.id,
|
|
4041
|
+
title: b.assumption.title,
|
|
4042
|
+
onOpenRecord
|
|
4043
|
+
}
|
|
4044
|
+
) : null,
|
|
4045
|
+
/* @__PURE__ */ jsx11(
|
|
4046
|
+
"span",
|
|
4047
|
+
{
|
|
4048
|
+
className: b.barVerdict ? "vos-pill vos-pill-good" : "vos-pill vos-pill-neutral",
|
|
4049
|
+
children: b.barVerdict ?? "open"
|
|
4050
|
+
}
|
|
4051
|
+
)
|
|
4052
|
+
] }, i)) }) : "\u2014" : row.text })
|
|
4053
|
+
] });
|
|
4054
|
+
}
|
|
4055
|
+
function RelationLinks({
|
|
4056
|
+
items,
|
|
4057
|
+
onOpenRecord
|
|
4058
|
+
}) {
|
|
4059
|
+
return /* @__PURE__ */ jsx11("span", { className: "vos-detail-links", children: items.map((item, i) => /* @__PURE__ */ jsxs11("span", { children: [
|
|
4060
|
+
i > 0 ? ", " : null,
|
|
4061
|
+
/* @__PURE__ */ jsx11(InlineLink, { id: item.id, title: item.title, onOpenRecord })
|
|
4062
|
+
] }, item.id)) });
|
|
4063
|
+
}
|
|
4064
|
+
function InlineLink({
|
|
4065
|
+
id,
|
|
4066
|
+
title,
|
|
4067
|
+
onOpenRecord
|
|
4068
|
+
}) {
|
|
4069
|
+
return onOpenRecord ? /* @__PURE__ */ jsx11(
|
|
4070
|
+
"button",
|
|
4071
|
+
{
|
|
4072
|
+
type: "button",
|
|
4073
|
+
className: "vos-inline-link",
|
|
4074
|
+
onClick: () => onOpenRecord(id),
|
|
4075
|
+
children: title
|
|
4076
|
+
}
|
|
4077
|
+
) : /* @__PURE__ */ jsx11("span", { children: title });
|
|
4078
|
+
}
|
|
3626
4079
|
function DerivedCell({
|
|
3627
4080
|
field,
|
|
3628
4081
|
value,
|
|
@@ -3658,7 +4111,7 @@ function DerivedCell({
|
|
|
3658
4111
|
DERIVED_SUB[field] ? /* @__PURE__ */ jsx11("div", { className: "vos-dcell-sub", children: DERIVED_SUB[field] }) : null
|
|
3659
4112
|
] });
|
|
3660
4113
|
}
|
|
3661
|
-
function
|
|
4114
|
+
function ConflictBanner2({
|
|
3662
4115
|
message,
|
|
3663
4116
|
onReload
|
|
3664
4117
|
}) {
|
|
@@ -4045,7 +4498,7 @@ function contextNeeds(register) {
|
|
|
4045
4498
|
return {
|
|
4046
4499
|
experiments: register === "assumptions" || register === "readings",
|
|
4047
4500
|
readings: register === "assumptions",
|
|
4048
|
-
assumptions: register === "decisions"
|
|
4501
|
+
assumptions: register === "decisions" || register === "experiments" || register === "readings"
|
|
4049
4502
|
};
|
|
4050
4503
|
}
|
|
4051
4504
|
function RegisterBrowser({
|
|
@@ -4098,6 +4551,12 @@ function RegisterBrowser({
|
|
|
4098
4551
|
const n = humanCount[tab.id] ?? 0;
|
|
4099
4552
|
return n > 0 ? n : null;
|
|
4100
4553
|
};
|
|
4554
|
+
const related = {
|
|
4555
|
+
assumptions: ctx.assumptions,
|
|
4556
|
+
experiments: ctx.experiments,
|
|
4557
|
+
readings: ctx.readings,
|
|
4558
|
+
decisions: ctx.decisions
|
|
4559
|
+
};
|
|
4101
4560
|
const patch = (p) => setDescriptor((d) => ({ ...d, ...p }));
|
|
4102
4561
|
const saveCurrentView = () => {
|
|
4103
4562
|
if (typeof window === "undefined") return;
|
|
@@ -4225,6 +4684,8 @@ function RegisterBrowser({
|
|
|
4225
4684
|
onClose: () => setOpenId(null),
|
|
4226
4685
|
basePath,
|
|
4227
4686
|
onOpenFull: onOpenRecord && openId ? () => onOpenRecord(openId) : void 0,
|
|
4687
|
+
onOpenRecord,
|
|
4688
|
+
related,
|
|
4228
4689
|
onChanged: () => {
|
|
4229
4690
|
refreshRecord();
|
|
4230
4691
|
refreshList();
|
|
@@ -4919,24 +5380,124 @@ function ValidationOSDashboard({ config = {} }) {
|
|
|
4919
5380
|
] });
|
|
4920
5381
|
}
|
|
4921
5382
|
|
|
4922
|
-
// src/
|
|
5383
|
+
// src/connect.ts
|
|
5384
|
+
var DEFAULT_TOKEN_ENV = "VALIDATION_OS_TOKEN";
|
|
5385
|
+
var SHELL_UNSAFE = /['"\\\s]/;
|
|
5386
|
+
function composeConnectCommand(input) {
|
|
5387
|
+
const tokenEnv = input.tokenEnv ?? DEFAULT_TOKEN_ENV;
|
|
5388
|
+
const guarded = [
|
|
5389
|
+
["Token", input.token],
|
|
5390
|
+
["API base URL", input.apiBaseUrl]
|
|
5391
|
+
];
|
|
5392
|
+
for (const [label, value] of guarded) {
|
|
5393
|
+
if (SHELL_UNSAFE.test(value)) {
|
|
5394
|
+
throw new Error(`${label} contains characters that can't be safely pasted.`);
|
|
5395
|
+
}
|
|
5396
|
+
}
|
|
5397
|
+
return [
|
|
5398
|
+
`export ${tokenEnv}='${input.token}'`,
|
|
5399
|
+
`cat > validation-os.config.yaml <<'EOF'`,
|
|
5400
|
+
`connector: remote-api`,
|
|
5401
|
+
`remote_api:`,
|
|
5402
|
+
` api_base_url: ${input.apiBaseUrl}`,
|
|
5403
|
+
` token_env: ${tokenEnv}`,
|
|
5404
|
+
`EOF`
|
|
5405
|
+
].join("\n");
|
|
5406
|
+
}
|
|
5407
|
+
|
|
5408
|
+
// src/connect-claude-code.tsx
|
|
5409
|
+
import { useState as useState14 } from "react";
|
|
4923
5410
|
import { jsx as jsx18, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
5411
|
+
function ConnectClaudeCode({
|
|
5412
|
+
apiBaseUrl,
|
|
5413
|
+
tokenEnv,
|
|
5414
|
+
mintToken
|
|
5415
|
+
}) {
|
|
5416
|
+
const [state, setState] = useState14({ phase: "idle" });
|
|
5417
|
+
const [copied, setCopied] = useState14(false);
|
|
5418
|
+
async function generate() {
|
|
5419
|
+
setState({ phase: "minting" });
|
|
5420
|
+
setCopied(false);
|
|
5421
|
+
try {
|
|
5422
|
+
const token = await mintToken();
|
|
5423
|
+
const command = composeConnectCommand({ token, apiBaseUrl, tokenEnv });
|
|
5424
|
+
setState({ phase: "ready", command });
|
|
5425
|
+
} catch (e) {
|
|
5426
|
+
setState({
|
|
5427
|
+
phase: "error",
|
|
5428
|
+
message: e instanceof Error ? e.message : "Couldn't generate your connection command."
|
|
5429
|
+
});
|
|
5430
|
+
}
|
|
5431
|
+
}
|
|
5432
|
+
async function copy(command) {
|
|
5433
|
+
try {
|
|
5434
|
+
await navigator.clipboard.writeText(command);
|
|
5435
|
+
setCopied(true);
|
|
5436
|
+
} catch {
|
|
5437
|
+
}
|
|
5438
|
+
}
|
|
5439
|
+
return /* @__PURE__ */ jsxs18("div", { children: [
|
|
5440
|
+
/* @__PURE__ */ jsx18("div", { className: "vos-head", children: /* @__PURE__ */ jsxs18("div", { children: [
|
|
5441
|
+
/* @__PURE__ */ jsx18("h1", { children: "Connect Claude Code" }),
|
|
5442
|
+
/* @__PURE__ */ jsx18("p", { children: "Run the validation skills against this register from your own Claude Code \u2014 no repo, no keys to hunt down." })
|
|
5443
|
+
] }) }),
|
|
5444
|
+
/* @__PURE__ */ jsxs18("ol", { className: "vos-hint", style: { lineHeight: 1.8 }, children: [
|
|
5445
|
+
/* @__PURE__ */ jsx18("li", { children: "Generate your personal connection command below." }),
|
|
5446
|
+
/* @__PURE__ */ jsx18("li", { children: "Paste it into a terminal in the workspace you'll run the skills in." }),
|
|
5447
|
+
/* @__PURE__ */ jsxs18("li", { children: [
|
|
5448
|
+
"The command carries a token tied to ",
|
|
5449
|
+
/* @__PURE__ */ jsx18("strong", { children: "you" }),
|
|
5450
|
+
" \u2014 anything you write lands under your name. Don't share it."
|
|
5451
|
+
] })
|
|
5452
|
+
] }),
|
|
5453
|
+
state.phase !== "ready" ? /* @__PURE__ */ jsx18(
|
|
5454
|
+
"button",
|
|
5455
|
+
{
|
|
5456
|
+
type: "button",
|
|
5457
|
+
className: "vos-btn",
|
|
5458
|
+
onClick: generate,
|
|
5459
|
+
disabled: state.phase === "minting",
|
|
5460
|
+
children: state.phase === "minting" ? "Generating\u2026" : "Generate connection command"
|
|
5461
|
+
}
|
|
5462
|
+
) : null,
|
|
5463
|
+
state.phase === "error" ? /* @__PURE__ */ jsx18("p", { className: "vos-hint", role: "alert", children: state.message }) : null,
|
|
5464
|
+
state.phase === "ready" ? /* @__PURE__ */ jsxs18("div", { children: [
|
|
5465
|
+
/* @__PURE__ */ jsx18("pre", { className: "vos-code", "aria-label": "Connection command", children: state.command }),
|
|
5466
|
+
/* @__PURE__ */ jsxs18("div", { style: { display: "flex", gap: 8 }, children: [
|
|
5467
|
+
/* @__PURE__ */ jsx18(
|
|
5468
|
+
"button",
|
|
5469
|
+
{
|
|
5470
|
+
type: "button",
|
|
5471
|
+
className: "vos-btn",
|
|
5472
|
+
onClick: () => copy(state.command),
|
|
5473
|
+
children: copied ? "Copied" : "Copy command"
|
|
5474
|
+
}
|
|
5475
|
+
),
|
|
5476
|
+
/* @__PURE__ */ jsx18("button", { type: "button", className: "vos-btn-ghost", onClick: generate, children: "Regenerate" })
|
|
5477
|
+
] }),
|
|
5478
|
+
/* @__PURE__ */ jsx18("p", { className: "vos-hint", style: { marginTop: 12 }, children: "Generating again revokes nothing on its own \u2014 remove old keys from your account settings when you rotate." })
|
|
5479
|
+
] }) : null
|
|
5480
|
+
] });
|
|
5481
|
+
}
|
|
5482
|
+
|
|
5483
|
+
// src/surface-placeholder.tsx
|
|
5484
|
+
import { jsx as jsx19, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
4924
5485
|
function SurfacePlaceholder({
|
|
4925
5486
|
title,
|
|
4926
5487
|
subtitle,
|
|
4927
5488
|
detail
|
|
4928
5489
|
}) {
|
|
4929
|
-
return /* @__PURE__ */
|
|
4930
|
-
/* @__PURE__ */
|
|
4931
|
-
/* @__PURE__ */
|
|
4932
|
-
/* @__PURE__ */
|
|
5490
|
+
return /* @__PURE__ */ jsxs19("div", { children: [
|
|
5491
|
+
/* @__PURE__ */ jsx19("div", { className: "vos-head", children: /* @__PURE__ */ jsxs19("div", { children: [
|
|
5492
|
+
/* @__PURE__ */ jsx19("h1", { children: title }),
|
|
5493
|
+
/* @__PURE__ */ jsx19("p", { children: subtitle })
|
|
4933
5494
|
] }) }),
|
|
4934
|
-
/* @__PURE__ */
|
|
5495
|
+
/* @__PURE__ */ jsx19("div", { className: "vos-empty", children: detail })
|
|
4935
5496
|
] });
|
|
4936
5497
|
}
|
|
4937
5498
|
|
|
4938
5499
|
// src/register-counts.tsx
|
|
4939
|
-
import { jsx as
|
|
5500
|
+
import { jsx as jsx20, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
4940
5501
|
function RegisterCounts({
|
|
4941
5502
|
counts,
|
|
4942
5503
|
caption,
|
|
@@ -4946,8 +5507,8 @@ function RegisterCounts({
|
|
|
4946
5507
|
const registers = REGISTER_ORDER.filter(
|
|
4947
5508
|
(r) => counts[r] !== void 0
|
|
4948
5509
|
);
|
|
4949
|
-
return /* @__PURE__ */
|
|
4950
|
-
/* @__PURE__ */
|
|
5510
|
+
return /* @__PURE__ */ jsxs20("section", { "aria-label": "Register counts", children: [
|
|
5511
|
+
/* @__PURE__ */ jsx20("div", { className: "vos-tile-grid", children: registers.map((register) => /* @__PURE__ */ jsx20(
|
|
4951
5512
|
StatTile,
|
|
4952
5513
|
{
|
|
4953
5514
|
label: REGISTER_LABEL[register],
|
|
@@ -4957,13 +5518,16 @@ function RegisterCounts({
|
|
|
4957
5518
|
},
|
|
4958
5519
|
register
|
|
4959
5520
|
)) }),
|
|
4960
|
-
caption ? /* @__PURE__ */
|
|
5521
|
+
caption ? /* @__PURE__ */ jsx20("p", { className: "vos-hint", style: { marginTop: 16 }, children: caption }) : null
|
|
4961
5522
|
] });
|
|
4962
5523
|
}
|
|
4963
5524
|
export {
|
|
4964
5525
|
BeliefJourney,
|
|
4965
5526
|
CONFLICT_MESSAGE,
|
|
4966
5527
|
ConfidenceCell,
|
|
5528
|
+
ConnectClaudeCode,
|
|
5529
|
+
DEFAULT_TOKEN_ENV,
|
|
5530
|
+
DIRECT_CYCLE_KEY,
|
|
4967
5531
|
EditBeliefForm,
|
|
4968
5532
|
EditFields,
|
|
4969
5533
|
FIRST_RUN_LINE,
|
|
@@ -4997,6 +5561,7 @@ export {
|
|
|
4997
5561
|
ValidationOSDashboard,
|
|
4998
5562
|
WriteDecisionForm,
|
|
4999
5563
|
backlinkPanels,
|
|
5564
|
+
buildCycles,
|
|
5000
5565
|
buildJourney,
|
|
5001
5566
|
buildPatch,
|
|
5002
5567
|
buildPipeline,
|
|
@@ -5005,9 +5570,11 @@ export {
|
|
|
5005
5570
|
cellValue,
|
|
5006
5571
|
coldStartFor,
|
|
5007
5572
|
columnsFor,
|
|
5573
|
+
composeConnectCommand,
|
|
5008
5574
|
confidenceTone,
|
|
5009
5575
|
configureRiskBands,
|
|
5010
5576
|
defaultTabId,
|
|
5577
|
+
detailRows,
|
|
5011
5578
|
dontConfuseWith,
|
|
5012
5579
|
draftFrom,
|
|
5013
5580
|
editableFields,
|
|
@@ -5034,8 +5601,10 @@ export {
|
|
|
5034
5601
|
movePresentation,
|
|
5035
5602
|
needsHumanCounts,
|
|
5036
5603
|
nestReadingsByPlan,
|
|
5604
|
+
ownerNames,
|
|
5037
5605
|
parseRoute,
|
|
5038
5606
|
primaryLabel,
|
|
5607
|
+
resolveBarLines,
|
|
5039
5608
|
riskBand,
|
|
5040
5609
|
riskFraction,
|
|
5041
5610
|
riskLevel,
|