@validation-os/dashboard 0.7.1 → 0.9.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 +366 -111
- package/dist/index.js +1462 -604
- package/dist/index.js.map +1 -1
- package/dist/styles.css +237 -0
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -56,7 +56,55 @@ var WORKFLOW_NAV = [
|
|
|
56
56
|
import {
|
|
57
57
|
isConcluded
|
|
58
58
|
} from "@validation-os/core/derivation";
|
|
59
|
-
|
|
59
|
+
|
|
60
|
+
// src/derived-views.ts
|
|
61
|
+
var KILL_ZONE = -50;
|
|
62
|
+
function readingBeliefs(r) {
|
|
63
|
+
return Array.isArray(r.beliefs) ? r.beliefs : [];
|
|
64
|
+
}
|
|
65
|
+
function readingBeliefFor(r, assumptionId) {
|
|
66
|
+
return readingBeliefs(r).find((b) => b.assumptionId === assumptionId);
|
|
67
|
+
}
|
|
68
|
+
function readingGrades(r, assumptionId) {
|
|
69
|
+
return readingBeliefFor(r, assumptionId) !== void 0;
|
|
70
|
+
}
|
|
71
|
+
function isArchivedExperiment(e) {
|
|
72
|
+
return str(e.Status) === "Archived";
|
|
73
|
+
}
|
|
74
|
+
function liveExperiments(experiments) {
|
|
75
|
+
return experiments.filter((e) => !isArchivedExperiment(e));
|
|
76
|
+
}
|
|
77
|
+
function str(v) {
|
|
78
|
+
return typeof v === "string" && v !== "" ? v : null;
|
|
79
|
+
}
|
|
80
|
+
function derivedNum(r, key) {
|
|
81
|
+
const v = r.derived?.[key];
|
|
82
|
+
return typeof v === "number" ? v : null;
|
|
83
|
+
}
|
|
84
|
+
function strList(v) {
|
|
85
|
+
return Array.isArray(v) ? v.filter((x) => typeof x === "string") : [];
|
|
86
|
+
}
|
|
87
|
+
function testsAssumption(exp, assumptionId) {
|
|
88
|
+
const bars = exp.barLines;
|
|
89
|
+
if (bars?.some((b) => b.assumptionId === assumptionId)) return true;
|
|
90
|
+
return strList(exp.barLineAssumptionIds).includes(assumptionId);
|
|
91
|
+
}
|
|
92
|
+
function hasOpenBarOn(exp, assumptionId) {
|
|
93
|
+
const bars = exp.barLines;
|
|
94
|
+
return bars?.some((b) => b.assumptionId === assumptionId && b.barVerdict == null) ?? false;
|
|
95
|
+
}
|
|
96
|
+
function inKillLane(a) {
|
|
97
|
+
return str(a.Status) === "Live" && (derivedNum(a, "confidence") ?? 0) <= KILL_ZONE;
|
|
98
|
+
}
|
|
99
|
+
function isTesting(a, experiments) {
|
|
100
|
+
if (str(a.Status) !== "Live") return false;
|
|
101
|
+
return experiments.some(
|
|
102
|
+
(e) => str(e.Status) === "Running" && hasOpenBarOn(e, a.id)
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// src/next-move.ts
|
|
107
|
+
function str2(record, key) {
|
|
60
108
|
const v = record[key];
|
|
61
109
|
return typeof v === "string" ? v : null;
|
|
62
110
|
}
|
|
@@ -71,13 +119,11 @@ function idList(record, key) {
|
|
|
71
119
|
function toNextMoveInput(records) {
|
|
72
120
|
const concludedByAssumption = /* @__PURE__ */ new Map();
|
|
73
121
|
for (const r of records.readings) {
|
|
74
|
-
const
|
|
75
|
-
|
|
76
|
-
const result = str(r, "Result");
|
|
77
|
-
if (result && isConcluded(result)) {
|
|
122
|
+
for (const b of readingBeliefs(r)) {
|
|
123
|
+
if (!b.assumptionId || !isConcluded(b.Result)) continue;
|
|
78
124
|
concludedByAssumption.set(
|
|
79
|
-
assumptionId,
|
|
80
|
-
(concludedByAssumption.get(assumptionId) ?? 0) + 1
|
|
125
|
+
b.assumptionId,
|
|
126
|
+
(concludedByAssumption.get(b.assumptionId) ?? 0) + 1
|
|
81
127
|
);
|
|
82
128
|
}
|
|
83
129
|
}
|
|
@@ -86,8 +132,8 @@ function toNextMoveInput(records) {
|
|
|
86
132
|
const derived = a.derived && typeof a.derived === "object" ? a.derived : {};
|
|
87
133
|
return {
|
|
88
134
|
id: a.id,
|
|
89
|
-
title:
|
|
90
|
-
status:
|
|
135
|
+
title: str2(a, "Title") ?? a.id,
|
|
136
|
+
status: str2(a, "Status") ?? "",
|
|
91
137
|
impact: numOrNull(a, "Impact"),
|
|
92
138
|
moot: a.moot === true,
|
|
93
139
|
risk: typeof derived.risk === "number" ? derived.risk : 0,
|
|
@@ -96,12 +142,12 @@ function toNextMoveInput(records) {
|
|
|
96
142
|
};
|
|
97
143
|
}),
|
|
98
144
|
experiments: records.experiments.map((e) => ({
|
|
99
|
-
status:
|
|
100
|
-
feasibility:
|
|
145
|
+
status: str2(e, "Status") ?? "",
|
|
146
|
+
feasibility: str2(e, "Feasibility") ?? null,
|
|
101
147
|
assumptionIds: idList(e, "barLineAssumptionIds")
|
|
102
148
|
})),
|
|
103
149
|
decisions: records.decisions.map((d) => ({
|
|
104
|
-
status:
|
|
150
|
+
status: str2(d, "Status") ?? "",
|
|
105
151
|
assumptionIds: [...idList(d, "basedOnIds"), ...idList(d, "resolvesIds")]
|
|
106
152
|
}))
|
|
107
153
|
};
|
|
@@ -292,7 +338,7 @@ function sparklineY(value, height, lo, hi) {
|
|
|
292
338
|
// src/pipeline.ts
|
|
293
339
|
import {
|
|
294
340
|
assumptionCompleteness,
|
|
295
|
-
|
|
341
|
+
readingBeliefInputs
|
|
296
342
|
} from "@validation-os/core";
|
|
297
343
|
import {
|
|
298
344
|
beliefRisk,
|
|
@@ -306,7 +352,7 @@ function num(v) {
|
|
|
306
352
|
const n = Number(v);
|
|
307
353
|
return Number.isFinite(n) ? n : 0;
|
|
308
354
|
}
|
|
309
|
-
function
|
|
355
|
+
function str3(v) {
|
|
310
356
|
return typeof v === "string" ? v : "";
|
|
311
357
|
}
|
|
312
358
|
function derivedOf(rec) {
|
|
@@ -346,7 +392,9 @@ function nextMove(stage, killZone) {
|
|
|
346
392
|
}
|
|
347
393
|
}
|
|
348
394
|
function buildPipeline(assumptions, experiments) {
|
|
349
|
-
const tests = beliefTestMeters(
|
|
395
|
+
const tests = beliefTestMeters(
|
|
396
|
+
liveExperiments(experiments).map(toStageExperimentInput)
|
|
397
|
+
);
|
|
350
398
|
const rows = [];
|
|
351
399
|
const resolved = [];
|
|
352
400
|
const portfolioInput = [];
|
|
@@ -367,7 +415,7 @@ function buildPipeline(assumptions, experiments) {
|
|
|
367
415
|
resolvedRetired += retired;
|
|
368
416
|
resolved.push({
|
|
369
417
|
id: a.id,
|
|
370
|
-
statement:
|
|
418
|
+
statement: str3(a.Title),
|
|
371
419
|
kind,
|
|
372
420
|
retired
|
|
373
421
|
});
|
|
@@ -382,7 +430,7 @@ function buildPipeline(assumptions, experiments) {
|
|
|
382
430
|
const stage = deriveBeliefStage({ framed, confidence: d.confidence, test });
|
|
383
431
|
rows.push({
|
|
384
432
|
id: a.id,
|
|
385
|
-
statement:
|
|
433
|
+
statement: str3(a.Title),
|
|
386
434
|
impact: d.derivedImpact,
|
|
387
435
|
risk: d.risk,
|
|
388
436
|
riskTone: riskLevel(d.risk),
|
|
@@ -407,28 +455,27 @@ function buildPipeline(assumptions, experiments) {
|
|
|
407
455
|
}
|
|
408
456
|
function weekOverWeekDelta(assumptions, readings, now) {
|
|
409
457
|
const anyDated = readings.some((r) => {
|
|
410
|
-
const t2 = Date.parse(
|
|
458
|
+
const t2 = Date.parse(str3(r.Date));
|
|
411
459
|
return !Number.isNaN(t2);
|
|
412
460
|
});
|
|
413
461
|
if (!anyDated) return null;
|
|
414
462
|
const cutoff = now.getTime() - 7 * 24 * 60 * 60 * 1e3;
|
|
415
463
|
const byAssumption = /* @__PURE__ */ new Map();
|
|
416
|
-
for (const
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
else byAssumption.set(id, [r]);
|
|
464
|
+
for (const input of readings.flatMap(readingBeliefInputs)) {
|
|
465
|
+
if (!input.assumptionId) continue;
|
|
466
|
+
const arr = byAssumption.get(input.assumptionId);
|
|
467
|
+
if (arr) arr.push(input);
|
|
468
|
+
else byAssumption.set(input.assumptionId, [input]);
|
|
422
469
|
}
|
|
423
470
|
const percentAsOf = (limit) => {
|
|
424
471
|
const inputs = assumptions.map((a) => {
|
|
425
472
|
const d = derivedOf(a);
|
|
426
|
-
const mine = (byAssumption.get(a.id) ?? []).filter((
|
|
473
|
+
const mine = (byAssumption.get(a.id) ?? []).filter((i) => {
|
|
427
474
|
if (limit === null) return true;
|
|
428
|
-
const t2 = Date.parse(
|
|
475
|
+
const t2 = Date.parse(i.date ?? "");
|
|
429
476
|
return !Number.isNaN(t2) && t2 <= limit;
|
|
430
477
|
});
|
|
431
|
-
const conf = confidence(mine
|
|
478
|
+
const conf = confidence(mine);
|
|
432
479
|
return {
|
|
433
480
|
id: a.id,
|
|
434
481
|
derivedImpact: d.derivedImpact,
|
|
@@ -506,29 +553,24 @@ var area = (key, label) => ({
|
|
|
506
553
|
label,
|
|
507
554
|
kind: "textarea"
|
|
508
555
|
});
|
|
509
|
-
var num2 = (key, label) => ({
|
|
556
|
+
var num2 = (key, label, range = {}) => ({
|
|
510
557
|
key,
|
|
511
558
|
label,
|
|
512
559
|
kind: "number",
|
|
513
|
-
nullable: true
|
|
560
|
+
nullable: true,
|
|
561
|
+
...range
|
|
514
562
|
});
|
|
515
563
|
var sel = (key, label, options, nullable = false) => ({ key, label, kind: "select", options, nullable });
|
|
516
|
-
var READING_RUNGS = [
|
|
517
|
-
"Opinion",
|
|
518
|
-
"Pitch-deck reaction",
|
|
519
|
-
"Anecdotal",
|
|
520
|
-
"Desk research",
|
|
521
|
-
"Survey at scale",
|
|
522
|
-
"Prototype usage",
|
|
523
|
-
"Signed intent",
|
|
524
|
-
"Paying users"
|
|
525
|
-
];
|
|
526
564
|
var SOURCE_QUALITY = ["1", "0.7", "0.5"];
|
|
527
565
|
var EDITORS = {
|
|
528
566
|
assumptions: [
|
|
529
567
|
t("Title", "Assumption"),
|
|
530
568
|
area("Description", "Description"),
|
|
531
|
-
|
|
569
|
+
// The only hand-scored number in the registry (`registry-schema.md`) — a
|
|
570
|
+
// 0–100 severity-if-false seed. Every other number (Confidence, Derived
|
|
571
|
+
// Impact, Risk, Strength, Source quality, Completeness %) is computed on
|
|
572
|
+
// write and deliberately absent from this list.
|
|
573
|
+
num2("Impact", "Impact", { min: 0, max: 100 }),
|
|
532
574
|
sel("Status", "Status", ["Draft", "Live", "Invalidated"]),
|
|
533
575
|
t("Lens", "Lens"),
|
|
534
576
|
area("Scoring justification", "Scoring justification")
|
|
@@ -557,12 +599,14 @@ var EDITORS = {
|
|
|
557
599
|
readings: [
|
|
558
600
|
t("Title", "Reading"),
|
|
559
601
|
t("Source", "Source"),
|
|
560
|
-
|
|
561
|
-
|
|
602
|
+
// Rung / Result / Magnitude band / Grading justification are PER BELIEF now
|
|
603
|
+
// (OPS-1305) — they live in each entry of `beliefs[]`, not on the row, so
|
|
604
|
+
// they are deliberately absent here rather than writing dead row-level
|
|
605
|
+
// fields. Editing a reading's per-belief scores is a deferred follow-up (a
|
|
606
|
+
// `beliefs[]` editor); this form edits only the row-level fields that remain.
|
|
562
607
|
sel("Representativeness", "Representativeness", SOURCE_QUALITY),
|
|
563
608
|
sel("Credibility", "Credibility", SOURCE_QUALITY),
|
|
564
|
-
|
|
565
|
-
area("Grading justification", "Grading justification"),
|
|
609
|
+
area("body", "Quote"),
|
|
566
610
|
t("Date", "Date")
|
|
567
611
|
],
|
|
568
612
|
decisions: [
|
|
@@ -601,6 +645,28 @@ function coerce(field, raw) {
|
|
|
601
645
|
function norm(value) {
|
|
602
646
|
return value === void 0 || value === "" ? null : value;
|
|
603
647
|
}
|
|
648
|
+
function fieldError(field, raw) {
|
|
649
|
+
if (field.kind !== "number") return null;
|
|
650
|
+
const str5 = String(raw ?? "").trim();
|
|
651
|
+
if (str5 === "") return null;
|
|
652
|
+
const n = Number(str5);
|
|
653
|
+
if (Number.isNaN(n)) return `${field.label} must be a number.`;
|
|
654
|
+
if (field.min !== void 0 && n < field.min) {
|
|
655
|
+
return `${field.label} must be at least ${field.min}.`;
|
|
656
|
+
}
|
|
657
|
+
if (field.max !== void 0 && n > field.max) {
|
|
658
|
+
return `${field.label} must be at most ${field.max}.`;
|
|
659
|
+
}
|
|
660
|
+
return null;
|
|
661
|
+
}
|
|
662
|
+
function draftErrors(register, draft) {
|
|
663
|
+
const errors = {};
|
|
664
|
+
for (const field of editableFields(register)) {
|
|
665
|
+
const message = fieldError(field, draft[field.key] ?? "");
|
|
666
|
+
if (message) errors[field.key] = message;
|
|
667
|
+
}
|
|
668
|
+
return errors;
|
|
669
|
+
}
|
|
604
670
|
function buildPatch(register, original, draft) {
|
|
605
671
|
const patch = { version: original.version };
|
|
606
672
|
for (const field of editableFields(register)) {
|
|
@@ -1035,14 +1101,16 @@ var COLUMNS = {
|
|
|
1035
1101
|
],
|
|
1036
1102
|
readings: [
|
|
1037
1103
|
{ key: "Title", header: "Reading" },
|
|
1038
|
-
{ key: "
|
|
1039
|
-
{ key: "
|
|
1104
|
+
{ key: "Source", header: "Source" },
|
|
1105
|
+
{ key: "Date", header: "Date" },
|
|
1106
|
+
// The row's per-belief Result / Rung / Strength are gone (OPS-1305) — they
|
|
1107
|
+
// live in the reading detail's per-belief verdict list. The table instead
|
|
1108
|
+
// previews the quote (`body`) so a row is legible at a glance; assumption
|
|
1109
|
+
// chips (see `readingAssumptionChips`) disambiguate same-titled readings.
|
|
1040
1110
|
{
|
|
1041
|
-
key: "
|
|
1042
|
-
header: "
|
|
1043
|
-
|
|
1044
|
-
derived: true,
|
|
1045
|
-
accessor: derivedField("strength")
|
|
1111
|
+
key: "body",
|
|
1112
|
+
header: "Quote",
|
|
1113
|
+
accessor: (r) => bodyPreview(r.body)
|
|
1046
1114
|
}
|
|
1047
1115
|
],
|
|
1048
1116
|
decisions: [
|
|
@@ -1057,6 +1125,16 @@ var COLUMNS = {
|
|
|
1057
1125
|
function columnsFor(register) {
|
|
1058
1126
|
return COLUMNS[register];
|
|
1059
1127
|
}
|
|
1128
|
+
function bodyPreview(value, max = 80) {
|
|
1129
|
+
if (typeof value !== "string") return "";
|
|
1130
|
+
const oneLine = value.replace(/\s+/g, " ").trim();
|
|
1131
|
+
if (oneLine.length <= max) return oneLine;
|
|
1132
|
+
return `${oneLine.slice(0, max - 1).trimEnd()}\u2026`;
|
|
1133
|
+
}
|
|
1134
|
+
function readingAssumptionChips(record, titleById = /* @__PURE__ */ new Map()) {
|
|
1135
|
+
const ids = Array.isArray(record.assumptionIds) ? record.assumptionIds.filter((x) => typeof x === "string") : [];
|
|
1136
|
+
return ids.map((id) => titleById.get(id) ?? id);
|
|
1137
|
+
}
|
|
1060
1138
|
function cellValue(column, record) {
|
|
1061
1139
|
return column.accessor ? column.accessor(record) : record[column.key];
|
|
1062
1140
|
}
|
|
@@ -1093,7 +1171,9 @@ var FIELD_LABEL = {
|
|
|
1093
1171
|
contradictsIds: "Contradicts",
|
|
1094
1172
|
readingIds: "Readings",
|
|
1095
1173
|
assumptionId: "Assumption",
|
|
1096
|
-
|
|
1174
|
+
assumptionIds: "Beliefs",
|
|
1175
|
+
experimentId: "Evidence plan",
|
|
1176
|
+
body: "Quote",
|
|
1097
1177
|
contextLinks: "Context links",
|
|
1098
1178
|
basedOnIds: "Based on",
|
|
1099
1179
|
resolvesIds: "Resolves",
|
|
@@ -1113,6 +1193,169 @@ function derivedLabel(key) {
|
|
|
1113
1193
|
return DERIVED_LABEL[key] ?? fieldLabel(key);
|
|
1114
1194
|
}
|
|
1115
1195
|
|
|
1196
|
+
// src/detail-fields.ts
|
|
1197
|
+
var META_FIELDS = /* @__PURE__ */ new Set([
|
|
1198
|
+
"id",
|
|
1199
|
+
"version",
|
|
1200
|
+
"createdAt",
|
|
1201
|
+
"updatedAt",
|
|
1202
|
+
"derived"
|
|
1203
|
+
]);
|
|
1204
|
+
var SUPPRESSED_FIELDS = /* @__PURE__ */ new Set([
|
|
1205
|
+
"barLineAssumptionIds",
|
|
1206
|
+
// A reading's `beliefs[]` is rendered as the richer per-belief verdict list
|
|
1207
|
+
// (OPS-1305), never as raw JSON in the generic row list.
|
|
1208
|
+
"beliefs",
|
|
1209
|
+
// `body` (a reading's quote / an experiment's narrative) renders as Markdown
|
|
1210
|
+
// in its own block, not as a raw-text row.
|
|
1211
|
+
"body"
|
|
1212
|
+
]);
|
|
1213
|
+
var RELATION_TARGET = {
|
|
1214
|
+
dependsOnIds: "assumptions",
|
|
1215
|
+
enablesIds: "assumptions",
|
|
1216
|
+
contradictsIds: "assumptions",
|
|
1217
|
+
readingIds: "readings",
|
|
1218
|
+
assumptionId: "assumptions",
|
|
1219
|
+
assumptionIds: "assumptions",
|
|
1220
|
+
experimentId: "experiments",
|
|
1221
|
+
basedOnIds: "assumptions",
|
|
1222
|
+
resolvesIds: "assumptions"
|
|
1223
|
+
};
|
|
1224
|
+
var OWNER_FIELDS = /* @__PURE__ */ new Set(["Owner", "Agreed by"]);
|
|
1225
|
+
function relatedList(related, register) {
|
|
1226
|
+
return related[register] ?? [];
|
|
1227
|
+
}
|
|
1228
|
+
function resolveItem(related, register, id) {
|
|
1229
|
+
const hit = relatedList(related, register).find((r) => r.id === id);
|
|
1230
|
+
return { id, register, title: hit ? primaryLabel(hit) : id };
|
|
1231
|
+
}
|
|
1232
|
+
function idsOf(value) {
|
|
1233
|
+
if (Array.isArray(value)) {
|
|
1234
|
+
return value.filter((v) => typeof v === "string");
|
|
1235
|
+
}
|
|
1236
|
+
return typeof value === "string" && value ? [value] : [];
|
|
1237
|
+
}
|
|
1238
|
+
function ownerNames(value) {
|
|
1239
|
+
if (!Array.isArray(value)) return [];
|
|
1240
|
+
return value.map((v) => {
|
|
1241
|
+
if (v && typeof v === "object") {
|
|
1242
|
+
const name = v.name;
|
|
1243
|
+
if (typeof name === "string" && name) return name;
|
|
1244
|
+
const id = v.id;
|
|
1245
|
+
return typeof id === "string" ? id : "\u2014";
|
|
1246
|
+
}
|
|
1247
|
+
return typeof v === "string" ? v : "\u2014";
|
|
1248
|
+
});
|
|
1249
|
+
}
|
|
1250
|
+
function resolveBarLines(bars, related) {
|
|
1251
|
+
return bars.map((b) => ({
|
|
1252
|
+
rightIf: b.rightIf ?? "",
|
|
1253
|
+
wrongIf: b.wrongIf ?? null,
|
|
1254
|
+
plannedRung: b.plannedRung ?? "",
|
|
1255
|
+
barVerdict: b.barVerdict ?? null,
|
|
1256
|
+
assumption: b.assumptionId ? resolveItem(related, "assumptions", b.assumptionId) : null
|
|
1257
|
+
}));
|
|
1258
|
+
}
|
|
1259
|
+
function detailRows(register, record, related = {}) {
|
|
1260
|
+
const keys = Object.keys(record).filter(
|
|
1261
|
+
(k) => !META_FIELDS.has(k) && !SUPPRESSED_FIELDS.has(k)
|
|
1262
|
+
);
|
|
1263
|
+
return keys.map((key) => {
|
|
1264
|
+
const value = record[key];
|
|
1265
|
+
const label = fieldLabel(key);
|
|
1266
|
+
const target = RELATION_TARGET[key];
|
|
1267
|
+
if (target) {
|
|
1268
|
+
let items = idsOf(value).map((id) => resolveItem(related, target, id));
|
|
1269
|
+
if (target === "experiments") {
|
|
1270
|
+
const archived = new Set(
|
|
1271
|
+
(related.experiments ?? []).filter((e) => isArchivedExperiment(e)).map((e) => e.id)
|
|
1272
|
+
);
|
|
1273
|
+
items = items.filter((it) => !archived.has(it.id));
|
|
1274
|
+
}
|
|
1275
|
+
return { key, label, kind: "relation", items };
|
|
1276
|
+
}
|
|
1277
|
+
if (OWNER_FIELDS.has(key)) {
|
|
1278
|
+
return { key, label, kind: "owner", names: ownerNames(value) };
|
|
1279
|
+
}
|
|
1280
|
+
if (key === "barLines" && Array.isArray(value)) {
|
|
1281
|
+
return {
|
|
1282
|
+
key,
|
|
1283
|
+
label,
|
|
1284
|
+
kind: "bar-lines",
|
|
1285
|
+
bars: resolveBarLines(value, related)
|
|
1286
|
+
};
|
|
1287
|
+
}
|
|
1288
|
+
return { key, label, kind: "text", text: formatValue(value) };
|
|
1289
|
+
});
|
|
1290
|
+
}
|
|
1291
|
+
|
|
1292
|
+
// src/edit-fields.tsx
|
|
1293
|
+
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
1294
|
+
function EditFields({
|
|
1295
|
+
register,
|
|
1296
|
+
draft,
|
|
1297
|
+
errors,
|
|
1298
|
+
onField
|
|
1299
|
+
}) {
|
|
1300
|
+
return /* @__PURE__ */ jsx2("div", { className: "vos-field-stack", children: editableFields(register).map((field) => /* @__PURE__ */ jsx2(
|
|
1301
|
+
FieldInput,
|
|
1302
|
+
{
|
|
1303
|
+
field,
|
|
1304
|
+
value: draft[field.key],
|
|
1305
|
+
error: errors?.[field.key],
|
|
1306
|
+
onChange: (v) => onField(field.key, v)
|
|
1307
|
+
},
|
|
1308
|
+
field.key
|
|
1309
|
+
)) });
|
|
1310
|
+
}
|
|
1311
|
+
function FieldInput({
|
|
1312
|
+
field,
|
|
1313
|
+
value,
|
|
1314
|
+
error,
|
|
1315
|
+
onChange
|
|
1316
|
+
}) {
|
|
1317
|
+
const id = `field-${field.key.replace(/\s+/g, "-")}`;
|
|
1318
|
+
return /* @__PURE__ */ jsxs2("div", { className: "vos-field", children: [
|
|
1319
|
+
/* @__PURE__ */ jsx2("label", { htmlFor: id, children: field.label }),
|
|
1320
|
+
field.kind === "textarea" ? /* @__PURE__ */ jsx2(
|
|
1321
|
+
"textarea",
|
|
1322
|
+
{
|
|
1323
|
+
id,
|
|
1324
|
+
value: String(value ?? ""),
|
|
1325
|
+
onChange: (e) => onChange(e.target.value),
|
|
1326
|
+
rows: 3,
|
|
1327
|
+
className: "vos-input",
|
|
1328
|
+
"aria-invalid": error ? true : void 0
|
|
1329
|
+
}
|
|
1330
|
+
) : field.kind === "select" ? /* @__PURE__ */ jsxs2(
|
|
1331
|
+
"select",
|
|
1332
|
+
{
|
|
1333
|
+
id,
|
|
1334
|
+
value: String(value ?? ""),
|
|
1335
|
+
onChange: (e) => onChange(e.target.value),
|
|
1336
|
+
className: "vos-input",
|
|
1337
|
+
children: [
|
|
1338
|
+
field.nullable ? /* @__PURE__ */ jsx2("option", { value: "", children: "\u2014" }) : null,
|
|
1339
|
+
field.options?.map((opt) => /* @__PURE__ */ jsx2("option", { value: opt, children: opt }, opt))
|
|
1340
|
+
]
|
|
1341
|
+
}
|
|
1342
|
+
) : /* @__PURE__ */ jsx2(
|
|
1343
|
+
"input",
|
|
1344
|
+
{
|
|
1345
|
+
id,
|
|
1346
|
+
type: field.kind === "number" ? "number" : "text",
|
|
1347
|
+
min: field.kind === "number" ? field.min : void 0,
|
|
1348
|
+
max: field.kind === "number" ? field.max : void 0,
|
|
1349
|
+
value: String(value ?? ""),
|
|
1350
|
+
onChange: (e) => onChange(e.target.value),
|
|
1351
|
+
className: "vos-input",
|
|
1352
|
+
"aria-invalid": error ? true : void 0
|
|
1353
|
+
}
|
|
1354
|
+
),
|
|
1355
|
+
error ? /* @__PURE__ */ jsx2("p", { role: "alert", className: "vos-field-error", children: error }) : null
|
|
1356
|
+
] });
|
|
1357
|
+
}
|
|
1358
|
+
|
|
1116
1359
|
// src/glossary-text.tsx
|
|
1117
1360
|
import { Fragment as Fragment2 } from "react";
|
|
1118
1361
|
|
|
@@ -1193,7 +1436,7 @@ function toGlossaryTerms(records) {
|
|
|
1193
1436
|
}
|
|
1194
1437
|
|
|
1195
1438
|
// src/glossary-text.tsx
|
|
1196
|
-
import { Fragment as Fragment3, jsx as
|
|
1439
|
+
import { Fragment as Fragment3, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
1197
1440
|
var PILL_CLASS = {
|
|
1198
1441
|
good: "vos-pill vos-pill-good",
|
|
1199
1442
|
warn: "vos-pill vos-pill-warn",
|
|
@@ -1208,8 +1451,8 @@ function GlossaryText({
|
|
|
1208
1451
|
onOpenTerm
|
|
1209
1452
|
}) {
|
|
1210
1453
|
const nodes = linkify(text, terms, { selfId });
|
|
1211
|
-
return /* @__PURE__ */
|
|
1212
|
-
(node, i) => node.kind === "text" ? /* @__PURE__ */
|
|
1454
|
+
return /* @__PURE__ */ jsx3(Fragment3, { children: nodes.map(
|
|
1455
|
+
(node, i) => node.kind === "text" ? /* @__PURE__ */ jsx3(Fragment2, { children: node.text }, i) : /* @__PURE__ */ jsx3(
|
|
1213
1456
|
TermLink,
|
|
1214
1457
|
{
|
|
1215
1458
|
text: node.text,
|
|
@@ -1225,8 +1468,8 @@ function TermLink({
|
|
|
1225
1468
|
term,
|
|
1226
1469
|
onOpenTerm
|
|
1227
1470
|
}) {
|
|
1228
|
-
return /* @__PURE__ */
|
|
1229
|
-
/* @__PURE__ */
|
|
1471
|
+
return /* @__PURE__ */ jsxs3("span", { className: "vos-gloss", children: [
|
|
1472
|
+
/* @__PURE__ */ jsx3(
|
|
1230
1473
|
"button",
|
|
1231
1474
|
{
|
|
1232
1475
|
type: "button",
|
|
@@ -1235,15 +1478,15 @@ function TermLink({
|
|
|
1235
1478
|
children: text
|
|
1236
1479
|
}
|
|
1237
1480
|
),
|
|
1238
|
-
/* @__PURE__ */
|
|
1239
|
-
/* @__PURE__ */
|
|
1240
|
-
/* @__PURE__ */
|
|
1241
|
-
/* @__PURE__ */
|
|
1481
|
+
/* @__PURE__ */ jsxs3("span", { className: "vos-gloss-pop", role: "tooltip", children: [
|
|
1482
|
+
/* @__PURE__ */ jsxs3("span", { className: "vos-gloss-pop-head", children: [
|
|
1483
|
+
/* @__PURE__ */ jsx3("b", { children: term.title }),
|
|
1484
|
+
/* @__PURE__ */ jsx3("span", { className: PILL_CLASS[statusTone(term.status)], children: term.status })
|
|
1242
1485
|
] }),
|
|
1243
|
-
/* @__PURE__ */
|
|
1244
|
-
term.dontConfuseWith.length ? /* @__PURE__ */
|
|
1245
|
-
/* @__PURE__ */
|
|
1246
|
-
term.dontConfuseWith.map((n) => /* @__PURE__ */
|
|
1486
|
+
/* @__PURE__ */ jsx3("span", { className: "vos-gloss-pop-def", children: term.definition || "\u2014" }),
|
|
1487
|
+
term.dontConfuseWith.length ? /* @__PURE__ */ jsxs3("span", { className: "vos-gloss-pop-neighbours", children: [
|
|
1488
|
+
/* @__PURE__ */ jsx3("span", { className: "vos-gloss-pop-label", children: "Don't confuse with" }),
|
|
1489
|
+
term.dontConfuseWith.map((n) => /* @__PURE__ */ jsx3(
|
|
1247
1490
|
"button",
|
|
1248
1491
|
{
|
|
1249
1492
|
type: "button",
|
|
@@ -1261,7 +1504,7 @@ function TermLink({
|
|
|
1261
1504
|
// src/journey.ts
|
|
1262
1505
|
import {
|
|
1263
1506
|
assumptionCompleteness as assumptionCompleteness2,
|
|
1264
|
-
|
|
1507
|
+
readingBeliefInputs as readingBeliefInputs3
|
|
1265
1508
|
} from "@validation-os/core";
|
|
1266
1509
|
import {
|
|
1267
1510
|
assembleJourney,
|
|
@@ -1271,35 +1514,103 @@ import {
|
|
|
1271
1514
|
rankNextMoves
|
|
1272
1515
|
} from "@validation-os/core/derivation";
|
|
1273
1516
|
|
|
1274
|
-
// src/
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
}
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
return
|
|
1282
|
-
}
|
|
1283
|
-
function strList(v) {
|
|
1284
|
-
return Array.isArray(v) ? v.filter((x) => typeof x === "string") : [];
|
|
1285
|
-
}
|
|
1286
|
-
function testsAssumption(exp, assumptionId) {
|
|
1287
|
-
const bars = exp.barLines;
|
|
1288
|
-
if (bars?.some((b) => b.assumptionId === assumptionId)) return true;
|
|
1289
|
-
return strList(exp.barLineAssumptionIds).includes(assumptionId);
|
|
1517
|
+
// src/cycles.ts
|
|
1518
|
+
import {
|
|
1519
|
+
readingBeliefInputs as readingBeliefInputs2
|
|
1520
|
+
} from "@validation-os/core";
|
|
1521
|
+
import { confidenceAttribution } from "@validation-os/core/derivation";
|
|
1522
|
+
var DIRECT_CYCLE_KEY = "direct";
|
|
1523
|
+
function readingDate(r) {
|
|
1524
|
+
return str(r.Date);
|
|
1290
1525
|
}
|
|
1291
|
-
function
|
|
1292
|
-
|
|
1293
|
-
|
|
1526
|
+
function toCycleReading(r, assumptionId) {
|
|
1527
|
+
return {
|
|
1528
|
+
id: r.id,
|
|
1529
|
+
date: readingDate(r),
|
|
1530
|
+
result: readingBeliefFor(r, assumptionId)?.Result ?? null
|
|
1531
|
+
};
|
|
1294
1532
|
}
|
|
1295
|
-
function
|
|
1296
|
-
return
|
|
1533
|
+
function sortByDate(readings) {
|
|
1534
|
+
return [...readings].sort((a, b) => {
|
|
1535
|
+
if (a.date === b.date) return 0;
|
|
1536
|
+
if (a.date === null) return 1;
|
|
1537
|
+
if (b.date === null) return -1;
|
|
1538
|
+
return a.date < b.date ? -1 : 1;
|
|
1539
|
+
});
|
|
1297
1540
|
}
|
|
1298
|
-
function
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1541
|
+
function barVerdictFor(exp, assumptionId) {
|
|
1542
|
+
const bars = exp.barLines ?? [];
|
|
1543
|
+
const line = bars.find((b) => b.assumptionId === assumptionId);
|
|
1544
|
+
return line?.barVerdict ?? null;
|
|
1545
|
+
}
|
|
1546
|
+
function buildCycles(assumptionId, readings, experiments) {
|
|
1547
|
+
const mine = readings.filter((r) => readingGrades(r, assumptionId));
|
|
1548
|
+
const inputs = readings.flatMap(readingBeliefInputs2).filter((i) => i.assumptionId === assumptionId);
|
|
1549
|
+
const { movers } = confidenceAttribution(inputs);
|
|
1550
|
+
const moverByKey = new Map(movers.map((m) => [m.key, m]));
|
|
1551
|
+
const byExperiment = /* @__PURE__ */ new Map();
|
|
1552
|
+
const direct = [];
|
|
1553
|
+
for (const r of mine) {
|
|
1554
|
+
const expId = str(r.experimentId);
|
|
1555
|
+
if (expId) {
|
|
1556
|
+
const bucket = byExperiment.get(expId) ?? [];
|
|
1557
|
+
bucket.push(r);
|
|
1558
|
+
byExperiment.set(expId, bucket);
|
|
1559
|
+
} else {
|
|
1560
|
+
direct.push(r);
|
|
1561
|
+
}
|
|
1562
|
+
}
|
|
1563
|
+
const experimentsById = new Map(experiments.map((e) => [e.id, e]));
|
|
1564
|
+
const experimentIds = /* @__PURE__ */ new Set([
|
|
1565
|
+
...liveExperiments(experiments).filter((e) => testsAssumption(e, assumptionId)).map((e) => e.id),
|
|
1566
|
+
...[...byExperiment.keys()].filter((id) => {
|
|
1567
|
+
const e = experimentsById.get(id);
|
|
1568
|
+
return !e || !isArchivedExperiment(e);
|
|
1569
|
+
})
|
|
1570
|
+
]);
|
|
1571
|
+
const cycles = [...experimentIds].map((id) => {
|
|
1572
|
+
const exp = experimentsById.get(id);
|
|
1573
|
+
const readingViews = sortByDate(
|
|
1574
|
+
(byExperiment.get(id) ?? []).map((r) => toCycleReading(r, assumptionId))
|
|
1575
|
+
);
|
|
1576
|
+
const mover = moverByKey.get(id);
|
|
1577
|
+
const date = (exp ? str(exp.Date) : null) ?? readingViews[0]?.date ?? null;
|
|
1578
|
+
return {
|
|
1579
|
+
key: id,
|
|
1580
|
+
kind: "experiment",
|
|
1581
|
+
title: exp ? str(exp.Title) : null,
|
|
1582
|
+
status: exp ? str(exp.Status) : null,
|
|
1583
|
+
date,
|
|
1584
|
+
barVerdict: exp ? barVerdictFor(exp, assumptionId) : null,
|
|
1585
|
+
readings: readingViews,
|
|
1586
|
+
contribution: mover?.contribution ?? 0,
|
|
1587
|
+
magnitude: mover?.magnitude ?? 0
|
|
1588
|
+
};
|
|
1589
|
+
});
|
|
1590
|
+
if (direct.length > 0) {
|
|
1591
|
+
const readingViews = sortByDate(
|
|
1592
|
+
direct.map((r) => toCycleReading(r, assumptionId))
|
|
1593
|
+
);
|
|
1594
|
+
const mover = moverByKey.get(DIRECT_CYCLE_KEY);
|
|
1595
|
+
cycles.push({
|
|
1596
|
+
key: DIRECT_CYCLE_KEY,
|
|
1597
|
+
kind: "direct",
|
|
1598
|
+
title: null,
|
|
1599
|
+
status: null,
|
|
1600
|
+
date: readingViews[0]?.date ?? null,
|
|
1601
|
+
barVerdict: null,
|
|
1602
|
+
readings: readingViews,
|
|
1603
|
+
contribution: mover?.contribution ?? 0,
|
|
1604
|
+
magnitude: mover?.magnitude ?? 0
|
|
1605
|
+
});
|
|
1606
|
+
}
|
|
1607
|
+
cycles.sort((a, b) => {
|
|
1608
|
+
if (a.date === b.date) return a.key.localeCompare(b.key);
|
|
1609
|
+
if (a.date === null) return 1;
|
|
1610
|
+
if (b.date === null) return -1;
|
|
1611
|
+
return a.date < b.date ? -1 : 1;
|
|
1612
|
+
});
|
|
1613
|
+
return cycles;
|
|
1303
1614
|
}
|
|
1304
1615
|
|
|
1305
1616
|
// src/journey.ts
|
|
@@ -1354,32 +1665,31 @@ function buildJourney(assumptionId, records, now) {
|
|
|
1354
1665
|
if (!belief2) return null;
|
|
1355
1666
|
const derived = belief2.derived && typeof belief2.derived === "object" ? belief2.derived : {};
|
|
1356
1667
|
const confidence2 = typeof derived.confidence === "number" ? derived.confidence : 0;
|
|
1357
|
-
const
|
|
1358
|
-
|
|
1359
|
-
) ?? emptyTestMeter();
|
|
1668
|
+
const live = liveExperiments(records.experiments);
|
|
1669
|
+
const test = beliefTestMeters2(live.map(toStageExperimentInput)).get(assumptionId) ?? emptyTestMeter();
|
|
1360
1670
|
const framed = assumptionCompleteness2(belief2);
|
|
1361
1671
|
const stage = deriveBeliefStage2({ framed, confidence: confidence2, test });
|
|
1362
|
-
const
|
|
1363
|
-
|
|
1364
|
-
);
|
|
1365
|
-
const myExperiments = records.experiments.filter((e) => testsAssumption(e, assumptionId)).map((e) => ({ id: e.id, date: str4(e.Date) || str4(e.createdAt) || null }));
|
|
1672
|
+
const myReadingInputs = records.readings.flatMap(readingBeliefInputs3).filter((i) => i.assumptionId === assumptionId);
|
|
1673
|
+
const myExperiments = live.filter((e) => testsAssumption(e, assumptionId)).map((e) => ({ id: e.id, date: str4(e.Date) || str4(e.createdAt) || null }));
|
|
1366
1674
|
const events = assembleJourney({
|
|
1367
1675
|
belief: {
|
|
1368
1676
|
createdAt: str4(belief2.createdAt) || null,
|
|
1369
1677
|
impactScored: belief2.Impact != null
|
|
1370
1678
|
},
|
|
1371
|
-
readings:
|
|
1679
|
+
readings: myReadingInputs,
|
|
1372
1680
|
experiments: myExperiments,
|
|
1373
1681
|
now
|
|
1374
1682
|
}).map((event) => ({ ...event, label: labelFor(event) }));
|
|
1375
1683
|
const nextMove2 = rankNextMoves(toNextMoveInput(records)).find(
|
|
1376
1684
|
(m) => m.assumptionId === assumptionId
|
|
1377
1685
|
) ?? null;
|
|
1686
|
+
const cycles = buildCycles(assumptionId, records.readings, records.experiments);
|
|
1378
1687
|
return {
|
|
1379
1688
|
id: assumptionId,
|
|
1380
1689
|
statement: str4(belief2.Title),
|
|
1381
1690
|
stage,
|
|
1382
1691
|
events,
|
|
1692
|
+
cycles,
|
|
1383
1693
|
nextMove: nextMove2,
|
|
1384
1694
|
resolved: resolvedKind(belief2)
|
|
1385
1695
|
};
|
|
@@ -1393,7 +1703,7 @@ import { useState as useState3 } from "react";
|
|
|
1393
1703
|
|
|
1394
1704
|
// src/drawer-shell.tsx
|
|
1395
1705
|
import { useEffect as useEffect2, useRef } from "react";
|
|
1396
|
-
import { Fragment as Fragment4, jsx as
|
|
1706
|
+
import { Fragment as Fragment4, jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
1397
1707
|
function DrawerShell({
|
|
1398
1708
|
open,
|
|
1399
1709
|
onClose,
|
|
@@ -1411,8 +1721,8 @@ function DrawerShell({
|
|
|
1411
1721
|
return () => document.removeEventListener("keydown", onKey);
|
|
1412
1722
|
}, [open, onClose]);
|
|
1413
1723
|
if (!open) return null;
|
|
1414
|
-
return /* @__PURE__ */
|
|
1415
|
-
/* @__PURE__ */
|
|
1724
|
+
return /* @__PURE__ */ jsxs4(Fragment4, { children: [
|
|
1725
|
+
/* @__PURE__ */ jsx4(
|
|
1416
1726
|
"button",
|
|
1417
1727
|
{
|
|
1418
1728
|
type: "button",
|
|
@@ -1421,7 +1731,7 @@ function DrawerShell({
|
|
|
1421
1731
|
className: "vos-scrim"
|
|
1422
1732
|
}
|
|
1423
1733
|
),
|
|
1424
|
-
/* @__PURE__ */
|
|
1734
|
+
/* @__PURE__ */ jsx4(
|
|
1425
1735
|
"aside",
|
|
1426
1736
|
{
|
|
1427
1737
|
ref: panelRef,
|
|
@@ -1436,65 +1746,6 @@ function DrawerShell({
|
|
|
1436
1746
|
] });
|
|
1437
1747
|
}
|
|
1438
1748
|
|
|
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
1749
|
// src/field-styles.ts
|
|
1499
1750
|
var FIELD_LABEL_CLASS = "vos-field-label";
|
|
1500
1751
|
var FIELD_CONTROL_CLASS = "vos-input";
|
|
@@ -2012,35 +2263,37 @@ function StatTile({
|
|
|
2012
2263
|
|
|
2013
2264
|
// src/understanding.ts
|
|
2014
2265
|
import {
|
|
2015
|
-
|
|
2266
|
+
readingBeliefInputs as readingBeliefInputs4
|
|
2016
2267
|
} from "@validation-os/core";
|
|
2017
2268
|
import {
|
|
2018
|
-
confidenceAttribution,
|
|
2269
|
+
confidenceAttribution as confidenceAttribution2,
|
|
2019
2270
|
confidenceTrajectory,
|
|
2020
2271
|
experimentProgress,
|
|
2021
2272
|
isConcluded as isConcluded2
|
|
2022
2273
|
} from "@validation-os/core/derivation";
|
|
2023
2274
|
function buildUnderstanding(assumption, readings, experiments) {
|
|
2024
|
-
const
|
|
2025
|
-
const
|
|
2026
|
-
const { confidence: confidence2, movers } = confidenceAttribution(inputs);
|
|
2275
|
+
const inputs = readings.flatMap(readingBeliefInputs4).filter((i) => i.assumptionId === assumption.id);
|
|
2276
|
+
const { confidence: confidence2, movers } = confidenceAttribution2(inputs);
|
|
2027
2277
|
const experimentsById = new Map(experiments.map((e) => [e.id, e]));
|
|
2028
2278
|
const moverByExperiment = new Map(
|
|
2029
2279
|
movers.filter((m) => m.kind === "experiment").map((m) => [m.experimentId, m])
|
|
2030
2280
|
);
|
|
2031
2281
|
const experimentIds = /* @__PURE__ */ new Set([
|
|
2032
|
-
...experiments.filter((e) => testsAssumption(e, assumption.id)).map((e) => e.id),
|
|
2033
|
-
...moverByExperiment.keys()
|
|
2282
|
+
...liveExperiments(experiments).filter((e) => testsAssumption(e, assumption.id)).map((e) => e.id),
|
|
2283
|
+
...[...moverByExperiment.keys()].filter((id) => {
|
|
2284
|
+
const e = experimentsById.get(id);
|
|
2285
|
+
return !e || !isArchivedExperiment(e);
|
|
2286
|
+
})
|
|
2034
2287
|
]);
|
|
2035
2288
|
const experimentViews = [...experimentIds].map((id) => {
|
|
2036
2289
|
const exp = experimentsById.get(id);
|
|
2037
2290
|
const mover = moverByExperiment.get(id);
|
|
2038
2291
|
const bars = exp?.barLines ?? [];
|
|
2039
2292
|
const progress = bars.length ? experimentProgress(bars) : null;
|
|
2040
|
-
const status = exp ?
|
|
2293
|
+
const status = exp ? str(exp.Status) : null;
|
|
2041
2294
|
return {
|
|
2042
2295
|
experimentId: id,
|
|
2043
|
-
title: exp ?
|
|
2296
|
+
title: exp ? str(exp.Title) : null,
|
|
2044
2297
|
status,
|
|
2045
2298
|
contribution: mover?.contribution ?? 0,
|
|
2046
2299
|
magnitude: mover?.magnitude ?? 0,
|
|
@@ -2268,6 +2521,10 @@ function BeliefJourney({
|
|
|
2268
2521
|
`${event.kind}-${event.refId ?? i}`
|
|
2269
2522
|
)) })
|
|
2270
2523
|
] }),
|
|
2524
|
+
journey.cycles.length > 0 ? /* @__PURE__ */ jsxs8("section", { children: [
|
|
2525
|
+
/* @__PURE__ */ jsx8("div", { className: "vos-why-section-title", children: "Round by round" }),
|
|
2526
|
+
/* @__PURE__ */ jsx8(CycleTimeline, { cycles: journey.cycles })
|
|
2527
|
+
] }) : null,
|
|
2271
2528
|
/* @__PURE__ */ jsxs8("section", { children: [
|
|
2272
2529
|
/* @__PURE__ */ jsx8("div", { className: "vos-why-section-title", children: "What moved the number" }),
|
|
2273
2530
|
/* @__PURE__ */ jsx8(UnderstandingPanel, { assumption, basePath })
|
|
@@ -2413,6 +2670,62 @@ function EventRow({
|
|
|
2413
2670
|
) : null
|
|
2414
2671
|
] });
|
|
2415
2672
|
}
|
|
2673
|
+
function readingDotTone(result) {
|
|
2674
|
+
if (result === "Validated") return "good";
|
|
2675
|
+
if (result === "Invalidated") return "crit";
|
|
2676
|
+
return "neutral";
|
|
2677
|
+
}
|
|
2678
|
+
var BAR_VERDICT_PILL = {
|
|
2679
|
+
Validated: "vos-pill vos-pill-good",
|
|
2680
|
+
Invalidated: "vos-pill vos-pill-crit",
|
|
2681
|
+
Inconclusive: "vos-pill vos-pill-neutral"
|
|
2682
|
+
};
|
|
2683
|
+
function CycleTimeline({ cycles }) {
|
|
2684
|
+
const maxMagnitude = Math.max(...cycles.map((c) => c.magnitude), 0.01);
|
|
2685
|
+
return /* @__PURE__ */ jsx8("ol", { className: "vos-cyc-list", children: cycles.map((cycle, i) => /* @__PURE__ */ jsx8(CycleCard, { cycle, n: i + 1, max: maxMagnitude }, cycle.key)) });
|
|
2686
|
+
}
|
|
2687
|
+
function CycleCard({
|
|
2688
|
+
cycle,
|
|
2689
|
+
n,
|
|
2690
|
+
max
|
|
2691
|
+
}) {
|
|
2692
|
+
const up = cycle.contribution >= 0;
|
|
2693
|
+
const moving = cycle.magnitude > 0;
|
|
2694
|
+
const width = Math.round(cycle.magnitude / max * 50);
|
|
2695
|
+
const fill = up ? { left: "50%", width: `${width}%`, background: "var(--vos-good)" } : { right: "50%", width: `${width}%`, background: "var(--vos-crit)" };
|
|
2696
|
+
return /* @__PURE__ */ jsxs8("li", { className: "vos-cyc-card", children: [
|
|
2697
|
+
/* @__PURE__ */ jsxs8("div", { className: "vos-cyc-head", children: [
|
|
2698
|
+
/* @__PURE__ */ jsxs8("span", { className: "vos-cyc-num", children: [
|
|
2699
|
+
"Round ",
|
|
2700
|
+
n
|
|
2701
|
+
] }),
|
|
2702
|
+
cycle.date ? /* @__PURE__ */ jsx8("span", { className: "vos-cyc-date", children: cycle.date }) : null
|
|
2703
|
+
] }),
|
|
2704
|
+
/* @__PURE__ */ jsx8("div", { className: "vos-cyc-title", children: cycle.kind === "direct" ? "Direct evidence" : cycle.title ?? "Untitled experiment" }),
|
|
2705
|
+
cycle.readings.length > 0 ? /* @__PURE__ */ jsx8(
|
|
2706
|
+
"div",
|
|
2707
|
+
{
|
|
2708
|
+
className: "vos-cyc-dots",
|
|
2709
|
+
role: "img",
|
|
2710
|
+
"aria-label": `${cycle.readings.length} reading${cycle.readings.length === 1 ? "" : "s"}`,
|
|
2711
|
+
children: cycle.readings.map((r) => /* @__PURE__ */ jsx8(
|
|
2712
|
+
"span",
|
|
2713
|
+
{
|
|
2714
|
+
className: `vos-jny-dot ${DOT_CLASS[readingDotTone(r.result)]}`
|
|
2715
|
+
},
|
|
2716
|
+
r.id
|
|
2717
|
+
))
|
|
2718
|
+
}
|
|
2719
|
+
) : /* @__PURE__ */ jsx8("span", { className: "vos-hint", children: "No readings yet" }),
|
|
2720
|
+
/* @__PURE__ */ jsxs8("div", { className: "vos-cyc-foot", children: [
|
|
2721
|
+
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,
|
|
2722
|
+
moving ? /* @__PURE__ */ jsxs8("span", { className: "vos-cyc-push", children: [
|
|
2723
|
+
/* @__PURE__ */ jsx8("span", { className: "vos-track vos-signed vos-cyc-track", children: /* @__PURE__ */ jsx8("i", { style: fill }) }),
|
|
2724
|
+
/* @__PURE__ */ jsx8("span", { className: up ? "vos-text-good" : "vos-text-crit", children: formatSigned(cycle.contribution) })
|
|
2725
|
+
] }) : null
|
|
2726
|
+
] })
|
|
2727
|
+
] });
|
|
2728
|
+
}
|
|
2416
2729
|
function NextMoveCard({
|
|
2417
2730
|
move,
|
|
2418
2731
|
resolved,
|
|
@@ -2457,42 +2770,43 @@ function JourneyColdCard({
|
|
|
2457
2770
|
}
|
|
2458
2771
|
|
|
2459
2772
|
// src/list-surface.ts
|
|
2773
|
+
function hasConcludedBelief(r) {
|
|
2774
|
+
return readingBeliefs(r).some((b) => b.Result !== "Inconclusive");
|
|
2775
|
+
}
|
|
2460
2776
|
function isProven(a, ctx) {
|
|
2461
|
-
if (
|
|
2462
|
-
const
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
const strongest = mine.reduce(
|
|
2467
|
-
(best, r) => Math.abs(derivedNum(r, "strength") ?? 0) > Math.abs(derivedNum(best, "strength") ?? 0) ? r : best
|
|
2777
|
+
if (str(a.Status) !== "Live") return false;
|
|
2778
|
+
const scores = (ctx.readings ?? []).map((r) => readingBeliefFor(r, a.id)).filter((b) => b != null && b.Result !== "Inconclusive");
|
|
2779
|
+
if (scores.length === 0) return false;
|
|
2780
|
+
const strongest = scores.reduce(
|
|
2781
|
+
(best, b) => Math.abs(b.derived?.strength ?? 0) > Math.abs(best.derived?.strength ?? 0) ? b : best
|
|
2468
2782
|
);
|
|
2469
|
-
return
|
|
2783
|
+
return strongest.Result === "Validated";
|
|
2470
2784
|
}
|
|
2471
2785
|
function isOverdue(e, ctx) {
|
|
2472
|
-
const deadline =
|
|
2473
|
-
if (!ctx.asOf || !deadline ||
|
|
2786
|
+
const deadline = str(e.Deadline);
|
|
2787
|
+
if (!ctx.asOf || !deadline || str(e.Status) !== "Running") return false;
|
|
2474
2788
|
return deadline < ctx.asOf;
|
|
2475
2789
|
}
|
|
2476
2790
|
function inTension(d, ctx) {
|
|
2477
|
-
if (
|
|
2791
|
+
if (str(d.Status) !== "Active") return false;
|
|
2478
2792
|
const based = strList(d.basedOnIds);
|
|
2479
2793
|
if (based.length === 0) return false;
|
|
2480
2794
|
const byId = new Map((ctx.assumptions ?? []).map((a) => [a.id, a]));
|
|
2481
2795
|
return based.some((id) => {
|
|
2482
2796
|
const a = byId.get(id);
|
|
2483
2797
|
if (!a) return false;
|
|
2484
|
-
return
|
|
2798
|
+
return str(a.Status) === "Invalidated" || inKillLane(a);
|
|
2485
2799
|
});
|
|
2486
2800
|
}
|
|
2487
2801
|
var ALWAYS = () => true;
|
|
2488
|
-
var byStatus = (...values) => (r) => values.includes(
|
|
2802
|
+
var byStatus = (...values) => (r) => values.includes(str(r.Status) ?? "");
|
|
2489
2803
|
var TAB_CATALOGUE = {
|
|
2490
2804
|
assumptions: [
|
|
2491
2805
|
{
|
|
2492
2806
|
id: "live",
|
|
2493
2807
|
label: "Live",
|
|
2494
2808
|
isDefault: true,
|
|
2495
|
-
predicate: (r) =>
|
|
2809
|
+
predicate: (r) => str(r.Status) === "Live" && r.moot !== true,
|
|
2496
2810
|
defaultSort: { key: "risk", dir: "desc" }
|
|
2497
2811
|
},
|
|
2498
2812
|
{
|
|
@@ -2545,12 +2859,12 @@ var TAB_CATALOGUE = {
|
|
|
2545
2859
|
{
|
|
2546
2860
|
id: "concluded",
|
|
2547
2861
|
label: "\xB1 Concluded",
|
|
2548
|
-
predicate: (r) =>
|
|
2862
|
+
predicate: (r) => hasConcludedBelief(r)
|
|
2549
2863
|
},
|
|
2550
2864
|
{
|
|
2551
2865
|
id: "inconclusive",
|
|
2552
2866
|
label: "Inconclusive",
|
|
2553
|
-
predicate: (r) =>
|
|
2867
|
+
predicate: (r) => !hasConcludedBelief(r)
|
|
2554
2868
|
}
|
|
2555
2869
|
],
|
|
2556
2870
|
decisions: [
|
|
@@ -2639,7 +2953,7 @@ function groupRecords(records, axis) {
|
|
|
2639
2953
|
if (values.length === 0) push(emptyLabel, r);
|
|
2640
2954
|
else for (const v of values) push(v, r);
|
|
2641
2955
|
} else {
|
|
2642
|
-
push(
|
|
2956
|
+
push(str(r[axis]) ?? emptyLabel, r);
|
|
2643
2957
|
}
|
|
2644
2958
|
}
|
|
2645
2959
|
return order.map((key) => ({ key, label: key, records: buckets.get(key) }));
|
|
@@ -2648,7 +2962,7 @@ function filterRecords(records, query) {
|
|
|
2648
2962
|
const q = query.trim().toLowerCase();
|
|
2649
2963
|
if (!q) return records;
|
|
2650
2964
|
return records.filter((r) => {
|
|
2651
|
-
const hay = `${
|
|
2965
|
+
const hay = `${str(r.Title) ?? ""} ${str(r.Description) ?? ""} ${str(r.Source) ?? ""}`.toLowerCase();
|
|
2652
2966
|
return hay.includes(q);
|
|
2653
2967
|
});
|
|
2654
2968
|
}
|
|
@@ -2674,11 +2988,11 @@ function sortRecords(records, sort) {
|
|
|
2674
2988
|
}).map((x) => x.r);
|
|
2675
2989
|
}
|
|
2676
2990
|
function nestReadingsByPlan(readings, experiments) {
|
|
2677
|
-
const titleById = new Map(experiments.map((e) => [e.id,
|
|
2991
|
+
const titleById = new Map(experiments.map((e) => [e.id, str(e.Title)]));
|
|
2678
2992
|
const order = [];
|
|
2679
2993
|
const groups = /* @__PURE__ */ new Map();
|
|
2680
2994
|
for (const r of readings) {
|
|
2681
|
-
const key =
|
|
2995
|
+
const key = str(r.experimentId);
|
|
2682
2996
|
if (!groups.has(key)) {
|
|
2683
2997
|
groups.set(key, []);
|
|
2684
2998
|
order.push(key);
|
|
@@ -2722,17 +3036,160 @@ function needsHumanCounts(ctx) {
|
|
|
2722
3036
|
};
|
|
2723
3037
|
}
|
|
2724
3038
|
|
|
2725
|
-
// src/
|
|
2726
|
-
import {
|
|
2727
|
-
function
|
|
2728
|
-
const
|
|
2729
|
-
|
|
2730
|
-
}
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
const
|
|
2734
|
-
|
|
2735
|
-
|
|
3039
|
+
// src/markdown.tsx
|
|
3040
|
+
import { jsx as jsx9 } from "react/jsx-runtime";
|
|
3041
|
+
function Markdown({ text }) {
|
|
3042
|
+
const trimmed = (text ?? "").trim();
|
|
3043
|
+
if (!trimmed) return null;
|
|
3044
|
+
return /* @__PURE__ */ jsx9("div", { className: "vos-md", children: renderBlocks(trimmed) });
|
|
3045
|
+
}
|
|
3046
|
+
function renderBlocks(text) {
|
|
3047
|
+
const lines = text.replace(/\r\n?/g, "\n").split("\n");
|
|
3048
|
+
const out = [];
|
|
3049
|
+
let i = 0;
|
|
3050
|
+
let key = 0;
|
|
3051
|
+
while (i < lines.length) {
|
|
3052
|
+
const line = lines[i];
|
|
3053
|
+
if (line.trim() === "") {
|
|
3054
|
+
i += 1;
|
|
3055
|
+
continue;
|
|
3056
|
+
}
|
|
3057
|
+
const fence = line.match(/^```/);
|
|
3058
|
+
if (fence) {
|
|
3059
|
+
const body = [];
|
|
3060
|
+
i += 1;
|
|
3061
|
+
while (i < lines.length && !/^```/.test(lines[i])) {
|
|
3062
|
+
body.push(lines[i]);
|
|
3063
|
+
i += 1;
|
|
3064
|
+
}
|
|
3065
|
+
i += 1;
|
|
3066
|
+
out.push(
|
|
3067
|
+
/* @__PURE__ */ jsx9("pre", { className: "vos-md-pre", children: /* @__PURE__ */ jsx9("code", { children: body.join("\n") }) }, key++)
|
|
3068
|
+
);
|
|
3069
|
+
continue;
|
|
3070
|
+
}
|
|
3071
|
+
const heading = line.match(/^(#{1,6})\s+(.*)$/);
|
|
3072
|
+
if (heading) {
|
|
3073
|
+
const level = heading[1].length;
|
|
3074
|
+
const Tag = `h${Math.min(level + 2, 6)}`;
|
|
3075
|
+
out.push(/* @__PURE__ */ jsx9(Tag, { children: renderInline(heading[2]) }, key++));
|
|
3076
|
+
i += 1;
|
|
3077
|
+
continue;
|
|
3078
|
+
}
|
|
3079
|
+
if (/^>\s?/.test(line)) {
|
|
3080
|
+
const quote = [];
|
|
3081
|
+
while (i < lines.length && /^>\s?/.test(lines[i])) {
|
|
3082
|
+
quote.push(lines[i].replace(/^>\s?/, ""));
|
|
3083
|
+
i += 1;
|
|
3084
|
+
}
|
|
3085
|
+
out.push(
|
|
3086
|
+
/* @__PURE__ */ jsx9("blockquote", { className: "vos-md-quote", children: renderBlocks(quote.join("\n")) }, key++)
|
|
3087
|
+
);
|
|
3088
|
+
continue;
|
|
3089
|
+
}
|
|
3090
|
+
if (/^[-*+]\s+/.test(line)) {
|
|
3091
|
+
const items = [];
|
|
3092
|
+
while (i < lines.length && /^[-*+]\s+/.test(lines[i])) {
|
|
3093
|
+
items.push(lines[i].replace(/^[-*+]\s+/, ""));
|
|
3094
|
+
i += 1;
|
|
3095
|
+
}
|
|
3096
|
+
out.push(
|
|
3097
|
+
/* @__PURE__ */ jsx9("ul", { className: "vos-md-ul", children: items.map((it, n) => /* @__PURE__ */ jsx9("li", { children: renderInline(it) }, n)) }, key++)
|
|
3098
|
+
);
|
|
3099
|
+
continue;
|
|
3100
|
+
}
|
|
3101
|
+
if (/^\d+\.\s+/.test(line)) {
|
|
3102
|
+
const items = [];
|
|
3103
|
+
while (i < lines.length && /^\d+\.\s+/.test(lines[i])) {
|
|
3104
|
+
items.push(lines[i].replace(/^\d+\.\s+/, ""));
|
|
3105
|
+
i += 1;
|
|
3106
|
+
}
|
|
3107
|
+
out.push(
|
|
3108
|
+
/* @__PURE__ */ jsx9("ol", { className: "vos-md-ol", children: items.map((it, n) => /* @__PURE__ */ jsx9("li", { children: renderInline(it) }, n)) }, key++)
|
|
3109
|
+
);
|
|
3110
|
+
continue;
|
|
3111
|
+
}
|
|
3112
|
+
const para = [];
|
|
3113
|
+
while (i < lines.length && lines[i].trim() !== "" && !/^```|^#{1,6}\s|^>\s?|^[-*+]\s+|^\d+\.\s+/.test(lines[i])) {
|
|
3114
|
+
para.push(lines[i]);
|
|
3115
|
+
i += 1;
|
|
3116
|
+
}
|
|
3117
|
+
out.push(/* @__PURE__ */ jsx9("p", { children: renderInline(para.join(" ")) }, key++));
|
|
3118
|
+
}
|
|
3119
|
+
return out;
|
|
3120
|
+
}
|
|
3121
|
+
function safeHref(href) {
|
|
3122
|
+
if (/^(https?:\/\/|mailto:)/i.test(href)) return href;
|
|
3123
|
+
if (/^[#/]/.test(href)) return href;
|
|
3124
|
+
return null;
|
|
3125
|
+
}
|
|
3126
|
+
var INLINE_RULES = [
|
|
3127
|
+
// Inline code first — its contents are literal.
|
|
3128
|
+
{
|
|
3129
|
+
re: /`([^`]+)`/,
|
|
3130
|
+
render: (m, key) => /* @__PURE__ */ jsx9("code", { className: "vos-md-code", children: m[1] }, key),
|
|
3131
|
+
recurse: false
|
|
3132
|
+
},
|
|
3133
|
+
// Links: [text](href)
|
|
3134
|
+
{
|
|
3135
|
+
re: /\[([^\]]+)\]\(([^)\s]+)\)/,
|
|
3136
|
+
render: (m, key) => {
|
|
3137
|
+
const href = safeHref(m[2]);
|
|
3138
|
+
if (!href) return /* @__PURE__ */ jsx9("span", { children: m[1] }, key);
|
|
3139
|
+
return /* @__PURE__ */ jsx9("a", { href, target: "_blank", rel: "noopener noreferrer", children: m[1] }, key);
|
|
3140
|
+
},
|
|
3141
|
+
recurse: false
|
|
3142
|
+
},
|
|
3143
|
+
// Bold: **text** or __text__
|
|
3144
|
+
{
|
|
3145
|
+
re: /\*\*([^*]+)\*\*|__([^_]+)__/,
|
|
3146
|
+
render: (m, key) => /* @__PURE__ */ jsx9("strong", { children: renderInline(m[1] ?? m[2] ?? "") }, key),
|
|
3147
|
+
recurse: true,
|
|
3148
|
+
inner: (m) => m[1] ?? m[2] ?? ""
|
|
3149
|
+
},
|
|
3150
|
+
// Italic: *text* or _text_
|
|
3151
|
+
{
|
|
3152
|
+
re: /\*([^*]+)\*|_([^_]+)_/,
|
|
3153
|
+
render: (m, key) => /* @__PURE__ */ jsx9("em", { children: renderInline(m[1] ?? m[2] ?? "") }, key),
|
|
3154
|
+
recurse: true,
|
|
3155
|
+
inner: (m) => m[1] ?? m[2] ?? ""
|
|
3156
|
+
}
|
|
3157
|
+
];
|
|
3158
|
+
function renderInline(text) {
|
|
3159
|
+
const nodes = [];
|
|
3160
|
+
let rest = text;
|
|
3161
|
+
let key = 0;
|
|
3162
|
+
while (rest.length > 0) {
|
|
3163
|
+
let best = null;
|
|
3164
|
+
for (const rule2 of INLINE_RULES) {
|
|
3165
|
+
const m2 = new RegExp(rule2.re).exec(rest);
|
|
3166
|
+
if (m2 && (best === null || m2.index < best.m.index)) {
|
|
3167
|
+
best = { rule: rule2, m: m2 };
|
|
3168
|
+
}
|
|
3169
|
+
}
|
|
3170
|
+
if (!best) {
|
|
3171
|
+
nodes.push(rest);
|
|
3172
|
+
break;
|
|
3173
|
+
}
|
|
3174
|
+
const { rule, m } = best;
|
|
3175
|
+
if (m.index > 0) nodes.push(rest.slice(0, m.index));
|
|
3176
|
+
nodes.push(rule.render(m, key++));
|
|
3177
|
+
rest = rest.slice(m.index + m[0].length);
|
|
3178
|
+
}
|
|
3179
|
+
return nodes;
|
|
3180
|
+
}
|
|
3181
|
+
|
|
3182
|
+
// src/record-view.ts
|
|
3183
|
+
import { experimentProgress as experimentProgress2 } from "@validation-os/core/derivation";
|
|
3184
|
+
function byIds(records, ids) {
|
|
3185
|
+
const map = new Map((records ?? []).map((r) => [r.id, r]));
|
|
3186
|
+
return ids.map((id) => map.get(id)).filter((r) => r != null);
|
|
3187
|
+
}
|
|
3188
|
+
function headerPills(register, record, related = {}, options = {}) {
|
|
3189
|
+
const pills = [];
|
|
3190
|
+
const status = str(record.Status);
|
|
3191
|
+
if (status) pills.push({ label: status, tone: statusTone(status) });
|
|
3192
|
+
if (register === "assumptions") {
|
|
2736
3193
|
if (record.moot === true) pills.push({ label: "Moot", tone: "neutral" });
|
|
2737
3194
|
if (inKillLane(record)) pills.push({ label: "Kill lane", tone: "crit" });
|
|
2738
3195
|
else if (isTesting(record, related.experiments ?? []))
|
|
@@ -2740,7 +3197,7 @@ function headerPills(register, record, related = {}, options = {}) {
|
|
|
2740
3197
|
} else if (register === "experiments") {
|
|
2741
3198
|
if (status === "Draft") pills.push({ label: "Test-next", tone: "accent" });
|
|
2742
3199
|
if (status === "Closed") pills.push({ label: "Concluded", tone: "good" });
|
|
2743
|
-
const deadline =
|
|
3200
|
+
const deadline = str(record.Deadline);
|
|
2744
3201
|
if (options.asOf && deadline && status === "Running" && deadline < options.asOf)
|
|
2745
3202
|
pills.push({ label: "Overdue", tone: "crit" });
|
|
2746
3203
|
} else if (register === "decisions") {
|
|
@@ -2781,15 +3238,6 @@ function leadingMeters(register, record) {
|
|
|
2781
3238
|
];
|
|
2782
3239
|
case "readings":
|
|
2783
3240
|
return [
|
|
2784
|
-
{
|
|
2785
|
-
key: "strength",
|
|
2786
|
-
label: "Strength",
|
|
2787
|
-
kind: "signed",
|
|
2788
|
-
value: derivedNum(record, "strength"),
|
|
2789
|
-
tone: "neutral",
|
|
2790
|
-
min: -100,
|
|
2791
|
-
max: 100
|
|
2792
|
-
},
|
|
2793
3241
|
{
|
|
2794
3242
|
key: "sourceQuality",
|
|
2795
3243
|
label: "Source quality",
|
|
@@ -2798,13 +3246,6 @@ function leadingMeters(register, record) {
|
|
|
2798
3246
|
value: derivedNum(record, "sourceQuality") === null ? null : Math.round((derivedNum(record, "sourceQuality") ?? 0) * 100),
|
|
2799
3247
|
tone: "neutral",
|
|
2800
3248
|
max: 100
|
|
2801
|
-
},
|
|
2802
|
-
{
|
|
2803
|
-
key: "Result",
|
|
2804
|
-
label: "Result",
|
|
2805
|
-
kind: "pill",
|
|
2806
|
-
value: str3(record.Result),
|
|
2807
|
-
tone: statusTone(str3(record.Result) ?? "")
|
|
2808
3249
|
}
|
|
2809
3250
|
];
|
|
2810
3251
|
case "experiments": {
|
|
@@ -2823,7 +3264,7 @@ function leadingMeters(register, record) {
|
|
|
2823
3264
|
key: "Feasibility",
|
|
2824
3265
|
label: "Feasibility",
|
|
2825
3266
|
kind: "pill",
|
|
2826
|
-
value:
|
|
3267
|
+
value: str(record.Feasibility),
|
|
2827
3268
|
tone: "neutral"
|
|
2828
3269
|
}
|
|
2829
3270
|
];
|
|
@@ -2834,8 +3275,8 @@ function leadingMeters(register, record) {
|
|
|
2834
3275
|
key: "Status",
|
|
2835
3276
|
label: "Status",
|
|
2836
3277
|
kind: "pill",
|
|
2837
|
-
value:
|
|
2838
|
-
tone: statusTone(
|
|
3278
|
+
value: str(record.Status),
|
|
3279
|
+
tone: statusTone(str(record.Status) ?? "")
|
|
2839
3280
|
}
|
|
2840
3281
|
];
|
|
2841
3282
|
case "glossary":
|
|
@@ -2844,8 +3285,8 @@ function leadingMeters(register, record) {
|
|
|
2844
3285
|
key: "Status",
|
|
2845
3286
|
label: "Status",
|
|
2846
3287
|
kind: "pill",
|
|
2847
|
-
value:
|
|
2848
|
-
tone: statusTone(
|
|
3288
|
+
value: str(record.Status),
|
|
3289
|
+
tone: statusTone(str(record.Status) ?? "")
|
|
2849
3290
|
}
|
|
2850
3291
|
];
|
|
2851
3292
|
}
|
|
@@ -2864,7 +3305,24 @@ var HUMAN_FIELDS = {
|
|
|
2864
3305
|
]
|
|
2865
3306
|
};
|
|
2866
3307
|
function humanInputFields(register, record) {
|
|
2867
|
-
return HUMAN_FIELDS[register].map((f) => ({ key: f.key, label: f.label, text:
|
|
3308
|
+
return HUMAN_FIELDS[register].map((f) => ({ key: f.key, label: f.label, text: str(record[f.key]) ?? "" })).filter((f) => f.text !== "");
|
|
3309
|
+
}
|
|
3310
|
+
function readingBeliefVerdicts(reading, assumptions = []) {
|
|
3311
|
+
const byId = new Map(assumptions.map((a) => [a.id, a]));
|
|
3312
|
+
return readingBeliefs(reading).map((b) => {
|
|
3313
|
+
const hit = byId.get(b.assumptionId);
|
|
3314
|
+
const strength = b.derived && typeof b.derived.strength === "number" ? b.derived.strength : null;
|
|
3315
|
+
return {
|
|
3316
|
+
assumptionId: b.assumptionId,
|
|
3317
|
+
title: hit ? primaryLabel(hit) : b.assumptionId,
|
|
3318
|
+
linked: hit != null,
|
|
3319
|
+
rung: b.Rung ?? null,
|
|
3320
|
+
result: b.Result ?? null,
|
|
3321
|
+
strength,
|
|
3322
|
+
magnitudeBand: b.magnitudeBand ?? null,
|
|
3323
|
+
justification: typeof b["Grading justification"] === "string" ? b["Grading justification"] : ""
|
|
3324
|
+
};
|
|
3325
|
+
});
|
|
2868
3326
|
}
|
|
2869
3327
|
function scoreChip(register, record) {
|
|
2870
3328
|
if (register === "assumptions") {
|
|
@@ -2872,14 +3330,14 @@ function scoreChip(register, record) {
|
|
|
2872
3330
|
return { label: "Confidence", value: formatSigned(c), tone: confidenceTone(c) };
|
|
2873
3331
|
}
|
|
2874
3332
|
if (register === "readings") {
|
|
2875
|
-
const
|
|
3333
|
+
const sq = derivedNum(record, "sourceQuality");
|
|
2876
3334
|
return {
|
|
2877
|
-
label: "
|
|
2878
|
-
value:
|
|
3335
|
+
label: "Source quality",
|
|
3336
|
+
value: sq === null ? "\u2014" : String(Math.round(sq * 100)),
|
|
2879
3337
|
tone: "neutral"
|
|
2880
3338
|
};
|
|
2881
3339
|
}
|
|
2882
|
-
const status =
|
|
3340
|
+
const status = str(record.Status) ?? "\u2014";
|
|
2883
3341
|
return { label: "Status", value: status, tone: statusTone(status) };
|
|
2884
3342
|
}
|
|
2885
3343
|
var PANELS = {
|
|
@@ -2888,7 +3346,7 @@ var PANELS = {
|
|
|
2888
3346
|
id: "readings",
|
|
2889
3347
|
label: "Readings",
|
|
2890
3348
|
register: "readings",
|
|
2891
|
-
resolve: (r, rel) => (rel.readings ?? []).filter((x) => x
|
|
3349
|
+
resolve: (r, rel) => (rel.readings ?? []).filter((x) => readingGrades(x, r.id))
|
|
2892
3350
|
},
|
|
2893
3351
|
{
|
|
2894
3352
|
id: "depends-on",
|
|
@@ -2912,7 +3370,10 @@ var PANELS = {
|
|
|
2912
3370
|
id: "tested-by",
|
|
2913
3371
|
label: "Tested by",
|
|
2914
3372
|
register: "experiments",
|
|
2915
|
-
|
|
3373
|
+
// Archived plans never surface as a relation (OPS-1305) — live plans only.
|
|
3374
|
+
resolve: (r, rel) => liveExperiments(rel.experiments ?? []).filter(
|
|
3375
|
+
(e) => testsAssumption(e, r.id)
|
|
3376
|
+
)
|
|
2916
3377
|
},
|
|
2917
3378
|
{
|
|
2918
3379
|
id: "decisions-based",
|
|
@@ -2930,15 +3391,20 @@ var PANELS = {
|
|
|
2930
3391
|
readings: [
|
|
2931
3392
|
{
|
|
2932
3393
|
id: "assumption",
|
|
2933
|
-
label: "
|
|
3394
|
+
label: "Beliefs",
|
|
2934
3395
|
register: "assumptions",
|
|
2935
|
-
|
|
3396
|
+
// A reading grades several beliefs now (OPS-1305) — resolve them all.
|
|
3397
|
+
resolve: (r, rel) => byIds(rel.assumptions, strList(r.assumptionIds))
|
|
2936
3398
|
},
|
|
2937
3399
|
{
|
|
2938
3400
|
id: "experiment",
|
|
2939
3401
|
label: "Evidence plan",
|
|
2940
3402
|
register: "experiments",
|
|
2941
|
-
|
|
3403
|
+
// Only ever surface a NON-archived plan (OPS-1305): an archived origin
|
|
3404
|
+
// reads as no plan at all, never a leaked backlink.
|
|
3405
|
+
resolve: (r, rel) => byIds(rel.experiments, [str(r.experimentId) ?? ""].filter(Boolean)).filter(
|
|
3406
|
+
(e) => !isArchivedExperiment(e)
|
|
3407
|
+
)
|
|
2942
3408
|
}
|
|
2943
3409
|
],
|
|
2944
3410
|
experiments: [
|
|
@@ -3007,8 +3473,49 @@ function buildRecordPage(register, record, related = {}, options = {}) {
|
|
|
3007
3473
|
};
|
|
3008
3474
|
}
|
|
3009
3475
|
|
|
3476
|
+
// src/belief-verdicts.tsx
|
|
3477
|
+
import { jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
3478
|
+
function resultClass(result) {
|
|
3479
|
+
if (result === "Validated") return "vos-pill vos-pill-good";
|
|
3480
|
+
if (result === "Invalidated") return "vos-pill vos-pill-crit";
|
|
3481
|
+
return "vos-pill vos-pill-neutral";
|
|
3482
|
+
}
|
|
3483
|
+
function BeliefVerdicts({
|
|
3484
|
+
reading,
|
|
3485
|
+
assumptions,
|
|
3486
|
+
onOpenRecord
|
|
3487
|
+
}) {
|
|
3488
|
+
const verdicts = readingBeliefVerdicts(reading, assumptions);
|
|
3489
|
+
if (verdicts.length === 0) {
|
|
3490
|
+
return /* @__PURE__ */ jsx10("p", { className: "vos-hint", children: "This reading grades no beliefs yet." });
|
|
3491
|
+
}
|
|
3492
|
+
return /* @__PURE__ */ jsx10("ul", { className: "vos-verdicts", children: verdicts.map((v) => /* @__PURE__ */ jsxs9("li", { className: "vos-verdict", children: [
|
|
3493
|
+
/* @__PURE__ */ jsxs9("div", { className: "vos-verdict-head", children: [
|
|
3494
|
+
v.linked && onOpenRecord ? /* @__PURE__ */ jsx10(
|
|
3495
|
+
"button",
|
|
3496
|
+
{
|
|
3497
|
+
type: "button",
|
|
3498
|
+
className: "vos-inline-link",
|
|
3499
|
+
onClick: () => onOpenRecord(v.assumptionId),
|
|
3500
|
+
children: v.title
|
|
3501
|
+
}
|
|
3502
|
+
) : /* @__PURE__ */ jsx10("span", { className: "vos-verdict-title", children: v.title }),
|
|
3503
|
+
/* @__PURE__ */ jsx10("span", { className: resultClass(v.result), children: v.result ?? "\u2014" })
|
|
3504
|
+
] }),
|
|
3505
|
+
/* @__PURE__ */ jsxs9("div", { className: "vos-verdict-meta", children: [
|
|
3506
|
+
v.rung ? /* @__PURE__ */ jsx10("span", { className: "vos-chip vos-pill vos-pill-neutral", children: v.rung }) : null,
|
|
3507
|
+
v.magnitudeBand ? /* @__PURE__ */ jsx10("span", { className: "vos-chip vos-pill vos-pill-neutral", children: v.magnitudeBand }) : null,
|
|
3508
|
+
v.strength !== null ? /* @__PURE__ */ jsxs9("span", { className: "vos-verdict-strength", children: [
|
|
3509
|
+
"Strength ",
|
|
3510
|
+
formatSigned(v.strength)
|
|
3511
|
+
] }) : null
|
|
3512
|
+
] }),
|
|
3513
|
+
v.justification ? /* @__PURE__ */ jsx10("p", { className: "vos-verdict-why", children: v.justification }) : null
|
|
3514
|
+
] }, v.assumptionId)) });
|
|
3515
|
+
}
|
|
3516
|
+
|
|
3010
3517
|
// src/record-page.tsx
|
|
3011
|
-
import { Fragment as Fragment8, jsx as
|
|
3518
|
+
import { Fragment as Fragment8, jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
3012
3519
|
var TAB_LABEL = {
|
|
3013
3520
|
overview: "Overview",
|
|
3014
3521
|
evidence: "Evidence",
|
|
@@ -3073,12 +3580,65 @@ function RecordPage({
|
|
|
3073
3580
|
lists.experiments.refresh();
|
|
3074
3581
|
lists.readings.refresh();
|
|
3075
3582
|
lists.decisions.refresh();
|
|
3583
|
+
lists.glossary.refresh();
|
|
3076
3584
|
};
|
|
3077
3585
|
const terms = toGlossaryTerms(related.glossary ?? []);
|
|
3078
3586
|
const openTerm = (id) => onNavigate({ name: "record", id });
|
|
3079
|
-
|
|
3080
|
-
|
|
3081
|
-
|
|
3587
|
+
const [editing, setEditing] = useState5(false);
|
|
3588
|
+
const [draft, setDraft] = useState5({});
|
|
3589
|
+
const [baseline, setBaseline] = useState5(null);
|
|
3590
|
+
const { save, saving, conflict, error: saveError, reset } = useUpdate(
|
|
3591
|
+
register ?? backRegister,
|
|
3592
|
+
basePath
|
|
3593
|
+
);
|
|
3594
|
+
function startEditing() {
|
|
3595
|
+
if (!record || !register) return;
|
|
3596
|
+
setBaseline(record);
|
|
3597
|
+
setDraft(draftFrom(register, record));
|
|
3598
|
+
reset();
|
|
3599
|
+
setEditing(true);
|
|
3600
|
+
}
|
|
3601
|
+
function cancelEditing() {
|
|
3602
|
+
setEditing(false);
|
|
3603
|
+
reset();
|
|
3604
|
+
}
|
|
3605
|
+
async function onSaveEdit() {
|
|
3606
|
+
if (!record || !register || !baseline) return;
|
|
3607
|
+
if (Object.keys(draftErrors(register, draft)).length > 0) return;
|
|
3608
|
+
const patch = buildPatch(register, baseline, draft);
|
|
3609
|
+
patch.version = record.version;
|
|
3610
|
+
if (Object.keys(patch).length <= 1) {
|
|
3611
|
+
setEditing(false);
|
|
3612
|
+
return;
|
|
3613
|
+
}
|
|
3614
|
+
const result = await save(record.id, patch);
|
|
3615
|
+
if (result.ok) {
|
|
3616
|
+
setEditing(false);
|
|
3617
|
+
refreshAll();
|
|
3618
|
+
}
|
|
3619
|
+
}
|
|
3620
|
+
function reloadLatest() {
|
|
3621
|
+
reset();
|
|
3622
|
+
refreshAll();
|
|
3623
|
+
}
|
|
3624
|
+
const setField = (key, value) => setDraft((d) => ({ ...d, [key]: value }));
|
|
3625
|
+
const editErrors = editing && register ? draftErrors(register, draft) : {};
|
|
3626
|
+
const edit = {
|
|
3627
|
+
editing,
|
|
3628
|
+
draft,
|
|
3629
|
+
errors: editErrors,
|
|
3630
|
+
saving,
|
|
3631
|
+
conflict,
|
|
3632
|
+
saveError,
|
|
3633
|
+
onEdit: startEditing,
|
|
3634
|
+
onCancel: cancelEditing,
|
|
3635
|
+
onSave: onSaveEdit,
|
|
3636
|
+
onReload: reloadLatest,
|
|
3637
|
+
onField: setField
|
|
3638
|
+
};
|
|
3639
|
+
return /* @__PURE__ */ jsxs10("div", { children: [
|
|
3640
|
+
/* @__PURE__ */ jsxs10("nav", { className: "vos-crumbs", "aria-label": "Breadcrumb", children: [
|
|
3641
|
+
/* @__PURE__ */ jsx11(
|
|
3082
3642
|
"button",
|
|
3083
3643
|
{
|
|
3084
3644
|
type: "button",
|
|
@@ -3086,14 +3646,14 @@ function RecordPage({
|
|
|
3086
3646
|
children: REGISTER_LABEL[register ?? backRegister]
|
|
3087
3647
|
}
|
|
3088
3648
|
),
|
|
3089
|
-
/* @__PURE__ */
|
|
3090
|
-
/* @__PURE__ */
|
|
3649
|
+
/* @__PURE__ */ jsx11("span", { "aria-hidden": "true", children: "\u203A" }),
|
|
3650
|
+
/* @__PURE__ */ jsx11("span", { className: "vos-rid", children: record ? formatValue(record.Title) : recordId })
|
|
3091
3651
|
] }),
|
|
3092
|
-
anyLoading ? /* @__PURE__ */
|
|
3652
|
+
anyLoading ? /* @__PURE__ */ jsx11("p", { className: "vos-muted", children: "Loading record\u2026" }) : !record || !register ? /* @__PURE__ */ jsxs10("div", { className: "vos-empty", children: [
|
|
3093
3653
|
"Couldn't find a record with id ",
|
|
3094
|
-
/* @__PURE__ */
|
|
3654
|
+
/* @__PURE__ */ jsx11("b", { children: recordId }),
|
|
3095
3655
|
"."
|
|
3096
|
-
] }) : /* @__PURE__ */
|
|
3656
|
+
] }) : /* @__PURE__ */ jsx11(
|
|
3097
3657
|
RecordBody,
|
|
3098
3658
|
{
|
|
3099
3659
|
register,
|
|
@@ -3108,7 +3668,8 @@ function RecordPage({
|
|
|
3108
3668
|
basePath,
|
|
3109
3669
|
journey,
|
|
3110
3670
|
onJourneyChanged: refreshAll,
|
|
3111
|
-
onNavigate
|
|
3671
|
+
onNavigate,
|
|
3672
|
+
edit
|
|
3112
3673
|
}
|
|
3113
3674
|
)
|
|
3114
3675
|
] });
|
|
@@ -3126,25 +3687,37 @@ function RecordBody({
|
|
|
3126
3687
|
basePath,
|
|
3127
3688
|
journey,
|
|
3128
3689
|
onJourneyChanged,
|
|
3129
|
-
onNavigate
|
|
3690
|
+
onNavigate,
|
|
3691
|
+
edit
|
|
3130
3692
|
}) {
|
|
3131
3693
|
const page = buildRecordPage(register, record, related, { asOf });
|
|
3132
3694
|
const activeTab = page.tabs.includes(tab) ? tab : "overview";
|
|
3133
3695
|
const description = typeof record.Description === "string" ? record.Description : "";
|
|
3134
|
-
|
|
3135
|
-
|
|
3136
|
-
|
|
3137
|
-
|
|
3138
|
-
|
|
3139
|
-
/* @__PURE__ */
|
|
3696
|
+
const bodyText = typeof record.body === "string" ? record.body : "";
|
|
3697
|
+
const hasErrors = Object.keys(edit.errors).length > 0;
|
|
3698
|
+
return /* @__PURE__ */ jsxs10(Fragment8, { children: [
|
|
3699
|
+
/* @__PURE__ */ jsxs10("div", { className: "vos-head vos-record-head", children: [
|
|
3700
|
+
/* @__PURE__ */ jsxs10("div", { children: [
|
|
3701
|
+
/* @__PURE__ */ jsx11("p", { className: "vos-drawer-eyebrow", children: REGISTER_SINGULAR[register] }),
|
|
3702
|
+
/* @__PURE__ */ jsx11("h1", { children: page.title }),
|
|
3703
|
+
/* @__PURE__ */ jsx11("div", { className: "vos-pill-row", children: page.pills.map((p, i) => /* @__PURE__ */ jsx11(PillView, { pill: p }, i)) })
|
|
3140
3704
|
] }),
|
|
3141
|
-
/* @__PURE__ */
|
|
3142
|
-
/* @__PURE__ */
|
|
3705
|
+
/* @__PURE__ */ jsx11("div", { className: "vos-spacer" }),
|
|
3706
|
+
/* @__PURE__ */ jsxs10("span", { className: "vos-verbadge", children: [
|
|
3143
3707
|
"v",
|
|
3144
3708
|
formatValue(record.version)
|
|
3145
|
-
] })
|
|
3709
|
+
] }),
|
|
3710
|
+
!edit.editing ? /* @__PURE__ */ jsx11(
|
|
3711
|
+
"button",
|
|
3712
|
+
{
|
|
3713
|
+
type: "button",
|
|
3714
|
+
onClick: edit.onEdit,
|
|
3715
|
+
className: "vos-btn vos-btn-ghost vos-btn-sm",
|
|
3716
|
+
children: "Edit"
|
|
3717
|
+
}
|
|
3718
|
+
) : null
|
|
3146
3719
|
] }),
|
|
3147
|
-
/* @__PURE__ */
|
|
3720
|
+
/* @__PURE__ */ jsx11("div", { className: "vos-tabs", role: "tablist", "aria-label": "Record sections", children: page.tabs.map((t2) => /* @__PURE__ */ jsx11(
|
|
3148
3721
|
"button",
|
|
3149
3722
|
{
|
|
3150
3723
|
type: "button",
|
|
@@ -3156,8 +3729,8 @@ function RecordBody({
|
|
|
3156
3729
|
},
|
|
3157
3730
|
t2
|
|
3158
3731
|
)) }),
|
|
3159
|
-
activeTab === "overview" ? /* @__PURE__ */
|
|
3160
|
-
/* @__PURE__ */
|
|
3732
|
+
activeTab === "overview" ? /* @__PURE__ */ jsxs10("div", { className: "vos-record-cols", children: [
|
|
3733
|
+
/* @__PURE__ */ jsx11("section", { className: "vos-meter-grid", children: page.meters.map((m) => /* @__PURE__ */ jsx11(
|
|
3161
3734
|
MeterView,
|
|
3162
3735
|
{
|
|
3163
3736
|
meter: m,
|
|
@@ -3166,38 +3739,91 @@ function RecordBody({
|
|
|
3166
3739
|
},
|
|
3167
3740
|
m.key
|
|
3168
3741
|
)) }),
|
|
3169
|
-
|
|
3170
|
-
/* @__PURE__ */
|
|
3171
|
-
/* @__PURE__ */
|
|
3172
|
-
|
|
3742
|
+
edit.editing ? /* @__PURE__ */ jsxs10("section", { className: "vos-record-editor", children: [
|
|
3743
|
+
/* @__PURE__ */ jsx11("h3", { className: "vos-section-title", children: "Edit" }),
|
|
3744
|
+
edit.conflict ? /* @__PURE__ */ jsx11(ConflictBanner, { message: edit.conflict, onReload: edit.onReload }) : null,
|
|
3745
|
+
edit.saveError ? /* @__PURE__ */ jsx11("p", { role: "alert", className: "vos-error", children: edit.saveError }) : null,
|
|
3746
|
+
/* @__PURE__ */ jsx11(
|
|
3747
|
+
EditFields,
|
|
3173
3748
|
{
|
|
3174
|
-
|
|
3175
|
-
|
|
3176
|
-
|
|
3177
|
-
|
|
3749
|
+
register,
|
|
3750
|
+
draft: edit.draft,
|
|
3751
|
+
errors: edit.errors,
|
|
3752
|
+
onField: edit.onField
|
|
3178
3753
|
}
|
|
3179
|
-
)
|
|
3180
|
-
|
|
3181
|
-
|
|
3182
|
-
|
|
3183
|
-
|
|
3184
|
-
|
|
3185
|
-
|
|
3186
|
-
|
|
3187
|
-
|
|
3188
|
-
|
|
3754
|
+
),
|
|
3755
|
+
/* @__PURE__ */ jsxs10("footer", { className: "vos-drawer-footer", children: [
|
|
3756
|
+
/* @__PURE__ */ jsx11(
|
|
3757
|
+
"button",
|
|
3758
|
+
{
|
|
3759
|
+
type: "button",
|
|
3760
|
+
onClick: edit.onCancel,
|
|
3761
|
+
disabled: edit.saving,
|
|
3762
|
+
className: "vos-btn vos-btn-ghost vos-btn-sm",
|
|
3763
|
+
children: "Cancel"
|
|
3764
|
+
}
|
|
3765
|
+
),
|
|
3766
|
+
/* @__PURE__ */ jsx11(
|
|
3767
|
+
"button",
|
|
3768
|
+
{
|
|
3769
|
+
type: "button",
|
|
3770
|
+
onClick: edit.onSave,
|
|
3771
|
+
disabled: edit.saving || hasErrors,
|
|
3772
|
+
title: hasErrors ? "Fix the highlighted field before saving" : void 0,
|
|
3773
|
+
className: "vos-btn vos-btn-sm",
|
|
3774
|
+
children: edit.saving ? "Saving\u2026" : "Save"
|
|
3775
|
+
}
|
|
3776
|
+
)
|
|
3777
|
+
] })
|
|
3778
|
+
] }) : /* @__PURE__ */ jsxs10(Fragment8, { children: [
|
|
3779
|
+
description ? /* @__PURE__ */ jsxs10("section", { className: "vos-record-prose", children: [
|
|
3780
|
+
/* @__PURE__ */ jsx11("h3", { className: "vos-section-title", children: "Description" }),
|
|
3781
|
+
/* @__PURE__ */ jsx11("p", { children: /* @__PURE__ */ jsx11(
|
|
3189
3782
|
GlossaryText,
|
|
3190
3783
|
{
|
|
3191
|
-
text:
|
|
3784
|
+
text: description,
|
|
3192
3785
|
terms,
|
|
3193
3786
|
selfId: register === "glossary" ? record.id : void 0,
|
|
3194
3787
|
onOpenTerm
|
|
3195
3788
|
}
|
|
3196
3789
|
) })
|
|
3197
|
-
] },
|
|
3198
|
-
|
|
3790
|
+
] }) : null,
|
|
3791
|
+
bodyText ? /* @__PURE__ */ jsxs10("section", { className: "vos-record-prose", children: [
|
|
3792
|
+
/* @__PURE__ */ jsx11("h3", { className: "vos-section-title", children: register === "readings" ? "Quote" : "Narrative" }),
|
|
3793
|
+
/* @__PURE__ */ jsx11(Markdown, { text: bodyText })
|
|
3794
|
+
] }) : null,
|
|
3795
|
+
register === "readings" ? /* @__PURE__ */ jsxs10("section", { className: "vos-record-prose", children: [
|
|
3796
|
+
/* @__PURE__ */ jsx11("h3", { className: "vos-section-title", children: "Per-belief verdicts" }),
|
|
3797
|
+
/* @__PURE__ */ jsx11(
|
|
3798
|
+
BeliefVerdicts,
|
|
3799
|
+
{
|
|
3800
|
+
reading: record,
|
|
3801
|
+
assumptions: related.assumptions ?? [],
|
|
3802
|
+
onOpenRecord
|
|
3803
|
+
}
|
|
3804
|
+
)
|
|
3805
|
+
] }) : null,
|
|
3806
|
+
page.humanText.length ? /* @__PURE__ */ jsxs10("section", { className: "vos-record-prose", children: [
|
|
3807
|
+
/* @__PURE__ */ jsxs10("h3", { className: "vos-section-title", children: [
|
|
3808
|
+
"From a human ",
|
|
3809
|
+
/* @__PURE__ */ jsx11("span", { className: "vos-hint", children: "\u2014 not computed" })
|
|
3810
|
+
] }),
|
|
3811
|
+
page.humanText.map((h) => /* @__PURE__ */ jsxs10("div", { className: "vos-human-field", children: [
|
|
3812
|
+
/* @__PURE__ */ jsx11("div", { className: "vos-detail-k", children: h.label }),
|
|
3813
|
+
/* @__PURE__ */ jsx11("p", { children: /* @__PURE__ */ jsx11(
|
|
3814
|
+
GlossaryText,
|
|
3815
|
+
{
|
|
3816
|
+
text: h.text,
|
|
3817
|
+
terms,
|
|
3818
|
+
selfId: register === "glossary" ? record.id : void 0,
|
|
3819
|
+
onOpenTerm
|
|
3820
|
+
}
|
|
3821
|
+
) })
|
|
3822
|
+
] }, h.key))
|
|
3823
|
+
] }) : null
|
|
3824
|
+
] })
|
|
3199
3825
|
] }) : null,
|
|
3200
|
-
activeTab === "evidence" ? /* @__PURE__ */
|
|
3826
|
+
activeTab === "evidence" ? /* @__PURE__ */ jsx11(
|
|
3201
3827
|
EvidenceTab,
|
|
3202
3828
|
{
|
|
3203
3829
|
register,
|
|
@@ -3207,25 +3833,25 @@ function RecordBody({
|
|
|
3207
3833
|
basePath
|
|
3208
3834
|
}
|
|
3209
3835
|
) : null,
|
|
3210
|
-
activeTab === "connections" ? /* @__PURE__ */
|
|
3211
|
-
activeTab === "history" ? /* @__PURE__ */
|
|
3212
|
-
/* @__PURE__ */
|
|
3213
|
-
/* @__PURE__ */
|
|
3214
|
-
/* @__PURE__ */
|
|
3836
|
+
activeTab === "connections" ? /* @__PURE__ */ jsx11("div", { className: "vos-panels", children: page.panels.map((panel) => /* @__PURE__ */ jsx11(PanelView, { panel, onOpenRecord }, panel.id)) }) : null,
|
|
3837
|
+
activeTab === "history" ? /* @__PURE__ */ jsxs10("section", { className: "vos-detail-list", children: [
|
|
3838
|
+
/* @__PURE__ */ jsxs10("div", { className: "vos-detail-row", children: [
|
|
3839
|
+
/* @__PURE__ */ jsx11("span", { className: "vos-detail-k", children: "Created" }),
|
|
3840
|
+
/* @__PURE__ */ jsx11("span", { className: "vos-detail-v", children: formatValue(record.createdAt) })
|
|
3215
3841
|
] }),
|
|
3216
|
-
/* @__PURE__ */
|
|
3217
|
-
/* @__PURE__ */
|
|
3218
|
-
/* @__PURE__ */
|
|
3842
|
+
/* @__PURE__ */ jsxs10("div", { className: "vos-detail-row", children: [
|
|
3843
|
+
/* @__PURE__ */ jsx11("span", { className: "vos-detail-k", children: "Last updated" }),
|
|
3844
|
+
/* @__PURE__ */ jsx11("span", { className: "vos-detail-v", children: formatValue(record.updatedAt) })
|
|
3219
3845
|
] }),
|
|
3220
|
-
/* @__PURE__ */
|
|
3221
|
-
/* @__PURE__ */
|
|
3222
|
-
/* @__PURE__ */
|
|
3846
|
+
/* @__PURE__ */ jsxs10("div", { className: "vos-detail-row", children: [
|
|
3847
|
+
/* @__PURE__ */ jsx11("span", { className: "vos-detail-k", children: "Version" }),
|
|
3848
|
+
/* @__PURE__ */ jsx11("span", { className: "vos-detail-v", children: formatValue(record.version) })
|
|
3223
3849
|
] }),
|
|
3224
|
-
/* @__PURE__ */
|
|
3850
|
+
/* @__PURE__ */ jsx11("p", { className: "vos-hint", children: "The full change trail lands here as the API exposes version history; this absorbs the retired provenance prose." })
|
|
3225
3851
|
] }) : null,
|
|
3226
|
-
page.hasJourney && journey ? /* @__PURE__ */
|
|
3227
|
-
/* @__PURE__ */
|
|
3228
|
-
/* @__PURE__ */
|
|
3852
|
+
page.hasJourney && journey ? /* @__PURE__ */ jsxs10("section", { className: "vos-journey-host", children: [
|
|
3853
|
+
/* @__PURE__ */ jsx11("h3", { className: "vos-section-title", children: "Validation journey" }),
|
|
3854
|
+
/* @__PURE__ */ jsx11(
|
|
3229
3855
|
BeliefJourney,
|
|
3230
3856
|
{
|
|
3231
3857
|
journey,
|
|
@@ -3235,14 +3861,23 @@ function RecordBody({
|
|
|
3235
3861
|
onChanged: onJourneyChanged
|
|
3236
3862
|
}
|
|
3237
3863
|
)
|
|
3238
|
-
] }) : page.hasJourney ? /* @__PURE__ */
|
|
3239
|
-
/* @__PURE__ */
|
|
3240
|
-
/* @__PURE__ */
|
|
3864
|
+
] }) : page.hasJourney ? /* @__PURE__ */ jsxs10("section", { className: "vos-journey-host", children: [
|
|
3865
|
+
/* @__PURE__ */ jsx11("h3", { className: "vos-section-title", children: "Validation journey" }),
|
|
3866
|
+
/* @__PURE__ */ jsx11("p", { className: "vos-hint", children: "The per-belief journey (Framed \u2192 Planned \u2192 Tested \u2192 Known) mounts here \u2014 built by the workflow-first map (OPS-1289). This page is its host." })
|
|
3241
3867
|
] }) : null
|
|
3242
3868
|
] });
|
|
3243
3869
|
}
|
|
3244
3870
|
function PillView({ pill }) {
|
|
3245
|
-
return /* @__PURE__ */
|
|
3871
|
+
return /* @__PURE__ */ jsx11("span", { className: PILL_CLASS3[pill.tone], children: pill.label });
|
|
3872
|
+
}
|
|
3873
|
+
function ConflictBanner({
|
|
3874
|
+
message,
|
|
3875
|
+
onReload
|
|
3876
|
+
}) {
|
|
3877
|
+
return /* @__PURE__ */ jsxs10("div", { role: "alert", className: "vos-banner vos-banner-warn", children: [
|
|
3878
|
+
/* @__PURE__ */ jsx11("div", { className: "vos-banner-body", children: /* @__PURE__ */ jsx11("span", { children: message }) }),
|
|
3879
|
+
/* @__PURE__ */ jsx11("button", { type: "button", onClick: onReload, children: "Review the latest" })
|
|
3880
|
+
] });
|
|
3246
3881
|
}
|
|
3247
3882
|
function MeterView({
|
|
3248
3883
|
meter,
|
|
@@ -3251,10 +3886,10 @@ function MeterView({
|
|
|
3251
3886
|
}) {
|
|
3252
3887
|
const [why, setWhy] = useState5(false);
|
|
3253
3888
|
const textTone = meter.tone === "crit" ? "vos-text-crit" : meter.tone === "warn" ? "vos-text-warn" : "";
|
|
3254
|
-
return /* @__PURE__ */
|
|
3255
|
-
/* @__PURE__ */
|
|
3256
|
-
/* @__PURE__ */
|
|
3257
|
-
meter.hasWhy && assumption ? /* @__PURE__ */
|
|
3889
|
+
return /* @__PURE__ */ jsxs10("div", { className: "vos-meter", children: [
|
|
3890
|
+
/* @__PURE__ */ jsxs10("div", { className: "vos-meter-head", children: [
|
|
3891
|
+
/* @__PURE__ */ jsx11("span", { className: "vos-meter-label", children: meter.label }),
|
|
3892
|
+
meter.hasWhy && assumption ? /* @__PURE__ */ jsxs10(
|
|
3258
3893
|
"button",
|
|
3259
3894
|
{
|
|
3260
3895
|
type: "button",
|
|
@@ -3268,12 +3903,12 @@ function MeterView({
|
|
|
3268
3903
|
}
|
|
3269
3904
|
) : null
|
|
3270
3905
|
] }),
|
|
3271
|
-
meter.value === null ? /* @__PURE__ */
|
|
3272
|
-
/* @__PURE__ */
|
|
3273
|
-
/* @__PURE__ */
|
|
3274
|
-
] }) : /* @__PURE__ */
|
|
3275
|
-
/* @__PURE__ */
|
|
3276
|
-
/* @__PURE__ */
|
|
3906
|
+
meter.value === null ? /* @__PURE__ */ jsx11("div", { className: "vos-meter-val vos-muted", children: "\u2014" }) : meter.kind === "pill" ? /* @__PURE__ */ jsx11("span", { className: PILL_CLASS3[meter.tone], children: meter.value }) : meter.kind === "signed" ? /* @__PURE__ */ jsxs10(Fragment8, { children: [
|
|
3907
|
+
/* @__PURE__ */ jsx11("div", { className: `vos-meter-val ${textTone}`, children: formatSigned(Number(meter.value)) }),
|
|
3908
|
+
/* @__PURE__ */ jsx11("span", { className: "vos-track vos-signed", children: /* @__PURE__ */ jsx11(SignedFill, { value: Number(meter.value), min: meter.min ?? -100, max: meter.max ?? 100 }) })
|
|
3909
|
+
] }) : /* @__PURE__ */ jsxs10(Fragment8, { children: [
|
|
3910
|
+
/* @__PURE__ */ jsx11("div", { className: `vos-meter-val ${textTone}`, children: Math.round(Number(meter.value)) }),
|
|
3911
|
+
/* @__PURE__ */ jsx11("span", { className: "vos-risk-bar", children: /* @__PURE__ */ jsx11(
|
|
3277
3912
|
"i",
|
|
3278
3913
|
{
|
|
3279
3914
|
className: meter.tone === "crit" ? "vos-fill-crit" : meter.tone === "warn" ? "vos-fill-warn" : "vos-fill-good",
|
|
@@ -3281,7 +3916,7 @@ function MeterView({
|
|
|
3281
3916
|
}
|
|
3282
3917
|
) })
|
|
3283
3918
|
] }),
|
|
3284
|
-
why && assumption ? /* @__PURE__ */
|
|
3919
|
+
why && assumption ? /* @__PURE__ */ jsx11("div", { className: "vos-why-panel", children: /* @__PURE__ */ jsx11(UnderstandingPanel, { assumption, basePath }) }) : null
|
|
3285
3920
|
] });
|
|
3286
3921
|
}
|
|
3287
3922
|
function SignedFill({ value, min, max }) {
|
|
@@ -3289,34 +3924,34 @@ function SignedFill({ value, min, max }) {
|
|
|
3289
3924
|
const width = Math.round(Math.min(Math.abs(value), span) / span * 50);
|
|
3290
3925
|
const up = value >= 0;
|
|
3291
3926
|
const style = up ? { left: "50%", width: `${width}%`, background: "var(--vos-good)" } : { right: "50%", width: `${width}%`, background: "var(--vos-crit)" };
|
|
3292
|
-
return width > 0 ? /* @__PURE__ */
|
|
3927
|
+
return width > 0 ? /* @__PURE__ */ jsx11("i", { style }) : null;
|
|
3293
3928
|
}
|
|
3294
3929
|
function PanelView({
|
|
3295
3930
|
panel,
|
|
3296
3931
|
onOpenRecord
|
|
3297
3932
|
}) {
|
|
3298
|
-
return /* @__PURE__ */
|
|
3299
|
-
/* @__PURE__ */
|
|
3933
|
+
return /* @__PURE__ */ jsxs10("section", { className: "vos-panel", children: [
|
|
3934
|
+
/* @__PURE__ */ jsxs10("h3", { className: "vos-panel-head", children: [
|
|
3300
3935
|
panel.label,
|
|
3301
|
-
/* @__PURE__ */
|
|
3936
|
+
/* @__PURE__ */ jsx11("span", { className: "vos-group-n", children: panel.items.length })
|
|
3302
3937
|
] }),
|
|
3303
|
-
panel.items.length === 0 ? /* @__PURE__ */
|
|
3938
|
+
panel.items.length === 0 ? /* @__PURE__ */ jsx11("p", { className: "vos-hint", children: "None yet." }) : /* @__PURE__ */ jsx11("ul", { className: "vos-backlinks", children: panel.items.map((item) => /* @__PURE__ */ jsx11(BacklinkRow, { item, onOpenRecord }, item.id)) })
|
|
3304
3939
|
] });
|
|
3305
3940
|
}
|
|
3306
3941
|
function BacklinkRow({
|
|
3307
3942
|
item,
|
|
3308
3943
|
onOpenRecord
|
|
3309
3944
|
}) {
|
|
3310
|
-
return /* @__PURE__ */
|
|
3945
|
+
return /* @__PURE__ */ jsx11("li", { children: /* @__PURE__ */ jsxs10(
|
|
3311
3946
|
"button",
|
|
3312
3947
|
{
|
|
3313
3948
|
type: "button",
|
|
3314
3949
|
className: "vos-backlink",
|
|
3315
3950
|
onClick: () => onOpenRecord(item.id),
|
|
3316
3951
|
children: [
|
|
3317
|
-
/* @__PURE__ */
|
|
3318
|
-
/* @__PURE__ */
|
|
3319
|
-
/* @__PURE__ */
|
|
3952
|
+
/* @__PURE__ */ jsx11("span", { className: "vos-backlink-title", children: item.title }),
|
|
3953
|
+
/* @__PURE__ */ jsxs10("span", { className: `vos-chip ${PILL_CLASS3[item.chip.tone]}`, children: [
|
|
3954
|
+
/* @__PURE__ */ jsx11("span", { className: "vos-chip-k", children: item.chip.label }),
|
|
3320
3955
|
item.chip.value
|
|
3321
3956
|
] })
|
|
3322
3957
|
]
|
|
@@ -3331,17 +3966,29 @@ function EvidenceTab({
|
|
|
3331
3966
|
basePath
|
|
3332
3967
|
}) {
|
|
3333
3968
|
if (register === "assumptions") {
|
|
3334
|
-
return /* @__PURE__ */
|
|
3969
|
+
return /* @__PURE__ */ jsx11("section", { className: "vos-why-panel", children: /* @__PURE__ */ jsx11(UnderstandingPanel, { assumption: record, basePath }) });
|
|
3335
3970
|
}
|
|
3336
|
-
const bars =
|
|
3971
|
+
const bars = resolveBarLines(
|
|
3972
|
+
record.barLines ?? [],
|
|
3973
|
+
related
|
|
3974
|
+
);
|
|
3337
3975
|
const mine = (related.readings ?? []).filter((r) => r.experimentId === record.id);
|
|
3338
3976
|
const nested = nestReadingsByPlan(mine, [record]);
|
|
3339
|
-
return /* @__PURE__ */
|
|
3340
|
-
/* @__PURE__ */
|
|
3341
|
-
/* @__PURE__ */
|
|
3342
|
-
bars.length === 0 ? /* @__PURE__ */
|
|
3343
|
-
/* @__PURE__ */
|
|
3344
|
-
/* @__PURE__ */
|
|
3977
|
+
return /* @__PURE__ */ jsxs10("div", { className: "vos-record-cols", children: [
|
|
3978
|
+
/* @__PURE__ */ jsxs10("section", { children: [
|
|
3979
|
+
/* @__PURE__ */ jsx11("h3", { className: "vos-section-title", children: "Bar lines" }),
|
|
3980
|
+
bars.length === 0 ? /* @__PURE__ */ jsx11("p", { className: "vos-hint", children: "No pre-registered bars." }) : /* @__PURE__ */ jsx11("ul", { className: "vos-bars", children: bars.map((b, i) => /* @__PURE__ */ jsxs10("li", { className: "vos-bar-line", children: [
|
|
3981
|
+
/* @__PURE__ */ jsx11("span", { className: "vos-bar-if", children: b.rightIf || "\u2014" }),
|
|
3982
|
+
b.assumption ? /* @__PURE__ */ jsx11(
|
|
3983
|
+
"button",
|
|
3984
|
+
{
|
|
3985
|
+
type: "button",
|
|
3986
|
+
className: "vos-inline-link",
|
|
3987
|
+
onClick: () => onOpenRecord(b.assumption.id),
|
|
3988
|
+
children: b.assumption.title
|
|
3989
|
+
}
|
|
3990
|
+
) : null,
|
|
3991
|
+
/* @__PURE__ */ jsx11(
|
|
3345
3992
|
"span",
|
|
3346
3993
|
{
|
|
3347
3994
|
className: b.barVerdict ? "vos-pill vos-pill-good" : "vos-pill vos-pill-neutral",
|
|
@@ -3350,17 +3997,21 @@ function EvidenceTab({
|
|
|
3350
3997
|
)
|
|
3351
3998
|
] }, i)) })
|
|
3352
3999
|
] }),
|
|
3353
|
-
/* @__PURE__ */
|
|
3354
|
-
/* @__PURE__ */
|
|
3355
|
-
nested.length === 0 ? /* @__PURE__ */
|
|
4000
|
+
/* @__PURE__ */ jsxs10("section", { children: [
|
|
4001
|
+
/* @__PURE__ */ jsx11("h3", { className: "vos-section-title", children: "Readings" }),
|
|
4002
|
+
nested.length === 0 ? /* @__PURE__ */ jsx11("p", { className: "vos-hint", children: "No readings logged yet." }) : /* @__PURE__ */ jsx11("ul", { className: "vos-backlinks", children: nested[0].readings.map((r) => /* @__PURE__ */ jsx11("li", { children: /* @__PURE__ */ jsxs10(
|
|
3356
4003
|
"button",
|
|
3357
4004
|
{
|
|
3358
4005
|
type: "button",
|
|
3359
4006
|
className: "vos-backlink",
|
|
3360
4007
|
onClick: () => onOpenRecord(r.id),
|
|
3361
4008
|
children: [
|
|
3362
|
-
/* @__PURE__ */
|
|
3363
|
-
/* @__PURE__ */
|
|
4009
|
+
/* @__PURE__ */ jsx11("span", { className: "vos-backlink-title", children: formatValue(r.Title) }),
|
|
4010
|
+
/* @__PURE__ */ jsxs10("span", { className: "vos-chip vos-pill vos-pill-neutral", children: [
|
|
4011
|
+
readingBeliefs(r).length,
|
|
4012
|
+
" belief",
|
|
4013
|
+
readingBeliefs(r).length === 1 ? "" : "s"
|
|
4014
|
+
] })
|
|
3364
4015
|
]
|
|
3365
4016
|
}
|
|
3366
4017
|
) }, r.id)) })
|
|
@@ -3372,19 +4023,20 @@ function EvidenceTab({
|
|
|
3372
4023
|
import { useMemo as useMemo4, useState as useState10 } from "react";
|
|
3373
4024
|
|
|
3374
4025
|
// src/register-table.tsx
|
|
3375
|
-
import { jsx as
|
|
4026
|
+
import { jsx as jsx12, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
3376
4027
|
function RegisterTable({
|
|
3377
4028
|
register,
|
|
3378
4029
|
records,
|
|
3379
4030
|
onRowClick,
|
|
3380
|
-
selectedId
|
|
4031
|
+
selectedId,
|
|
4032
|
+
assumptionTitles
|
|
3381
4033
|
}) {
|
|
3382
4034
|
const columns = columnsFor(register);
|
|
3383
4035
|
if (records.length === 0) {
|
|
3384
|
-
return /* @__PURE__ */
|
|
4036
|
+
return /* @__PURE__ */ jsx12("p", { className: "vos-empty", children: "No records yet." });
|
|
3385
4037
|
}
|
|
3386
|
-
return /* @__PURE__ */
|
|
3387
|
-
/* @__PURE__ */
|
|
4038
|
+
return /* @__PURE__ */ jsx12("div", { className: "vos-card vos-table-scroll", children: /* @__PURE__ */ jsxs11("table", { className: "vos-table", children: [
|
|
4039
|
+
/* @__PURE__ */ jsx12("thead", { children: /* @__PURE__ */ jsx12("tr", { children: columns.map((c) => /* @__PURE__ */ jsx12(
|
|
3388
4040
|
"th",
|
|
3389
4041
|
{
|
|
3390
4042
|
scope: "col",
|
|
@@ -3393,9 +4045,9 @@ function RegisterTable({
|
|
|
3393
4045
|
},
|
|
3394
4046
|
c.key
|
|
3395
4047
|
)) }) }),
|
|
3396
|
-
/* @__PURE__ */
|
|
4048
|
+
/* @__PURE__ */ jsx12("tbody", { children: records.map((record) => {
|
|
3397
4049
|
const isSelected = record.id === selectedId;
|
|
3398
|
-
return /* @__PURE__ */
|
|
4050
|
+
return /* @__PURE__ */ jsx12(
|
|
3399
4051
|
"tr",
|
|
3400
4052
|
{
|
|
3401
4053
|
onClick: () => onRowClick?.(record.id),
|
|
@@ -3408,11 +4060,19 @@ function RegisterTable({
|
|
|
3408
4060
|
tabIndex: onRowClick ? 0 : void 0,
|
|
3409
4061
|
"aria-selected": isSelected,
|
|
3410
4062
|
className: isSelected ? "is-selected" : void 0,
|
|
3411
|
-
children: columns.map((c, i) => /* @__PURE__ */
|
|
4063
|
+
children: columns.map((c, i) => /* @__PURE__ */ jsx12(
|
|
3412
4064
|
"td",
|
|
3413
4065
|
{
|
|
3414
4066
|
className: c.align === "right" ? "vos-r" : void 0,
|
|
3415
|
-
children: /* @__PURE__ */
|
|
4067
|
+
children: /* @__PURE__ */ jsx12(
|
|
4068
|
+
Cell,
|
|
4069
|
+
{
|
|
4070
|
+
column: c,
|
|
4071
|
+
record,
|
|
4072
|
+
headline: i === 0,
|
|
4073
|
+
chips: i === 0 && register === "readings" ? readingAssumptionChips(record, assumptionTitles) : void 0
|
|
4074
|
+
}
|
|
4075
|
+
)
|
|
3416
4076
|
},
|
|
3417
4077
|
c.key
|
|
3418
4078
|
))
|
|
@@ -3425,26 +4085,32 @@ function RegisterTable({
|
|
|
3425
4085
|
function Cell({
|
|
3426
4086
|
column,
|
|
3427
4087
|
record,
|
|
3428
|
-
headline
|
|
4088
|
+
headline,
|
|
4089
|
+
chips
|
|
3429
4090
|
}) {
|
|
3430
4091
|
const raw = cellValue(column, record);
|
|
3431
4092
|
if (column.kind === "status") {
|
|
3432
|
-
return /* @__PURE__ */
|
|
4093
|
+
return /* @__PURE__ */ jsx12(StatusPill, { status: raw == null ? null : String(raw) });
|
|
3433
4094
|
}
|
|
3434
4095
|
if (column.kind === "risk") {
|
|
3435
|
-
return typeof raw === "number" ? /* @__PURE__ */
|
|
4096
|
+
return typeof raw === "number" ? /* @__PURE__ */ jsx12(RiskBar, { risk: raw }) : /* @__PURE__ */ jsx12("span", { className: "vos-muted", children: "\u2014" });
|
|
3436
4097
|
}
|
|
3437
4098
|
if (column.kind === "confidence") {
|
|
3438
|
-
return typeof raw === "number" ? /* @__PURE__ */
|
|
4099
|
+
return typeof raw === "number" ? /* @__PURE__ */ jsx12(ConfidenceCell, { confidence: raw }) : /* @__PURE__ */ jsx12("span", { className: "vos-muted", children: "\u2014" });
|
|
3439
4100
|
}
|
|
3440
4101
|
const text = headline && (raw === null || raw === void 0 || raw === "") ? primaryLabel(record) : formatValue(raw);
|
|
3441
|
-
|
|
4102
|
+
if (headline && chips && chips.length > 0) {
|
|
4103
|
+
return /* @__PURE__ */ jsxs11("span", { className: "vos-ttl-wrap", children: [
|
|
4104
|
+
/* @__PURE__ */ jsx12("span", { className: "vos-ttl", children: text }),
|
|
4105
|
+
/* @__PURE__ */ jsx12("span", { className: "vos-reading-chips", children: chips.map((chip, n) => /* @__PURE__ */ jsx12("span", { className: "vos-chip vos-pill vos-pill-neutral", children: chip }, n)) })
|
|
4106
|
+
] });
|
|
4107
|
+
}
|
|
4108
|
+
return /* @__PURE__ */ jsx12("span", { className: headline ? "vos-ttl" : void 0, children: text });
|
|
3442
4109
|
}
|
|
3443
4110
|
|
|
3444
4111
|
// src/record-drawer.tsx
|
|
3445
4112
|
import { useEffect as useEffect3, useState as useState6 } from "react";
|
|
3446
|
-
import { Fragment as Fragment9, jsx as
|
|
3447
|
-
var META_FIELDS = /* @__PURE__ */ new Set(["id", "version", "createdAt", "updatedAt", "derived"]);
|
|
4113
|
+
import { Fragment as Fragment9, jsx as jsx13, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
3448
4114
|
var DERIVED_SUB = {
|
|
3449
4115
|
confidence: "Signed average of concluded readings",
|
|
3450
4116
|
risk: "Impact \xD7 (1 \u2212 Confidence\u207A/100)",
|
|
@@ -3463,6 +4129,8 @@ function RecordDrawer({
|
|
|
3463
4129
|
basePath,
|
|
3464
4130
|
onChanged,
|
|
3465
4131
|
onOpenFull,
|
|
4132
|
+
onOpenRecord,
|
|
4133
|
+
related,
|
|
3466
4134
|
children
|
|
3467
4135
|
}) {
|
|
3468
4136
|
const [editing, setEditing] = useState6(false);
|
|
@@ -3481,7 +4149,7 @@ function RecordDrawer({
|
|
|
3481
4149
|
reset();
|
|
3482
4150
|
}, [recordId, reset]);
|
|
3483
4151
|
const derived = record && record.derived && typeof record.derived === "object" ? record.derived : null;
|
|
3484
|
-
const
|
|
4152
|
+
const rows = record ? detailRows(register, record, related ?? {}) : [];
|
|
3485
4153
|
function startEditing() {
|
|
3486
4154
|
if (!record) return;
|
|
3487
4155
|
setBaseline(record);
|
|
@@ -3495,6 +4163,7 @@ function RecordDrawer({
|
|
|
3495
4163
|
}
|
|
3496
4164
|
async function onSave() {
|
|
3497
4165
|
if (!record || !baseline) return;
|
|
4166
|
+
if (Object.keys(draftErrors(register, draft)).length > 0) return;
|
|
3498
4167
|
const patch = buildPatch(register, baseline, draft);
|
|
3499
4168
|
patch.version = record.version;
|
|
3500
4169
|
if (Object.keys(patch).length <= 1) {
|
|
@@ -3512,23 +4181,25 @@ function RecordDrawer({
|
|
|
3512
4181
|
onChanged?.();
|
|
3513
4182
|
}
|
|
3514
4183
|
const setField = (key, value) => setDraft((d) => ({ ...d, [key]: value }));
|
|
3515
|
-
|
|
4184
|
+
const errors = editing ? draftErrors(register, draft) : {};
|
|
4185
|
+
const hasErrors = Object.keys(errors).length > 0;
|
|
4186
|
+
return /* @__PURE__ */ jsxs12(
|
|
3516
4187
|
DrawerShell,
|
|
3517
4188
|
{
|
|
3518
4189
|
open,
|
|
3519
4190
|
onClose,
|
|
3520
4191
|
ariaLabel: `${REGISTER_LABEL[register]} record`,
|
|
3521
4192
|
children: [
|
|
3522
|
-
/* @__PURE__ */
|
|
3523
|
-
/* @__PURE__ */
|
|
3524
|
-
/* @__PURE__ */
|
|
3525
|
-
/* @__PURE__ */
|
|
4193
|
+
/* @__PURE__ */ jsxs12("header", { className: "vos-drawer-header", children: [
|
|
4194
|
+
/* @__PURE__ */ jsxs12("div", { style: { flex: 1, minWidth: 0 }, children: [
|
|
4195
|
+
/* @__PURE__ */ jsx13("p", { className: "vos-drawer-eyebrow", children: REGISTER_LABEL[register] }),
|
|
4196
|
+
/* @__PURE__ */ jsx13("h2", { className: "vos-drawer-title", children: record ? primaryLabel(record) : loading ? "Loading\u2026" : "\u2014" })
|
|
3526
4197
|
] }),
|
|
3527
|
-
record ? /* @__PURE__ */
|
|
4198
|
+
record ? /* @__PURE__ */ jsxs12("span", { className: "vos-verbadge", children: [
|
|
3528
4199
|
"v",
|
|
3529
4200
|
formatValue(record.version)
|
|
3530
4201
|
] }) : null,
|
|
3531
|
-
record && !editing && onOpenFull ? /* @__PURE__ */
|
|
4202
|
+
record && !editing && onOpenFull ? /* @__PURE__ */ jsx13(
|
|
3532
4203
|
"button",
|
|
3533
4204
|
{
|
|
3534
4205
|
type: "button",
|
|
@@ -3537,7 +4208,7 @@ function RecordDrawer({
|
|
|
3537
4208
|
children: "Full page \u2197"
|
|
3538
4209
|
}
|
|
3539
4210
|
) : null,
|
|
3540
|
-
record && !editing ? /* @__PURE__ */
|
|
4211
|
+
record && !editing ? /* @__PURE__ */ jsx13(
|
|
3541
4212
|
"button",
|
|
3542
4213
|
{
|
|
3543
4214
|
type: "button",
|
|
@@ -3546,7 +4217,7 @@ function RecordDrawer({
|
|
|
3546
4217
|
children: "Edit"
|
|
3547
4218
|
}
|
|
3548
4219
|
) : null,
|
|
3549
|
-
/* @__PURE__ */
|
|
4220
|
+
/* @__PURE__ */ jsx13(
|
|
3550
4221
|
"button",
|
|
3551
4222
|
{
|
|
3552
4223
|
type: "button",
|
|
@@ -3557,14 +4228,14 @@ function RecordDrawer({
|
|
|
3557
4228
|
}
|
|
3558
4229
|
)
|
|
3559
4230
|
] }),
|
|
3560
|
-
/* @__PURE__ */
|
|
3561
|
-
derived ? /* @__PURE__ */
|
|
3562
|
-
/* @__PURE__ */
|
|
3563
|
-
/* @__PURE__ */
|
|
4231
|
+
/* @__PURE__ */ jsx13("div", { className: "vos-drawer-body", children: loading ? /* @__PURE__ */ jsx13("p", { className: "vos-muted", children: "Loading record\u2026" }) : error ? /* @__PURE__ */ jsx13("p", { className: "vos-error", children: error }) : !record ? /* @__PURE__ */ jsx13("p", { className: "vos-muted", children: "No record." }) : /* @__PURE__ */ jsxs12(Fragment9, { children: [
|
|
4232
|
+
derived ? /* @__PURE__ */ jsxs12("div", { children: [
|
|
4233
|
+
/* @__PURE__ */ jsxs12("div", { className: "vos-derived", children: [
|
|
4234
|
+
/* @__PURE__ */ jsxs12("div", { className: "vos-derived-head", children: [
|
|
3564
4235
|
"Derived",
|
|
3565
|
-
/* @__PURE__ */
|
|
4236
|
+
/* @__PURE__ */ jsx13("span", { className: "vos-lock", children: "\u{1F512} computed on write \u2014 not editable" })
|
|
3566
4237
|
] }),
|
|
3567
|
-
/* @__PURE__ */
|
|
4238
|
+
/* @__PURE__ */ jsx13("div", { className: "vos-dgrid", children: Object.entries(derived).map(([key, value]) => /* @__PURE__ */ jsx13(
|
|
3568
4239
|
DerivedCell,
|
|
3569
4240
|
{
|
|
3570
4241
|
field: key,
|
|
@@ -3576,25 +4247,47 @@ function RecordDrawer({
|
|
|
3576
4247
|
key
|
|
3577
4248
|
)) })
|
|
3578
4249
|
] }),
|
|
3579
|
-
"confidence" in derived && why ? /* @__PURE__ */
|
|
4250
|
+
"confidence" in derived && why ? /* @__PURE__ */ jsx13("div", { className: "vos-why-panel", children: /* @__PURE__ */ jsx13(UnderstandingPanel, { assumption: record, basePath }) }) : null
|
|
3580
4251
|
] }) : null,
|
|
3581
|
-
conflict ? /* @__PURE__ */
|
|
3582
|
-
saveError ? /* @__PURE__ */
|
|
3583
|
-
editing ? /* @__PURE__ */
|
|
4252
|
+
conflict ? /* @__PURE__ */ jsx13(ConflictBanner2, { message: conflict, onReload: reloadLatest }) : null,
|
|
4253
|
+
saveError ? /* @__PURE__ */ jsx13("p", { role: "alert", className: "vos-banner vos-banner-crit", children: saveError }) : null,
|
|
4254
|
+
editing ? /* @__PURE__ */ jsx13(
|
|
3584
4255
|
EditFields,
|
|
3585
4256
|
{
|
|
3586
4257
|
register,
|
|
3587
4258
|
draft,
|
|
4259
|
+
errors,
|
|
3588
4260
|
onField: setField
|
|
3589
4261
|
}
|
|
3590
|
-
) : /* @__PURE__ */
|
|
3591
|
-
/* @__PURE__ */
|
|
3592
|
-
|
|
3593
|
-
|
|
4262
|
+
) : /* @__PURE__ */ jsxs12(Fragment9, { children: [
|
|
4263
|
+
/* @__PURE__ */ jsx13("div", { className: "vos-detail-list", children: rows.map((row) => /* @__PURE__ */ jsx13(
|
|
4264
|
+
DetailRowView,
|
|
4265
|
+
{
|
|
4266
|
+
row,
|
|
4267
|
+
onOpenRecord
|
|
4268
|
+
},
|
|
4269
|
+
row.key
|
|
4270
|
+
)) }),
|
|
4271
|
+
typeof record.body === "string" && record.body.trim() ? /* @__PURE__ */ jsxs12("section", { className: "vos-record-prose", children: [
|
|
4272
|
+
/* @__PURE__ */ jsx13("div", { className: "vos-detail-k", children: register === "readings" ? "Quote" : "Narrative" }),
|
|
4273
|
+
/* @__PURE__ */ jsx13(Markdown, { text: record.body })
|
|
4274
|
+
] }) : null,
|
|
4275
|
+
register === "readings" ? /* @__PURE__ */ jsxs12("section", { className: "vos-record-prose", children: [
|
|
4276
|
+
/* @__PURE__ */ jsx13("div", { className: "vos-detail-k", children: "Per-belief verdicts" }),
|
|
4277
|
+
/* @__PURE__ */ jsx13(
|
|
4278
|
+
BeliefVerdicts,
|
|
4279
|
+
{
|
|
4280
|
+
reading: record,
|
|
4281
|
+
assumptions: related?.assumptions ?? [],
|
|
4282
|
+
onOpenRecord
|
|
4283
|
+
}
|
|
4284
|
+
)
|
|
4285
|
+
] }) : null
|
|
4286
|
+
] })
|
|
3594
4287
|
] }) }),
|
|
3595
4288
|
record && !loading && !error && !editing ? children : null,
|
|
3596
|
-
record && editing ? /* @__PURE__ */
|
|
3597
|
-
/* @__PURE__ */
|
|
4289
|
+
record && editing ? /* @__PURE__ */ jsxs12("footer", { className: "vos-drawer-footer", children: [
|
|
4290
|
+
/* @__PURE__ */ jsx13(
|
|
3598
4291
|
"button",
|
|
3599
4292
|
{
|
|
3600
4293
|
type: "button",
|
|
@@ -3604,17 +4297,18 @@ function RecordDrawer({
|
|
|
3604
4297
|
children: "Cancel"
|
|
3605
4298
|
}
|
|
3606
4299
|
),
|
|
3607
|
-
/* @__PURE__ */
|
|
4300
|
+
/* @__PURE__ */ jsx13(
|
|
3608
4301
|
"button",
|
|
3609
4302
|
{
|
|
3610
4303
|
type: "button",
|
|
3611
4304
|
onClick: onSave,
|
|
3612
|
-
disabled: saving,
|
|
4305
|
+
disabled: saving || hasErrors,
|
|
4306
|
+
title: hasErrors ? "Fix the highlighted field before saving" : void 0,
|
|
3613
4307
|
className: "vos-btn vos-btn-sm",
|
|
3614
4308
|
children: saving ? "Saving\u2026" : "Save"
|
|
3615
4309
|
}
|
|
3616
4310
|
)
|
|
3617
|
-
] }) : record ? /* @__PURE__ */
|
|
4311
|
+
] }) : record ? /* @__PURE__ */ jsxs12("footer", { className: "vos-drawer-footer", children: [
|
|
3618
4312
|
record.id,
|
|
3619
4313
|
" \xB7 updated ",
|
|
3620
4314
|
formatValue(record.updatedAt)
|
|
@@ -3623,6 +4317,56 @@ function RecordDrawer({
|
|
|
3623
4317
|
}
|
|
3624
4318
|
);
|
|
3625
4319
|
}
|
|
4320
|
+
function DetailRowView({
|
|
4321
|
+
row,
|
|
4322
|
+
onOpenRecord
|
|
4323
|
+
}) {
|
|
4324
|
+
return /* @__PURE__ */ jsxs12("div", { className: "vos-detail-row", children: [
|
|
4325
|
+
/* @__PURE__ */ jsx13("span", { className: "vos-detail-k", children: row.label }),
|
|
4326
|
+
/* @__PURE__ */ jsx13("span", { className: "vos-detail-v", children: row.kind === "relation" ? row.items && row.items.length ? /* @__PURE__ */ jsx13(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__ */ jsx13("ul", { className: "vos-bars", children: row.bars.map((b, i) => /* @__PURE__ */ jsxs12("li", { className: "vos-bar-line", children: [
|
|
4327
|
+
/* @__PURE__ */ jsx13("span", { className: "vos-bar-if", children: b.rightIf || "\u2014" }),
|
|
4328
|
+
b.assumption ? /* @__PURE__ */ jsx13(
|
|
4329
|
+
InlineLink,
|
|
4330
|
+
{
|
|
4331
|
+
id: b.assumption.id,
|
|
4332
|
+
title: b.assumption.title,
|
|
4333
|
+
onOpenRecord
|
|
4334
|
+
}
|
|
4335
|
+
) : null,
|
|
4336
|
+
/* @__PURE__ */ jsx13(
|
|
4337
|
+
"span",
|
|
4338
|
+
{
|
|
4339
|
+
className: b.barVerdict ? "vos-pill vos-pill-good" : "vos-pill vos-pill-neutral",
|
|
4340
|
+
children: b.barVerdict ?? "open"
|
|
4341
|
+
}
|
|
4342
|
+
)
|
|
4343
|
+
] }, i)) }) : "\u2014" : row.text })
|
|
4344
|
+
] });
|
|
4345
|
+
}
|
|
4346
|
+
function RelationLinks({
|
|
4347
|
+
items,
|
|
4348
|
+
onOpenRecord
|
|
4349
|
+
}) {
|
|
4350
|
+
return /* @__PURE__ */ jsx13("span", { className: "vos-detail-links", children: items.map((item, i) => /* @__PURE__ */ jsxs12("span", { children: [
|
|
4351
|
+
i > 0 ? ", " : null,
|
|
4352
|
+
/* @__PURE__ */ jsx13(InlineLink, { id: item.id, title: item.title, onOpenRecord })
|
|
4353
|
+
] }, item.id)) });
|
|
4354
|
+
}
|
|
4355
|
+
function InlineLink({
|
|
4356
|
+
id,
|
|
4357
|
+
title,
|
|
4358
|
+
onOpenRecord
|
|
4359
|
+
}) {
|
|
4360
|
+
return onOpenRecord ? /* @__PURE__ */ jsx13(
|
|
4361
|
+
"button",
|
|
4362
|
+
{
|
|
4363
|
+
type: "button",
|
|
4364
|
+
className: "vos-inline-link",
|
|
4365
|
+
onClick: () => onOpenRecord(id),
|
|
4366
|
+
children: title
|
|
4367
|
+
}
|
|
4368
|
+
) : /* @__PURE__ */ jsx13("span", { children: title });
|
|
4369
|
+
}
|
|
3626
4370
|
function DerivedCell({
|
|
3627
4371
|
field,
|
|
3628
4372
|
value,
|
|
@@ -3637,10 +4381,10 @@ function DerivedCell({
|
|
|
3637
4381
|
toneClass = heroToneClass(derivedTone(field, num3));
|
|
3638
4382
|
display = field === "confidence" ? formatSigned(num3) : String(Math.round(num3));
|
|
3639
4383
|
}
|
|
3640
|
-
return /* @__PURE__ */
|
|
3641
|
-
/* @__PURE__ */
|
|
4384
|
+
return /* @__PURE__ */ jsxs12("div", { className: "vos-dcell", children: [
|
|
4385
|
+
/* @__PURE__ */ jsxs12("div", { className: "vos-dcell-k", children: [
|
|
3642
4386
|
derivedLabel(field),
|
|
3643
|
-
showWhy ? /* @__PURE__ */
|
|
4387
|
+
showWhy ? /* @__PURE__ */ jsxs12(
|
|
3644
4388
|
"button",
|
|
3645
4389
|
{
|
|
3646
4390
|
type: "button",
|
|
@@ -3654,17 +4398,17 @@ function DerivedCell({
|
|
|
3654
4398
|
}
|
|
3655
4399
|
) : null
|
|
3656
4400
|
] }),
|
|
3657
|
-
/* @__PURE__ */
|
|
3658
|
-
DERIVED_SUB[field] ? /* @__PURE__ */
|
|
4401
|
+
/* @__PURE__ */ jsx13("div", { className: `vos-dcell-v ${toneClass}`, children: display }),
|
|
4402
|
+
DERIVED_SUB[field] ? /* @__PURE__ */ jsx13("div", { className: "vos-dcell-sub", children: DERIVED_SUB[field] }) : null
|
|
3659
4403
|
] });
|
|
3660
4404
|
}
|
|
3661
|
-
function
|
|
4405
|
+
function ConflictBanner2({
|
|
3662
4406
|
message,
|
|
3663
4407
|
onReload
|
|
3664
4408
|
}) {
|
|
3665
|
-
return /* @__PURE__ */
|
|
3666
|
-
/* @__PURE__ */
|
|
3667
|
-
/* @__PURE__ */
|
|
4409
|
+
return /* @__PURE__ */ jsxs12("div", { role: "alert", className: "vos-banner vos-banner-warn", children: [
|
|
4410
|
+
/* @__PURE__ */ jsx13("div", { className: "vos-banner-body", children: /* @__PURE__ */ jsx13("span", { children: message }) }),
|
|
4411
|
+
/* @__PURE__ */ jsx13("button", { type: "button", onClick: onReload, children: "Review the latest" })
|
|
3668
4412
|
] });
|
|
3669
4413
|
}
|
|
3670
4414
|
|
|
@@ -3672,20 +4416,13 @@ function ConflictBanner({
|
|
|
3672
4416
|
import { useMemo as useMemo2, useState as useState7 } from "react";
|
|
3673
4417
|
|
|
3674
4418
|
// src/form-fields.ts
|
|
3675
|
-
import {
|
|
3676
|
-
MARKET_RUNG_VALUES,
|
|
3677
|
-
TESTING_RUNGS
|
|
3678
|
-
} from "@validation-os/core";
|
|
3679
4419
|
var ASSUMPTION_STATUS = ["Draft", "Live", "Invalidated"];
|
|
3680
4420
|
var EXPERIMENT_STATUS = ["Draft", "Running", "Closed"];
|
|
3681
4421
|
var CLOSURE_REASON = ["Completed", "Early-stop", "Kill"];
|
|
3682
4422
|
var EXPERIMENT_OUTCOME = ["Achieved", "Missed", "Dropped"];
|
|
3683
4423
|
var DECISION_STATUS2 = ["Active", "Provisional", "Superseded", "Reversed"];
|
|
3684
4424
|
var GLOSSARY_STATUS = ["Active", "Provisional", "Superseded"];
|
|
3685
|
-
var RESULT = ["Validated", "Invalidated", "Inconclusive"];
|
|
3686
|
-
var MAGNITUDE = ["Low", "Typical", "High"];
|
|
3687
4425
|
var FEASIBILITY = ["High", "Medium", "Low"];
|
|
3688
|
-
var RUNGS = [...TESTING_RUNGS, ...MARKET_RUNG_VALUES];
|
|
3689
4426
|
var QUALITY = ["1", "0.7", "0.5"];
|
|
3690
4427
|
var FIELDS = {
|
|
3691
4428
|
assumptions: [
|
|
@@ -3718,8 +4455,10 @@ var FIELDS = {
|
|
|
3718
4455
|
readings: [
|
|
3719
4456
|
{ key: "Title", label: "Reading", kind: "text", required: true },
|
|
3720
4457
|
{ key: "Source", label: "Source", kind: "text" },
|
|
3721
|
-
|
|
3722
|
-
|
|
4458
|
+
// Rung / Result / Magnitude band / Grading justification are PER BELIEF now
|
|
4459
|
+
// (OPS-1305) — carried in `beliefs[]`, not on the row. They are omitted here
|
|
4460
|
+
// so the create form can never write a dead row-level field; grading a
|
|
4461
|
+
// reading's beliefs is a deferred follow-up (a `beliefs[]` editor).
|
|
3723
4462
|
{
|
|
3724
4463
|
key: "Representativeness",
|
|
3725
4464
|
label: "Representativeness",
|
|
@@ -3734,17 +4473,7 @@ var FIELDS = {
|
|
|
3734
4473
|
options: QUALITY,
|
|
3735
4474
|
coerce: "number"
|
|
3736
4475
|
},
|
|
3737
|
-
{
|
|
3738
|
-
key: "magnitudeBand",
|
|
3739
|
-
label: "Magnitude band",
|
|
3740
|
-
kind: "select",
|
|
3741
|
-
options: MAGNITUDE
|
|
3742
|
-
},
|
|
3743
|
-
{
|
|
3744
|
-
key: "Grading justification",
|
|
3745
|
-
label: "Grading justification",
|
|
3746
|
-
kind: "textarea"
|
|
3747
|
-
},
|
|
4476
|
+
{ key: "body", label: "Quote", kind: "textarea" },
|
|
3748
4477
|
{ key: "Date", label: "Date", kind: "text", placeholder: "YYYY-MM-DD" }
|
|
3749
4478
|
],
|
|
3750
4479
|
decisions: [
|
|
@@ -3786,7 +4515,7 @@ function toCreatePayload(register, draft) {
|
|
|
3786
4515
|
}
|
|
3787
4516
|
|
|
3788
4517
|
// src/record-form.tsx
|
|
3789
|
-
import { jsx as
|
|
4518
|
+
import { jsx as jsx14, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
3790
4519
|
function RecordForm({
|
|
3791
4520
|
register,
|
|
3792
4521
|
basePath,
|
|
@@ -3809,9 +4538,9 @@ function RecordForm({
|
|
|
3809
4538
|
} catch {
|
|
3810
4539
|
}
|
|
3811
4540
|
};
|
|
3812
|
-
return /* @__PURE__ */
|
|
3813
|
-
/* @__PURE__ */
|
|
3814
|
-
fields.map((field) => /* @__PURE__ */
|
|
4541
|
+
return /* @__PURE__ */ jsxs13("form", { onSubmit, className: "vos-form", children: [
|
|
4542
|
+
/* @__PURE__ */ jsxs13("div", { className: "vos-form-body", children: [
|
|
4543
|
+
fields.map((field) => /* @__PURE__ */ jsx14(
|
|
3815
4544
|
Field,
|
|
3816
4545
|
{
|
|
3817
4546
|
field,
|
|
@@ -3820,11 +4549,11 @@ function RecordForm({
|
|
|
3820
4549
|
},
|
|
3821
4550
|
field.key
|
|
3822
4551
|
)),
|
|
3823
|
-
error ? /* @__PURE__ */
|
|
4552
|
+
error ? /* @__PURE__ */ jsx14("p", { className: "vos-error", children: error }) : null
|
|
3824
4553
|
] }),
|
|
3825
|
-
/* @__PURE__ */
|
|
3826
|
-
/* @__PURE__ */
|
|
3827
|
-
/* @__PURE__ */
|
|
4554
|
+
/* @__PURE__ */ jsxs13("footer", { className: "vos-drawer-footer", children: [
|
|
4555
|
+
/* @__PURE__ */ jsx14("button", { type: "button", onClick: onCancel, className: "vos-btn vos-btn-ghost vos-btn-sm", children: "Cancel" }),
|
|
4556
|
+
/* @__PURE__ */ jsx14(
|
|
3828
4557
|
"button",
|
|
3829
4558
|
{
|
|
3830
4559
|
type: "submit",
|
|
@@ -3843,12 +4572,12 @@ function Field({
|
|
|
3843
4572
|
onChange
|
|
3844
4573
|
}) {
|
|
3845
4574
|
const id = `field-${field.key}`;
|
|
3846
|
-
return /* @__PURE__ */
|
|
3847
|
-
/* @__PURE__ */
|
|
4575
|
+
return /* @__PURE__ */ jsxs13("div", { className: "vos-field", children: [
|
|
4576
|
+
/* @__PURE__ */ jsxs13("label", { htmlFor: id, className: FIELD_LABEL_CLASS, children: [
|
|
3848
4577
|
field.label,
|
|
3849
|
-
field.required ? /* @__PURE__ */
|
|
4578
|
+
field.required ? /* @__PURE__ */ jsx14("span", { className: "vos-req", children: " *" }) : null
|
|
3850
4579
|
] }),
|
|
3851
|
-
field.kind === "textarea" ? /* @__PURE__ */
|
|
4580
|
+
field.kind === "textarea" ? /* @__PURE__ */ jsx14(
|
|
3852
4581
|
"textarea",
|
|
3853
4582
|
{
|
|
3854
4583
|
id,
|
|
@@ -3858,7 +4587,7 @@ function Field({
|
|
|
3858
4587
|
onChange: (e) => onChange(e.target.value),
|
|
3859
4588
|
className: FIELD_CONTROL_CLASS
|
|
3860
4589
|
}
|
|
3861
|
-
) : field.kind === "select" ? /* @__PURE__ */
|
|
4590
|
+
) : field.kind === "select" ? /* @__PURE__ */ jsxs13(
|
|
3862
4591
|
"select",
|
|
3863
4592
|
{
|
|
3864
4593
|
id,
|
|
@@ -3866,11 +4595,11 @@ function Field({
|
|
|
3866
4595
|
onChange: (e) => onChange(e.target.value),
|
|
3867
4596
|
className: FIELD_CONTROL_CLASS,
|
|
3868
4597
|
children: [
|
|
3869
|
-
/* @__PURE__ */
|
|
3870
|
-
field.options?.map((opt) => /* @__PURE__ */
|
|
4598
|
+
/* @__PURE__ */ jsx14("option", { value: "", children: "\u2014" }),
|
|
4599
|
+
field.options?.map((opt) => /* @__PURE__ */ jsx14("option", { value: opt, children: opt }, opt))
|
|
3871
4600
|
]
|
|
3872
4601
|
}
|
|
3873
|
-
) : /* @__PURE__ */
|
|
4602
|
+
) : /* @__PURE__ */ jsx14(
|
|
3874
4603
|
"input",
|
|
3875
4604
|
{
|
|
3876
4605
|
id,
|
|
@@ -3906,7 +4635,7 @@ function linkChoicesFrom(register) {
|
|
|
3906
4635
|
}
|
|
3907
4636
|
|
|
3908
4637
|
// src/relation-editor.tsx
|
|
3909
|
-
import { jsx as
|
|
4638
|
+
import { jsx as jsx15, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
3910
4639
|
function RelationEditor({
|
|
3911
4640
|
register,
|
|
3912
4641
|
recordId,
|
|
@@ -3940,10 +4669,10 @@ function RelationEditor({
|
|
|
3940
4669
|
} catch {
|
|
3941
4670
|
}
|
|
3942
4671
|
};
|
|
3943
|
-
return /* @__PURE__ */
|
|
3944
|
-
/* @__PURE__ */
|
|
3945
|
-
/* @__PURE__ */
|
|
3946
|
-
/* @__PURE__ */
|
|
4672
|
+
return /* @__PURE__ */ jsxs14("section", { className: "vos-relation", children: [
|
|
4673
|
+
/* @__PURE__ */ jsx15("h3", { className: "vos-sectitle", children: "Link a record" }),
|
|
4674
|
+
/* @__PURE__ */ jsxs14("div", { className: "vos-field-stack", children: [
|
|
4675
|
+
/* @__PURE__ */ jsxs14(
|
|
3947
4676
|
"select",
|
|
3948
4677
|
{
|
|
3949
4678
|
"aria-label": "Relation",
|
|
@@ -3954,12 +4683,12 @@ function RelationEditor({
|
|
|
3954
4683
|
},
|
|
3955
4684
|
className: FIELD_CONTROL_CLASS,
|
|
3956
4685
|
children: [
|
|
3957
|
-
/* @__PURE__ */
|
|
3958
|
-
choices.map((c) => /* @__PURE__ */
|
|
4686
|
+
/* @__PURE__ */ jsx15("option", { value: "", children: "Choose a relation\u2026" }),
|
|
4687
|
+
choices.map((c) => /* @__PURE__ */ jsx15("option", { value: c.relation, children: c.label }, c.relation))
|
|
3959
4688
|
]
|
|
3960
4689
|
}
|
|
3961
4690
|
),
|
|
3962
|
-
active ? /* @__PURE__ */
|
|
4691
|
+
active ? /* @__PURE__ */ jsxs14(
|
|
3963
4692
|
"select",
|
|
3964
4693
|
{
|
|
3965
4694
|
"aria-label": "Target record",
|
|
@@ -3967,13 +4696,13 @@ function RelationEditor({
|
|
|
3967
4696
|
onChange: (e) => setTargetId(e.target.value),
|
|
3968
4697
|
className: FIELD_CONTROL_CLASS,
|
|
3969
4698
|
children: [
|
|
3970
|
-
/* @__PURE__ */
|
|
3971
|
-
targets.map((r) => /* @__PURE__ */
|
|
4699
|
+
/* @__PURE__ */ jsx15("option", { value: "", children: "Choose a record\u2026" }),
|
|
4700
|
+
targets.map((r) => /* @__PURE__ */ jsx15("option", { value: r.id, children: primaryLabel(r) }, r.id))
|
|
3972
4701
|
]
|
|
3973
4702
|
}
|
|
3974
4703
|
) : null,
|
|
3975
|
-
error ? /* @__PURE__ */
|
|
3976
|
-
/* @__PURE__ */
|
|
4704
|
+
error ? /* @__PURE__ */ jsx15("p", { className: "vos-error", children: error }) : null,
|
|
4705
|
+
/* @__PURE__ */ jsx15(
|
|
3977
4706
|
"button",
|
|
3978
4707
|
{
|
|
3979
4708
|
type: "button",
|
|
@@ -4040,12 +4769,12 @@ function useSavedViews(register) {
|
|
|
4040
4769
|
}
|
|
4041
4770
|
|
|
4042
4771
|
// src/register-browser.tsx
|
|
4043
|
-
import { jsx as
|
|
4772
|
+
import { jsx as jsx16, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
4044
4773
|
function contextNeeds(register) {
|
|
4045
4774
|
return {
|
|
4046
4775
|
experiments: register === "assumptions" || register === "readings",
|
|
4047
4776
|
readings: register === "assumptions",
|
|
4048
|
-
assumptions: register === "decisions"
|
|
4777
|
+
assumptions: register === "decisions" || register === "experiments" || register === "readings"
|
|
4049
4778
|
};
|
|
4050
4779
|
}
|
|
4051
4780
|
function RegisterBrowser({
|
|
@@ -4098,6 +4827,15 @@ function RegisterBrowser({
|
|
|
4098
4827
|
const n = humanCount[tab.id] ?? 0;
|
|
4099
4828
|
return n > 0 ? n : null;
|
|
4100
4829
|
};
|
|
4830
|
+
const related = {
|
|
4831
|
+
assumptions: ctx.assumptions,
|
|
4832
|
+
experiments: ctx.experiments,
|
|
4833
|
+
readings: ctx.readings,
|
|
4834
|
+
decisions: ctx.decisions
|
|
4835
|
+
};
|
|
4836
|
+
const assumptionTitles = new Map(
|
|
4837
|
+
(ctx.assumptions ?? []).map((a) => [a.id, primaryLabel(a)])
|
|
4838
|
+
);
|
|
4101
4839
|
const patch = (p) => setDescriptor((d) => ({ ...d, ...p }));
|
|
4102
4840
|
const saveCurrentView = () => {
|
|
4103
4841
|
if (typeof window === "undefined") return;
|
|
@@ -4109,14 +4847,14 @@ function RegisterBrowser({
|
|
|
4109
4847
|
void _name;
|
|
4110
4848
|
setDescriptor(rest);
|
|
4111
4849
|
};
|
|
4112
|
-
return /* @__PURE__ */
|
|
4113
|
-
/* @__PURE__ */
|
|
4114
|
-
/* @__PURE__ */
|
|
4115
|
-
/* @__PURE__ */
|
|
4116
|
-
subtitle ? /* @__PURE__ */
|
|
4850
|
+
return /* @__PURE__ */ jsxs15("div", { children: [
|
|
4851
|
+
/* @__PURE__ */ jsxs15("div", { className: "vos-head", children: [
|
|
4852
|
+
/* @__PURE__ */ jsxs15("div", { children: [
|
|
4853
|
+
/* @__PURE__ */ jsx16("h1", { children: REGISTER_LABEL[register] }),
|
|
4854
|
+
subtitle ? /* @__PURE__ */ jsx16("p", { children: subtitle }) : null
|
|
4117
4855
|
] }),
|
|
4118
|
-
/* @__PURE__ */
|
|
4119
|
-
/* @__PURE__ */
|
|
4856
|
+
/* @__PURE__ */ jsx16("div", { className: "vos-spacer" }),
|
|
4857
|
+
/* @__PURE__ */ jsx16(
|
|
4120
4858
|
"button",
|
|
4121
4859
|
{
|
|
4122
4860
|
type: "button",
|
|
@@ -4125,7 +4863,7 @@ function RegisterBrowser({
|
|
|
4125
4863
|
children: "\u21BB Refresh"
|
|
4126
4864
|
}
|
|
4127
4865
|
),
|
|
4128
|
-
/* @__PURE__ */
|
|
4866
|
+
/* @__PURE__ */ jsxs15(
|
|
4129
4867
|
"button",
|
|
4130
4868
|
{
|
|
4131
4869
|
type: "button",
|
|
@@ -4138,10 +4876,10 @@ function RegisterBrowser({
|
|
|
4138
4876
|
}
|
|
4139
4877
|
)
|
|
4140
4878
|
] }),
|
|
4141
|
-
/* @__PURE__ */
|
|
4879
|
+
/* @__PURE__ */ jsx16("div", { className: "vos-tabs", role: "tablist", "aria-label": "Views", children: shaped.tabs.map((tab) => {
|
|
4142
4880
|
const active = tab.id === shaped.activeTabId;
|
|
4143
4881
|
const badge = badgeFor(tab);
|
|
4144
|
-
return /* @__PURE__ */
|
|
4882
|
+
return /* @__PURE__ */ jsxs15(
|
|
4145
4883
|
"button",
|
|
4146
4884
|
{
|
|
4147
4885
|
type: "button",
|
|
@@ -4151,13 +4889,13 @@ function RegisterBrowser({
|
|
|
4151
4889
|
onClick: () => patch({ tabId: tab.id }),
|
|
4152
4890
|
children: [
|
|
4153
4891
|
tab.label,
|
|
4154
|
-
badge !== null ? /* @__PURE__ */
|
|
4892
|
+
badge !== null ? /* @__PURE__ */ jsx16("span", { className: "vos-tab-badge", children: badge }) : null
|
|
4155
4893
|
]
|
|
4156
4894
|
},
|
|
4157
4895
|
tab.id
|
|
4158
4896
|
);
|
|
4159
4897
|
}) }),
|
|
4160
|
-
/* @__PURE__ */
|
|
4898
|
+
/* @__PURE__ */ jsx16(
|
|
4161
4899
|
ViewControls,
|
|
4162
4900
|
{
|
|
4163
4901
|
register,
|
|
@@ -4168,10 +4906,10 @@ function RegisterBrowser({
|
|
|
4168
4906
|
onQuery: (query) => patch({ query })
|
|
4169
4907
|
}
|
|
4170
4908
|
),
|
|
4171
|
-
/* @__PURE__ */
|
|
4172
|
-
/* @__PURE__ */
|
|
4173
|
-
savedViews.views.length === 0 ? /* @__PURE__ */
|
|
4174
|
-
/* @__PURE__ */
|
|
4909
|
+
/* @__PURE__ */ jsxs15("div", { className: "vos-saved-views", children: [
|
|
4910
|
+
/* @__PURE__ */ jsx16("span", { className: "vos-saved-label", children: "Saved views" }),
|
|
4911
|
+
savedViews.views.length === 0 ? /* @__PURE__ */ jsx16("span", { className: "vos-hint", children: "none yet" }) : savedViews.views.map((v) => /* @__PURE__ */ jsxs15("span", { className: "vos-saved-view", children: [
|
|
4912
|
+
/* @__PURE__ */ jsx16(
|
|
4175
4913
|
"button",
|
|
4176
4914
|
{
|
|
4177
4915
|
type: "button",
|
|
@@ -4180,7 +4918,7 @@ function RegisterBrowser({
|
|
|
4180
4918
|
children: v.name
|
|
4181
4919
|
}
|
|
4182
4920
|
),
|
|
4183
|
-
/* @__PURE__ */
|
|
4921
|
+
/* @__PURE__ */ jsx16(
|
|
4184
4922
|
"button",
|
|
4185
4923
|
{
|
|
4186
4924
|
type: "button",
|
|
@@ -4191,7 +4929,7 @@ function RegisterBrowser({
|
|
|
4191
4929
|
}
|
|
4192
4930
|
)
|
|
4193
4931
|
] }, v.name)),
|
|
4194
|
-
/* @__PURE__ */
|
|
4932
|
+
/* @__PURE__ */ jsx16(
|
|
4195
4933
|
"button",
|
|
4196
4934
|
{
|
|
4197
4935
|
type: "button",
|
|
@@ -4201,20 +4939,21 @@ function RegisterBrowser({
|
|
|
4201
4939
|
}
|
|
4202
4940
|
)
|
|
4203
4941
|
] }),
|
|
4204
|
-
loading && !records ? /* @__PURE__ */
|
|
4942
|
+
loading && !records ? /* @__PURE__ */ jsxs15("p", { className: "vos-muted", children: [
|
|
4205
4943
|
"Loading ",
|
|
4206
4944
|
REGISTER_LABEL[register].toLowerCase(),
|
|
4207
4945
|
"\u2026"
|
|
4208
|
-
] }) : error ? /* @__PURE__ */
|
|
4946
|
+
] }) : error ? /* @__PURE__ */ jsx16("p", { className: "vos-error", children: error }) : /* @__PURE__ */ jsx16(
|
|
4209
4947
|
ShapedBody,
|
|
4210
4948
|
{
|
|
4211
4949
|
register,
|
|
4212
4950
|
shaped,
|
|
4213
4951
|
onRowClick: setOpenId,
|
|
4214
|
-
selectedId: openId
|
|
4952
|
+
selectedId: openId,
|
|
4953
|
+
assumptionTitles
|
|
4215
4954
|
}
|
|
4216
4955
|
),
|
|
4217
|
-
/* @__PURE__ */
|
|
4956
|
+
/* @__PURE__ */ jsx16(
|
|
4218
4957
|
RecordDrawer,
|
|
4219
4958
|
{
|
|
4220
4959
|
register,
|
|
@@ -4225,11 +4964,13 @@ function RegisterBrowser({
|
|
|
4225
4964
|
onClose: () => setOpenId(null),
|
|
4226
4965
|
basePath,
|
|
4227
4966
|
onOpenFull: onOpenRecord && openId ? () => onOpenRecord(openId) : void 0,
|
|
4967
|
+
onOpenRecord,
|
|
4968
|
+
related,
|
|
4228
4969
|
onChanged: () => {
|
|
4229
4970
|
refreshRecord();
|
|
4230
4971
|
refreshList();
|
|
4231
4972
|
},
|
|
4232
|
-
children: openId ? /* @__PURE__ */
|
|
4973
|
+
children: openId ? /* @__PURE__ */ jsx16(
|
|
4233
4974
|
RelationEditor,
|
|
4234
4975
|
{
|
|
4235
4976
|
register,
|
|
@@ -4243,18 +4984,18 @@ function RegisterBrowser({
|
|
|
4243
4984
|
) : null
|
|
4244
4985
|
}
|
|
4245
4986
|
),
|
|
4246
|
-
/* @__PURE__ */
|
|
4987
|
+
/* @__PURE__ */ jsxs15(
|
|
4247
4988
|
DrawerShell,
|
|
4248
4989
|
{
|
|
4249
4990
|
open: creating,
|
|
4250
4991
|
onClose: () => setCreating(false),
|
|
4251
4992
|
ariaLabel: `New ${REGISTER_SINGULAR[register]} record`,
|
|
4252
4993
|
children: [
|
|
4253
|
-
/* @__PURE__ */
|
|
4254
|
-
/* @__PURE__ */
|
|
4255
|
-
/* @__PURE__ */
|
|
4994
|
+
/* @__PURE__ */ jsx16("header", { className: "vos-drawer-header", children: /* @__PURE__ */ jsxs15("div", { children: [
|
|
4995
|
+
/* @__PURE__ */ jsx16("p", { className: "vos-drawer-eyebrow", children: "New" }),
|
|
4996
|
+
/* @__PURE__ */ jsx16("h2", { className: "vos-drawer-title", children: REGISTER_SINGULAR[register] })
|
|
4256
4997
|
] }) }),
|
|
4257
|
-
/* @__PURE__ */
|
|
4998
|
+
/* @__PURE__ */ jsx16(
|
|
4258
4999
|
RecordForm,
|
|
4259
5000
|
{
|
|
4260
5001
|
register,
|
|
@@ -4282,8 +5023,8 @@ function ViewControls({
|
|
|
4282
5023
|
}) {
|
|
4283
5024
|
const sortable = columnsFor(register);
|
|
4284
5025
|
const sort = descriptor.sort ?? null;
|
|
4285
|
-
return /* @__PURE__ */
|
|
4286
|
-
/* @__PURE__ */
|
|
5026
|
+
return /* @__PURE__ */ jsxs15("div", { className: "vos-view-controls", children: [
|
|
5027
|
+
/* @__PURE__ */ jsx16(
|
|
4287
5028
|
"input",
|
|
4288
5029
|
{
|
|
4289
5030
|
type: "search",
|
|
@@ -4294,24 +5035,24 @@ function ViewControls({
|
|
|
4294
5035
|
"aria-label": "Filter records"
|
|
4295
5036
|
}
|
|
4296
5037
|
),
|
|
4297
|
-
axes.length ? /* @__PURE__ */
|
|
4298
|
-
/* @__PURE__ */
|
|
4299
|
-
/* @__PURE__ */
|
|
5038
|
+
axes.length ? /* @__PURE__ */ jsxs15("label", { className: "vos-control", children: [
|
|
5039
|
+
/* @__PURE__ */ jsx16("span", { children: "Group" }),
|
|
5040
|
+
/* @__PURE__ */ jsxs15(
|
|
4300
5041
|
"select",
|
|
4301
5042
|
{
|
|
4302
5043
|
className: "vos-input",
|
|
4303
5044
|
value: descriptor.groupBy ?? "",
|
|
4304
5045
|
onChange: (e) => onGroupBy(e.target.value || null),
|
|
4305
5046
|
children: [
|
|
4306
|
-
/* @__PURE__ */
|
|
4307
|
-
axes.map((axis) => /* @__PURE__ */
|
|
5047
|
+
/* @__PURE__ */ jsx16("option", { value: "", children: "None" }),
|
|
5048
|
+
axes.map((axis) => /* @__PURE__ */ jsx16("option", { value: axis, children: axis }, axis))
|
|
4308
5049
|
]
|
|
4309
5050
|
}
|
|
4310
5051
|
)
|
|
4311
5052
|
] }) : null,
|
|
4312
|
-
/* @__PURE__ */
|
|
4313
|
-
/* @__PURE__ */
|
|
4314
|
-
/* @__PURE__ */
|
|
5053
|
+
/* @__PURE__ */ jsxs15("label", { className: "vos-control", children: [
|
|
5054
|
+
/* @__PURE__ */ jsx16("span", { children: "Sort" }),
|
|
5055
|
+
/* @__PURE__ */ jsxs15(
|
|
4315
5056
|
"select",
|
|
4316
5057
|
{
|
|
4317
5058
|
className: "vos-input",
|
|
@@ -4320,13 +5061,13 @@ function ViewControls({
|
|
|
4320
5061
|
e.target.value ? { key: e.target.value, dir: sort?.dir ?? "desc" } : null
|
|
4321
5062
|
),
|
|
4322
5063
|
children: [
|
|
4323
|
-
/* @__PURE__ */
|
|
4324
|
-
sortable.map((c) => /* @__PURE__ */
|
|
5064
|
+
/* @__PURE__ */ jsx16("option", { value: "", children: "Default" }),
|
|
5065
|
+
sortable.map((c) => /* @__PURE__ */ jsx16("option", { value: c.key, children: c.header }, c.key))
|
|
4325
5066
|
]
|
|
4326
5067
|
}
|
|
4327
5068
|
)
|
|
4328
5069
|
] }),
|
|
4329
|
-
sort ? /* @__PURE__ */
|
|
5070
|
+
sort ? /* @__PURE__ */ jsx16(
|
|
4330
5071
|
"button",
|
|
4331
5072
|
{
|
|
4332
5073
|
type: "button",
|
|
@@ -4342,53 +5083,57 @@ function ShapedBody({
|
|
|
4342
5083
|
register,
|
|
4343
5084
|
shaped,
|
|
4344
5085
|
onRowClick,
|
|
4345
|
-
selectedId
|
|
5086
|
+
selectedId,
|
|
5087
|
+
assumptionTitles
|
|
4346
5088
|
}) {
|
|
4347
5089
|
if (shaped.nested) {
|
|
4348
5090
|
if (shaped.nested.length === 0)
|
|
4349
|
-
return /* @__PURE__ */
|
|
4350
|
-
return /* @__PURE__ */
|
|
4351
|
-
/* @__PURE__ */
|
|
5091
|
+
return /* @__PURE__ */ jsx16("p", { className: "vos-empty", children: "No readings in this view." });
|
|
5092
|
+
return /* @__PURE__ */ jsx16("div", { className: "vos-groups", children: shaped.nested.map((group) => /* @__PURE__ */ jsxs15("section", { className: "vos-group", children: [
|
|
5093
|
+
/* @__PURE__ */ jsxs15("h3", { className: "vos-group-head", children: [
|
|
4352
5094
|
group.label,
|
|
4353
|
-
/* @__PURE__ */
|
|
5095
|
+
/* @__PURE__ */ jsx16("span", { className: "vos-group-n", children: group.readings.length })
|
|
4354
5096
|
] }),
|
|
4355
|
-
/* @__PURE__ */
|
|
5097
|
+
/* @__PURE__ */ jsx16(
|
|
4356
5098
|
RegisterTable,
|
|
4357
5099
|
{
|
|
4358
5100
|
register,
|
|
4359
5101
|
records: group.readings,
|
|
4360
5102
|
onRowClick,
|
|
4361
|
-
selectedId
|
|
5103
|
+
selectedId,
|
|
5104
|
+
assumptionTitles
|
|
4362
5105
|
}
|
|
4363
5106
|
)
|
|
4364
5107
|
] }, group.experimentId ?? "__none__")) });
|
|
4365
5108
|
}
|
|
4366
5109
|
if (shaped.groups) {
|
|
4367
5110
|
if (shaped.groups.length === 0)
|
|
4368
|
-
return /* @__PURE__ */
|
|
4369
|
-
return /* @__PURE__ */
|
|
4370
|
-
/* @__PURE__ */
|
|
5111
|
+
return /* @__PURE__ */ jsx16("p", { className: "vos-empty", children: "No records in this view." });
|
|
5112
|
+
return /* @__PURE__ */ jsx16("div", { className: "vos-groups", children: shaped.groups.map((group) => /* @__PURE__ */ jsxs15("section", { className: "vos-group", children: [
|
|
5113
|
+
/* @__PURE__ */ jsxs15("h3", { className: "vos-group-head", children: [
|
|
4371
5114
|
group.label,
|
|
4372
|
-
/* @__PURE__ */
|
|
5115
|
+
/* @__PURE__ */ jsx16("span", { className: "vos-group-n", children: group.records.length })
|
|
4373
5116
|
] }),
|
|
4374
|
-
/* @__PURE__ */
|
|
5117
|
+
/* @__PURE__ */ jsx16(
|
|
4375
5118
|
RegisterTable,
|
|
4376
5119
|
{
|
|
4377
5120
|
register,
|
|
4378
5121
|
records: group.records,
|
|
4379
5122
|
onRowClick,
|
|
4380
|
-
selectedId
|
|
5123
|
+
selectedId,
|
|
5124
|
+
assumptionTitles
|
|
4381
5125
|
}
|
|
4382
5126
|
)
|
|
4383
5127
|
] }, group.key)) });
|
|
4384
5128
|
}
|
|
4385
|
-
return /* @__PURE__ */
|
|
5129
|
+
return /* @__PURE__ */ jsx16(
|
|
4386
5130
|
RegisterTable,
|
|
4387
5131
|
{
|
|
4388
5132
|
register,
|
|
4389
5133
|
records: shaped.rows,
|
|
4390
5134
|
onRowClick,
|
|
4391
|
-
selectedId
|
|
5135
|
+
selectedId,
|
|
5136
|
+
assumptionTitles
|
|
4392
5137
|
}
|
|
4393
5138
|
);
|
|
4394
5139
|
}
|
|
@@ -4396,7 +5141,7 @@ function ShapedBody({
|
|
|
4396
5141
|
// src/next-move-surface.tsx
|
|
4397
5142
|
import { useMemo as useMemo5, useState as useState11 } from "react";
|
|
4398
5143
|
import { rankNextMoves as rankNextMoves2 } from "@validation-os/core/derivation";
|
|
4399
|
-
import { Fragment as Fragment10, jsx as
|
|
5144
|
+
import { Fragment as Fragment10, jsx as jsx17, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
4400
5145
|
var STAGES = ["Framed", "Planned", "Tested", "Known"];
|
|
4401
5146
|
var MOVE_STAGE = {
|
|
4402
5147
|
"score-impact": 0,
|
|
@@ -4454,12 +5199,12 @@ function NextMoveSurface({ basePath, onNavigate }) {
|
|
|
4454
5199
|
});
|
|
4455
5200
|
};
|
|
4456
5201
|
if (loading) {
|
|
4457
|
-
return /* @__PURE__ */
|
|
5202
|
+
return /* @__PURE__ */ jsx17(NextMoveFrame, { children: /* @__PURE__ */ jsx17("div", { className: "vos-empty", children: "Reading your beliefs\u2026" }) });
|
|
4458
5203
|
}
|
|
4459
5204
|
if (error) {
|
|
4460
|
-
return /* @__PURE__ */
|
|
4461
|
-
/* @__PURE__ */
|
|
4462
|
-
/* @__PURE__ */
|
|
5205
|
+
return /* @__PURE__ */ jsx17(NextMoveFrame, { children: /* @__PURE__ */ jsx17("div", { className: "vos-banner vos-banner-crit", children: /* @__PURE__ */ jsxs16("div", { className: "vos-banner-body", children: [
|
|
5206
|
+
/* @__PURE__ */ jsx17("b", { children: "Couldn't load the workflow." }),
|
|
5207
|
+
/* @__PURE__ */ jsx17("span", { children: error })
|
|
4463
5208
|
] }) }) });
|
|
4464
5209
|
}
|
|
4465
5210
|
if (moves.length === 0) {
|
|
@@ -4471,13 +5216,13 @@ function NextMoveSurface({ basePath, onNavigate }) {
|
|
|
4471
5216
|
};
|
|
4472
5217
|
const cold = coldStartFor(records);
|
|
4473
5218
|
if (cold.cold) {
|
|
4474
|
-
return /* @__PURE__ */
|
|
4475
|
-
/* @__PURE__ */
|
|
4476
|
-
/* @__PURE__ */
|
|
4477
|
-
/* @__PURE__ */
|
|
4478
|
-
/* @__PURE__ */
|
|
4479
|
-
/* @__PURE__ */
|
|
4480
|
-
/* @__PURE__ */
|
|
5219
|
+
return /* @__PURE__ */ jsxs16(NextMoveFrame, { children: [
|
|
5220
|
+
/* @__PURE__ */ jsx17("div", { className: "vos-firstrun", children: FIRST_RUN_LINE }),
|
|
5221
|
+
/* @__PURE__ */ jsxs16("div", { className: "vos-card vos-cold vos-cold-next", children: [
|
|
5222
|
+
/* @__PURE__ */ jsx17("span", { className: "vos-cold-eyebrow", children: cold.next.eyebrow }),
|
|
5223
|
+
/* @__PURE__ */ jsx17("h2", { className: "vos-cold-headline", children: cold.next.headline }),
|
|
5224
|
+
/* @__PURE__ */ jsx17("p", { className: "vos-cold-body", children: cold.next.body }),
|
|
5225
|
+
/* @__PURE__ */ jsx17(
|
|
4481
5226
|
"button",
|
|
4482
5227
|
{
|
|
4483
5228
|
type: "button",
|
|
@@ -4489,10 +5234,10 @@ function NextMoveSurface({ basePath, onNavigate }) {
|
|
|
4489
5234
|
] })
|
|
4490
5235
|
] });
|
|
4491
5236
|
}
|
|
4492
|
-
return /* @__PURE__ */
|
|
5237
|
+
return /* @__PURE__ */ jsx17(NextMoveFrame, { children: /* @__PURE__ */ jsxs16("div", { className: "vos-empty", children: [
|
|
4493
5238
|
"Nothing needs your attention right now \u2014 every belief is either resting on a decision or waiting on a test. Add a new belief from",
|
|
4494
5239
|
" ",
|
|
4495
|
-
/* @__PURE__ */
|
|
5240
|
+
/* @__PURE__ */ jsx17(
|
|
4496
5241
|
"button",
|
|
4497
5242
|
{
|
|
4498
5243
|
type: "button",
|
|
@@ -4510,11 +5255,11 @@ function NextMoveSurface({ basePath, onNavigate }) {
|
|
|
4510
5255
|
const onDeck = rest.filter((m) => m.assumptionId !== top.assumptionId).slice(0, 3);
|
|
4511
5256
|
const topPres = movePresentation(top.move);
|
|
4512
5257
|
const topTone = riskLevel(top.risk);
|
|
4513
|
-
return /* @__PURE__ */
|
|
4514
|
-
killMoves.length > 0 && !top.killLane ? /* @__PURE__ */
|
|
4515
|
-
/* @__PURE__ */
|
|
4516
|
-
/* @__PURE__ */
|
|
4517
|
-
/* @__PURE__ */
|
|
5258
|
+
return /* @__PURE__ */ jsxs16(NextMoveFrame, { children: [
|
|
5259
|
+
killMoves.length > 0 && !top.killLane ? /* @__PURE__ */ jsx17(KillBanner, { count: killMoves.length, onReview: () => startStepIn(killMoves[0]) }) : null,
|
|
5260
|
+
/* @__PURE__ */ jsxs16("div", { className: `vos-hero vos-card${top.killLane ? " vos-hero-kill" : ""}`, children: [
|
|
5261
|
+
/* @__PURE__ */ jsx17("span", { className: "vos-hero-eyebrow", children: top.killLane ? "Kill lane \u2014 turning against you" : "Your next move" }),
|
|
5262
|
+
/* @__PURE__ */ jsx17(
|
|
4518
5263
|
"button",
|
|
4519
5264
|
{
|
|
4520
5265
|
type: "button",
|
|
@@ -4524,23 +5269,23 @@ function NextMoveSurface({ basePath, onNavigate }) {
|
|
|
4524
5269
|
children: top.title
|
|
4525
5270
|
}
|
|
4526
5271
|
),
|
|
4527
|
-
/* @__PURE__ */
|
|
4528
|
-
/* @__PURE__ */
|
|
5272
|
+
/* @__PURE__ */ jsxs16("div", { className: "vos-riskchip", "aria-label": `Risk: ${RISK_PHRASE[topTone]}`, children: [
|
|
5273
|
+
/* @__PURE__ */ jsx17("span", { className: "vos-risk-bar", "aria-hidden": "true", children: /* @__PURE__ */ jsx17(
|
|
4529
5274
|
"i",
|
|
4530
5275
|
{
|
|
4531
5276
|
className: `vos-fill-${topTone}`,
|
|
4532
5277
|
style: { width: `${riskFraction(top.risk) * 100}%` }
|
|
4533
5278
|
}
|
|
4534
5279
|
) }),
|
|
4535
|
-
/* @__PURE__ */
|
|
5280
|
+
/* @__PURE__ */ jsx17("span", { className: `vos-riskchip-label vos-text-${topTone}`, children: top.killLane ? "Confidence has turned negative" : RISK_PHRASE[topTone] })
|
|
4536
5281
|
] }),
|
|
4537
|
-
/* @__PURE__ */
|
|
4538
|
-
/* @__PURE__ */
|
|
5282
|
+
/* @__PURE__ */ jsx17(ActButton, { move: top, onStepIn: () => startStepIn(top), onReview: () => openRecord(top.assumptionId) }),
|
|
5283
|
+
/* @__PURE__ */ jsx17("button", { type: "button", className: "vos-why", onClick: () => setWhy((w) => !w), children: why ? "Hide details" : "Why this?" })
|
|
4539
5284
|
] }),
|
|
4540
|
-
why ? /* @__PURE__ */
|
|
4541
|
-
onDeck.length > 0 ? /* @__PURE__ */
|
|
4542
|
-
/* @__PURE__ */
|
|
4543
|
-
onDeck.map((m) => /* @__PURE__ */
|
|
5285
|
+
why ? /* @__PURE__ */ jsx17(WhyPanel, { top, ranked: moves }) : null,
|
|
5286
|
+
onDeck.length > 0 ? /* @__PURE__ */ jsxs16("section", { className: "vos-ondeck", children: [
|
|
5287
|
+
/* @__PURE__ */ jsx17("h3", { className: "vos-sectitle", children: "On deck" }),
|
|
5288
|
+
onDeck.map((m) => /* @__PURE__ */ jsx17(
|
|
4544
5289
|
OnDeckRow,
|
|
4545
5290
|
{
|
|
4546
5291
|
move: m,
|
|
@@ -4550,7 +5295,7 @@ function NextMoveSurface({ basePath, onNavigate }) {
|
|
|
4550
5295
|
m.assumptionId
|
|
4551
5296
|
))
|
|
4552
5297
|
] }) : null,
|
|
4553
|
-
/* @__PURE__ */
|
|
5298
|
+
/* @__PURE__ */ jsx17(
|
|
4554
5299
|
"button",
|
|
4555
5300
|
{
|
|
4556
5301
|
type: "button",
|
|
@@ -4559,7 +5304,7 @@ function NextMoveSurface({ basePath, onNavigate }) {
|
|
|
4559
5304
|
children: "Act on a different belief \u2192"
|
|
4560
5305
|
}
|
|
4561
5306
|
),
|
|
4562
|
-
stepIn?.form === "score-impact" ? /* @__PURE__ */
|
|
5307
|
+
stepIn?.form === "score-impact" ? /* @__PURE__ */ jsx17(
|
|
4563
5308
|
ScoreImpactForm,
|
|
4564
5309
|
{
|
|
4565
5310
|
assumption: stepIn.assumption,
|
|
@@ -4571,7 +5316,7 @@ function NextMoveSurface({ basePath, onNavigate }) {
|
|
|
4571
5316
|
onCancel: () => setStepIn(null)
|
|
4572
5317
|
}
|
|
4573
5318
|
) : null,
|
|
4574
|
-
stepIn?.form === "write-decision" ? /* @__PURE__ */
|
|
5319
|
+
stepIn?.form === "write-decision" ? /* @__PURE__ */ jsx17(
|
|
4575
5320
|
WriteDecisionForm,
|
|
4576
5321
|
{
|
|
4577
5322
|
assumption: stepIn.assumption,
|
|
@@ -4587,12 +5332,12 @@ function NextMoveSurface({ basePath, onNavigate }) {
|
|
|
4587
5332
|
] });
|
|
4588
5333
|
}
|
|
4589
5334
|
function NextMoveFrame({ children }) {
|
|
4590
|
-
return /* @__PURE__ */
|
|
4591
|
-
/* @__PURE__ */
|
|
4592
|
-
/* @__PURE__ */
|
|
4593
|
-
/* @__PURE__ */
|
|
5335
|
+
return /* @__PURE__ */ jsxs16("div", { children: [
|
|
5336
|
+
/* @__PURE__ */ jsx17("div", { className: "vos-head", children: /* @__PURE__ */ jsxs16("div", { children: [
|
|
5337
|
+
/* @__PURE__ */ jsx17("h1", { children: "Next move" }),
|
|
5338
|
+
/* @__PURE__ */ jsx17("p", { children: "The single next move to make \u2014 and what's on deck." })
|
|
4594
5339
|
] }) }),
|
|
4595
|
-
/* @__PURE__ */
|
|
5340
|
+
/* @__PURE__ */ jsx17("div", { className: "vos-next", children })
|
|
4596
5341
|
] });
|
|
4597
5342
|
}
|
|
4598
5343
|
function ActButton({
|
|
@@ -4602,20 +5347,20 @@ function ActButton({
|
|
|
4602
5347
|
}) {
|
|
4603
5348
|
const pres = movePresentation(move.move);
|
|
4604
5349
|
if (pres.steppable) {
|
|
4605
|
-
return /* @__PURE__ */
|
|
5350
|
+
return /* @__PURE__ */ jsx17("button", { type: "button", className: "vos-btn vos-hero-act", onClick: onStepIn, children: pres.cta });
|
|
4606
5351
|
}
|
|
4607
|
-
return /* @__PURE__ */
|
|
4608
|
-
/* @__PURE__ */
|
|
4609
|
-
/* @__PURE__ */
|
|
5352
|
+
return /* @__PURE__ */ jsxs16("div", { className: "vos-hero-agent", children: [
|
|
5353
|
+
/* @__PURE__ */ jsx17("span", { className: "vos-agent-note", children: "\u{1F916} Claude Code runs this off the dashboard" }),
|
|
5354
|
+
/* @__PURE__ */ jsx17("button", { type: "button", className: "vos-btn vos-btn-ghost vos-hero-act", onClick: onReview, children: "Review on the record \u2192" })
|
|
4610
5355
|
] });
|
|
4611
5356
|
}
|
|
4612
5357
|
function KillBanner({ count, onReview }) {
|
|
4613
|
-
return /* @__PURE__ */
|
|
4614
|
-
/* @__PURE__ */
|
|
4615
|
-
/* @__PURE__ */
|
|
4616
|
-
/* @__PURE__ */
|
|
5358
|
+
return /* @__PURE__ */ jsxs16("div", { className: "vos-banner vos-banner-crit", children: [
|
|
5359
|
+
/* @__PURE__ */ jsxs16("div", { className: "vos-banner-body", children: [
|
|
5360
|
+
/* @__PURE__ */ jsx17("b", { children: count === 1 ? "A belief has fallen into the kill lane" : `${count} beliefs have fallen into the kill lane` }),
|
|
5361
|
+
/* @__PURE__ */ jsx17("span", { children: "Confidence \u2264 \u221250 \u2014 the evidence is against it. Kill it or test it again." })
|
|
4617
5362
|
] }),
|
|
4618
|
-
/* @__PURE__ */
|
|
5363
|
+
/* @__PURE__ */ jsx17("button", { type: "button", onClick: onReview, children: "Review" })
|
|
4619
5364
|
] });
|
|
4620
5365
|
}
|
|
4621
5366
|
function OnDeckRow({
|
|
@@ -4625,47 +5370,47 @@ function OnDeckRow({
|
|
|
4625
5370
|
}) {
|
|
4626
5371
|
const pres = movePresentation(move.move);
|
|
4627
5372
|
const tone = riskLevel(move.risk);
|
|
4628
|
-
return /* @__PURE__ */
|
|
4629
|
-
/* @__PURE__ */
|
|
4630
|
-
/* @__PURE__ */
|
|
4631
|
-
/* @__PURE__ */
|
|
5373
|
+
return /* @__PURE__ */ jsxs16("div", { className: "vos-ondeck-row", children: [
|
|
5374
|
+
/* @__PURE__ */ jsx17("span", { className: "vos-risk-bar", "aria-hidden": "true", children: /* @__PURE__ */ jsx17("i", { className: `vos-fill-${tone}`, style: { width: `${riskFraction(move.risk) * 100}%` } }) }),
|
|
5375
|
+
/* @__PURE__ */ jsx17("button", { type: "button", className: "vos-ondeck-title", onClick: onOpen, children: move.title }),
|
|
5376
|
+
/* @__PURE__ */ jsx17("button", { type: "button", className: "vos-pill vos-pill-accent vos-ondeck-act", onClick: onAct, children: pres.pill })
|
|
4632
5377
|
] });
|
|
4633
5378
|
}
|
|
4634
5379
|
function WhyPanel({ top, ranked }) {
|
|
4635
|
-
return /* @__PURE__ */
|
|
4636
|
-
/* @__PURE__ */
|
|
4637
|
-
/* @__PURE__ */
|
|
4638
|
-
/* @__PURE__ */
|
|
4639
|
-
/* @__PURE__ */
|
|
5380
|
+
return /* @__PURE__ */ jsxs16("div", { className: "vos-why-panel vos-next-why", children: [
|
|
5381
|
+
/* @__PURE__ */ jsx17("p", { className: "vos-why-reason", children: top.reason }),
|
|
5382
|
+
/* @__PURE__ */ jsxs16("div", { children: [
|
|
5383
|
+
/* @__PURE__ */ jsx17("div", { className: "vos-why-section-title", children: "Where it sits" }),
|
|
5384
|
+
/* @__PURE__ */ jsx17(StageStepper, { move: top.move })
|
|
4640
5385
|
] }),
|
|
4641
|
-
/* @__PURE__ */
|
|
4642
|
-
/* @__PURE__ */
|
|
4643
|
-
/* @__PURE__ */
|
|
5386
|
+
/* @__PURE__ */ jsxs16("div", { children: [
|
|
5387
|
+
/* @__PURE__ */ jsx17("div", { className: "vos-why-section-title", children: "Why it's on top" }),
|
|
5388
|
+
/* @__PURE__ */ jsxs16("p", { className: "vos-why-formula", children: [
|
|
4644
5389
|
"Ranked by ",
|
|
4645
|
-
/* @__PURE__ */
|
|
5390
|
+
/* @__PURE__ */ jsx17("b", { children: "Feasibility \xD7 Risk" }),
|
|
4646
5391
|
" \u2014 Risk ",
|
|
4647
|
-
/* @__PURE__ */
|
|
4648
|
-
top.feasibility ? /* @__PURE__ */
|
|
5392
|
+
/* @__PURE__ */ jsx17("b", { children: Math.round(top.risk) }),
|
|
5393
|
+
top.feasibility ? /* @__PURE__ */ jsxs16(Fragment10, { children: [
|
|
4649
5394
|
" ",
|
|
4650
5395
|
"\xD7 Feasibility ",
|
|
4651
|
-
/* @__PURE__ */
|
|
4652
|
-
] }) : /* @__PURE__ */
|
|
5396
|
+
/* @__PURE__ */ jsx17("b", { children: top.feasibility })
|
|
5397
|
+
] }) : /* @__PURE__ */ jsx17(Fragment10, { children: " (no test planned yet \u2014 neutral feasibility)" }),
|
|
4653
5398
|
top.killLane ? " \xB7 in the kill lane, so it jumps the queue" : null,
|
|
4654
5399
|
"."
|
|
4655
5400
|
] })
|
|
4656
5401
|
] }),
|
|
4657
|
-
/* @__PURE__ */
|
|
4658
|
-
/* @__PURE__ */
|
|
4659
|
-
/* @__PURE__ */
|
|
4660
|
-
/* @__PURE__ */
|
|
4661
|
-
/* @__PURE__ */
|
|
5402
|
+
/* @__PURE__ */ jsxs16("div", { children: [
|
|
5403
|
+
/* @__PURE__ */ jsx17("div", { className: "vos-why-section-title", children: "The ranking" }),
|
|
5404
|
+
/* @__PURE__ */ jsx17("ol", { className: "vos-why-rank", children: ranked.slice(0, 6).map((m) => /* @__PURE__ */ jsxs16("li", { className: m.assumptionId === top.assumptionId ? "vos-why-rank-top" : "", children: [
|
|
5405
|
+
/* @__PURE__ */ jsx17("span", { className: "vos-why-rank-title", children: m.title }),
|
|
5406
|
+
/* @__PURE__ */ jsx17("span", { className: "vos-why-rank-score", children: Math.round(m.score) })
|
|
4662
5407
|
] }, m.assumptionId)) })
|
|
4663
5408
|
] })
|
|
4664
5409
|
] });
|
|
4665
5410
|
}
|
|
4666
5411
|
function StageStepper({ move }) {
|
|
4667
5412
|
const at = MOVE_STAGE[move];
|
|
4668
|
-
return /* @__PURE__ */
|
|
5413
|
+
return /* @__PURE__ */ jsx17("div", { className: "vos-stepper", "aria-label": `Stage: ${STAGES[at]}`, children: STAGES.map((label, i) => /* @__PURE__ */ jsx17(
|
|
4669
5414
|
"span",
|
|
4670
5415
|
{
|
|
4671
5416
|
className: `vos-step${i === at ? " vos-step-at" : ""}${i < at ? " vos-step-done" : ""}`,
|
|
@@ -4705,7 +5450,7 @@ function formatRoute(route) {
|
|
|
4705
5450
|
}
|
|
4706
5451
|
|
|
4707
5452
|
// src/sidebar-nav.tsx
|
|
4708
|
-
import { jsx as
|
|
5453
|
+
import { jsx as jsx18, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
4709
5454
|
function SidebarNav({
|
|
4710
5455
|
route,
|
|
4711
5456
|
onNavigate,
|
|
@@ -4714,12 +5459,12 @@ function SidebarNav({
|
|
|
4714
5459
|
registers
|
|
4715
5460
|
}) {
|
|
4716
5461
|
const activeRegister = route.name === "records" ? route.register : null;
|
|
4717
|
-
return /* @__PURE__ */
|
|
4718
|
-
/* @__PURE__ */
|
|
4719
|
-
/* @__PURE__ */
|
|
5462
|
+
return /* @__PURE__ */ jsxs17("nav", { className: "vos-nav", "aria-label": "Navigation", children: [
|
|
5463
|
+
/* @__PURE__ */ jsxs17("div", { children: [
|
|
5464
|
+
/* @__PURE__ */ jsx18("div", { className: "vos-nav-group", children: "Workflow" }),
|
|
4720
5465
|
WORKFLOW_NAV.map((item) => {
|
|
4721
5466
|
const active = route.name === item.route;
|
|
4722
|
-
return /* @__PURE__ */
|
|
5467
|
+
return /* @__PURE__ */ jsxs17(
|
|
4723
5468
|
"button",
|
|
4724
5469
|
{
|
|
4725
5470
|
type: "button",
|
|
@@ -4727,20 +5472,20 @@ function SidebarNav({
|
|
|
4727
5472
|
"aria-current": active ? "page" : void 0,
|
|
4728
5473
|
onClick: () => onNavigate({ name: item.route }),
|
|
4729
5474
|
children: [
|
|
4730
|
-
/* @__PURE__ */
|
|
5475
|
+
/* @__PURE__ */ jsx18("span", { className: "vos-nav-ic", "aria-hidden": "true", children: item.icon }),
|
|
4731
5476
|
item.label,
|
|
4732
|
-
item.isDefault ? /* @__PURE__ */
|
|
5477
|
+
item.isDefault ? /* @__PURE__ */ jsx18("span", { className: "vos-nav-default", children: "home" }) : null
|
|
4733
5478
|
]
|
|
4734
5479
|
},
|
|
4735
5480
|
item.route
|
|
4736
5481
|
);
|
|
4737
5482
|
})
|
|
4738
5483
|
] }),
|
|
4739
|
-
/* @__PURE__ */
|
|
4740
|
-
/* @__PURE__ */
|
|
5484
|
+
/* @__PURE__ */ jsxs17("div", { children: [
|
|
5485
|
+
/* @__PURE__ */ jsx18("div", { className: "vos-nav-group", children: "Records" }),
|
|
4741
5486
|
registers.map((register) => {
|
|
4742
5487
|
const active = register === activeRegister;
|
|
4743
|
-
return /* @__PURE__ */
|
|
5488
|
+
return /* @__PURE__ */ jsxs17(
|
|
4744
5489
|
"button",
|
|
4745
5490
|
{
|
|
4746
5491
|
type: "button",
|
|
@@ -4748,9 +5493,9 @@ function SidebarNav({
|
|
|
4748
5493
|
"aria-current": active ? "page" : void 0,
|
|
4749
5494
|
onClick: () => onNavigate({ name: "records", register }),
|
|
4750
5495
|
children: [
|
|
4751
|
-
/* @__PURE__ */
|
|
5496
|
+
/* @__PURE__ */ jsx18("span", { className: "vos-nav-ic", "aria-hidden": "true", children: REGISTER_ICON[register] }),
|
|
4752
5497
|
REGISTER_LABEL[register],
|
|
4753
|
-
needsHuman?.[register] ? /* @__PURE__ */
|
|
5498
|
+
needsHuman?.[register] ? /* @__PURE__ */ jsx18(
|
|
4754
5499
|
"span",
|
|
4755
5500
|
{
|
|
4756
5501
|
className: "vos-nav-alert",
|
|
@@ -4758,7 +5503,7 @@ function SidebarNav({
|
|
|
4758
5503
|
children: formatCount(needsHuman[register] ?? 0)
|
|
4759
5504
|
}
|
|
4760
5505
|
) : null,
|
|
4761
|
-
/* @__PURE__ */
|
|
5506
|
+
/* @__PURE__ */ jsx18("span", { className: "vos-nav-count vos-num", children: counts?.[register] !== void 0 ? formatCount(counts[register] ?? 0) : "\xB7" })
|
|
4762
5507
|
]
|
|
4763
5508
|
},
|
|
4764
5509
|
register
|
|
@@ -4819,7 +5564,7 @@ function useNeedsHuman(basePath = "/api") {
|
|
|
4819
5564
|
}
|
|
4820
5565
|
|
|
4821
5566
|
// src/dashboard-app.tsx
|
|
4822
|
-
import { jsx as
|
|
5567
|
+
import { jsx as jsx19, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
4823
5568
|
function initialsOf(name) {
|
|
4824
5569
|
const parts = name.trim().split(/\s+/);
|
|
4825
5570
|
const first = parts[0]?.[0] ?? "";
|
|
@@ -4861,33 +5606,33 @@ function ValidationOSDashboard({ config = {} }) {
|
|
|
4861
5606
|
}, []);
|
|
4862
5607
|
const brandName = branding?.name ?? "Validation-OS";
|
|
4863
5608
|
const brandMark = branding?.initials ?? "V";
|
|
4864
|
-
return /* @__PURE__ */
|
|
4865
|
-
/* @__PURE__ */
|
|
4866
|
-
/* @__PURE__ */
|
|
5609
|
+
return /* @__PURE__ */ jsxs18("div", { className: "vos-app", children: [
|
|
5610
|
+
/* @__PURE__ */ jsxs18("div", { className: "vos-brand", children: [
|
|
5611
|
+
/* @__PURE__ */ jsx19("span", { className: "vos-brand-dot", children: branding?.logoUrl ? /* @__PURE__ */ jsx19("img", { src: branding.logoUrl, alt: "" }) : brandMark }),
|
|
4867
5612
|
" ",
|
|
4868
5613
|
brandName
|
|
4869
5614
|
] }),
|
|
4870
|
-
/* @__PURE__ */
|
|
4871
|
-
backendLabel ? /* @__PURE__ */
|
|
4872
|
-
/* @__PURE__ */
|
|
5615
|
+
/* @__PURE__ */ jsxs18("div", { className: "vos-topbar", children: [
|
|
5616
|
+
backendLabel ? /* @__PURE__ */ jsxs18("div", { className: "vos-backend", children: [
|
|
5617
|
+
/* @__PURE__ */ jsx19("span", { className: "vos-live-dot" }),
|
|
4873
5618
|
" Backend: ",
|
|
4874
|
-
/* @__PURE__ */
|
|
5619
|
+
/* @__PURE__ */ jsx19("b", { children: backendLabel })
|
|
4875
5620
|
] }) : null,
|
|
4876
|
-
agentLabel ? /* @__PURE__ */
|
|
5621
|
+
agentLabel ? /* @__PURE__ */ jsxs18("span", { className: "vos-hint", children: [
|
|
4877
5622
|
"Agent: ",
|
|
4878
|
-
/* @__PURE__ */
|
|
5623
|
+
/* @__PURE__ */ jsx19("b", { style: { color: "var(--vos-text)" }, children: agentLabel })
|
|
4879
5624
|
] }) : null,
|
|
4880
|
-
/* @__PURE__ */
|
|
4881
|
-
/* @__PURE__ */
|
|
4882
|
-
user?.name ? /* @__PURE__ */
|
|
4883
|
-
/* @__PURE__ */
|
|
4884
|
-
/* @__PURE__ */
|
|
4885
|
-
/* @__PURE__ */
|
|
4886
|
-
user.caption ? /* @__PURE__ */
|
|
5625
|
+
/* @__PURE__ */ jsx19("div", { className: "vos-spacer" }),
|
|
5626
|
+
/* @__PURE__ */ jsx19("button", { type: "button", className: "vos-iconbtn", onClick: toggleTheme, children: "\u25D0 Theme" }),
|
|
5627
|
+
user?.name ? /* @__PURE__ */ jsxs18("div", { className: "vos-user", children: [
|
|
5628
|
+
/* @__PURE__ */ jsx19("span", { className: "vos-avatar", children: initialsOf(user.name) }),
|
|
5629
|
+
/* @__PURE__ */ jsxs18("div", { children: [
|
|
5630
|
+
/* @__PURE__ */ jsx19("span", { className: "vos-user-name", children: user.name }),
|
|
5631
|
+
user.caption ? /* @__PURE__ */ jsx19("small", { children: user.caption }) : null
|
|
4887
5632
|
] })
|
|
4888
5633
|
] }) : null
|
|
4889
5634
|
] }),
|
|
4890
|
-
/* @__PURE__ */
|
|
5635
|
+
/* @__PURE__ */ jsx19(
|
|
4891
5636
|
SidebarNav,
|
|
4892
5637
|
{
|
|
4893
5638
|
route,
|
|
@@ -4897,7 +5642,7 @@ function ValidationOSDashboard({ config = {} }) {
|
|
|
4897
5642
|
registers
|
|
4898
5643
|
}
|
|
4899
5644
|
),
|
|
4900
|
-
/* @__PURE__ */
|
|
5645
|
+
/* @__PURE__ */ jsx19("main", { className: "vos-main", children: route.name === "records" ? /* @__PURE__ */ jsx19(
|
|
4901
5646
|
RegisterBrowser,
|
|
4902
5647
|
{
|
|
4903
5648
|
register: route.register,
|
|
@@ -4906,7 +5651,7 @@ function ValidationOSDashboard({ config = {} }) {
|
|
|
4906
5651
|
onOpenRecord: (id) => navigate({ name: "record", id })
|
|
4907
5652
|
},
|
|
4908
5653
|
route.register
|
|
4909
|
-
) : route.name === "record" ? /* @__PURE__ */
|
|
5654
|
+
) : route.name === "record" ? /* @__PURE__ */ jsx19(
|
|
4910
5655
|
RecordPage,
|
|
4911
5656
|
{
|
|
4912
5657
|
recordId: route.id,
|
|
@@ -4915,28 +5660,128 @@ function ValidationOSDashboard({ config = {} }) {
|
|
|
4915
5660
|
basePath
|
|
4916
5661
|
},
|
|
4917
5662
|
route.id
|
|
4918
|
-
) : route.name === "pipeline" ? /* @__PURE__ */
|
|
5663
|
+
) : route.name === "pipeline" ? /* @__PURE__ */ jsx19(PipelineSurface, { basePath, onNavigate: navigate }, "pipeline") : /* @__PURE__ */ jsx19(NextMoveSurface, { basePath, onNavigate: navigate }, "next") })
|
|
5664
|
+
] });
|
|
5665
|
+
}
|
|
5666
|
+
|
|
5667
|
+
// src/connect.ts
|
|
5668
|
+
var DEFAULT_TOKEN_ENV = "VALIDATION_OS_TOKEN";
|
|
5669
|
+
var SHELL_UNSAFE = /['"\\\s]/;
|
|
5670
|
+
function composeConnectCommand(input) {
|
|
5671
|
+
const tokenEnv = input.tokenEnv ?? DEFAULT_TOKEN_ENV;
|
|
5672
|
+
const guarded = [
|
|
5673
|
+
["Token", input.token],
|
|
5674
|
+
["API base URL", input.apiBaseUrl]
|
|
5675
|
+
];
|
|
5676
|
+
for (const [label, value] of guarded) {
|
|
5677
|
+
if (SHELL_UNSAFE.test(value)) {
|
|
5678
|
+
throw new Error(`${label} contains characters that can't be safely pasted.`);
|
|
5679
|
+
}
|
|
5680
|
+
}
|
|
5681
|
+
return [
|
|
5682
|
+
`export ${tokenEnv}='${input.token}'`,
|
|
5683
|
+
`cat > validation-os.config.yaml <<'EOF'`,
|
|
5684
|
+
`connector: remote-api`,
|
|
5685
|
+
`remote_api:`,
|
|
5686
|
+
` api_base_url: ${input.apiBaseUrl}`,
|
|
5687
|
+
` token_env: ${tokenEnv}`,
|
|
5688
|
+
`EOF`
|
|
5689
|
+
].join("\n");
|
|
5690
|
+
}
|
|
5691
|
+
|
|
5692
|
+
// src/connect-claude-code.tsx
|
|
5693
|
+
import { useState as useState14 } from "react";
|
|
5694
|
+
import { jsx as jsx20, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
5695
|
+
function ConnectClaudeCode({
|
|
5696
|
+
apiBaseUrl,
|
|
5697
|
+
tokenEnv,
|
|
5698
|
+
mintToken
|
|
5699
|
+
}) {
|
|
5700
|
+
const [state, setState] = useState14({ phase: "idle" });
|
|
5701
|
+
const [copied, setCopied] = useState14(false);
|
|
5702
|
+
async function generate() {
|
|
5703
|
+
setState({ phase: "minting" });
|
|
5704
|
+
setCopied(false);
|
|
5705
|
+
try {
|
|
5706
|
+
const token = await mintToken();
|
|
5707
|
+
const command = composeConnectCommand({ token, apiBaseUrl, tokenEnv });
|
|
5708
|
+
setState({ phase: "ready", command });
|
|
5709
|
+
} catch (e) {
|
|
5710
|
+
setState({
|
|
5711
|
+
phase: "error",
|
|
5712
|
+
message: e instanceof Error ? e.message : "Couldn't generate your connection command."
|
|
5713
|
+
});
|
|
5714
|
+
}
|
|
5715
|
+
}
|
|
5716
|
+
async function copy(command) {
|
|
5717
|
+
try {
|
|
5718
|
+
await navigator.clipboard.writeText(command);
|
|
5719
|
+
setCopied(true);
|
|
5720
|
+
} catch {
|
|
5721
|
+
}
|
|
5722
|
+
}
|
|
5723
|
+
return /* @__PURE__ */ jsxs19("div", { children: [
|
|
5724
|
+
/* @__PURE__ */ jsx20("div", { className: "vos-head", children: /* @__PURE__ */ jsxs19("div", { children: [
|
|
5725
|
+
/* @__PURE__ */ jsx20("h1", { children: "Connect Claude Code" }),
|
|
5726
|
+
/* @__PURE__ */ jsx20("p", { children: "Run the validation skills against this register from your own Claude Code \u2014 no repo, no keys to hunt down." })
|
|
5727
|
+
] }) }),
|
|
5728
|
+
/* @__PURE__ */ jsxs19("ol", { className: "vos-hint", style: { lineHeight: 1.8 }, children: [
|
|
5729
|
+
/* @__PURE__ */ jsx20("li", { children: "Generate your personal connection command below." }),
|
|
5730
|
+
/* @__PURE__ */ jsx20("li", { children: "Paste it into a terminal in the workspace you'll run the skills in." }),
|
|
5731
|
+
/* @__PURE__ */ jsxs19("li", { children: [
|
|
5732
|
+
"The command carries a token tied to ",
|
|
5733
|
+
/* @__PURE__ */ jsx20("strong", { children: "you" }),
|
|
5734
|
+
" \u2014 anything you write lands under your name. Don't share it."
|
|
5735
|
+
] })
|
|
5736
|
+
] }),
|
|
5737
|
+
state.phase !== "ready" ? /* @__PURE__ */ jsx20(
|
|
5738
|
+
"button",
|
|
5739
|
+
{
|
|
5740
|
+
type: "button",
|
|
5741
|
+
className: "vos-btn",
|
|
5742
|
+
onClick: generate,
|
|
5743
|
+
disabled: state.phase === "minting",
|
|
5744
|
+
children: state.phase === "minting" ? "Generating\u2026" : "Generate connection command"
|
|
5745
|
+
}
|
|
5746
|
+
) : null,
|
|
5747
|
+
state.phase === "error" ? /* @__PURE__ */ jsx20("p", { className: "vos-hint", role: "alert", children: state.message }) : null,
|
|
5748
|
+
state.phase === "ready" ? /* @__PURE__ */ jsxs19("div", { children: [
|
|
5749
|
+
/* @__PURE__ */ jsx20("pre", { className: "vos-code", "aria-label": "Connection command", children: state.command }),
|
|
5750
|
+
/* @__PURE__ */ jsxs19("div", { style: { display: "flex", gap: 8 }, children: [
|
|
5751
|
+
/* @__PURE__ */ jsx20(
|
|
5752
|
+
"button",
|
|
5753
|
+
{
|
|
5754
|
+
type: "button",
|
|
5755
|
+
className: "vos-btn",
|
|
5756
|
+
onClick: () => copy(state.command),
|
|
5757
|
+
children: copied ? "Copied" : "Copy command"
|
|
5758
|
+
}
|
|
5759
|
+
),
|
|
5760
|
+
/* @__PURE__ */ jsx20("button", { type: "button", className: "vos-btn-ghost", onClick: generate, children: "Regenerate" })
|
|
5761
|
+
] }),
|
|
5762
|
+
/* @__PURE__ */ jsx20("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." })
|
|
5763
|
+
] }) : null
|
|
4919
5764
|
] });
|
|
4920
5765
|
}
|
|
4921
5766
|
|
|
4922
5767
|
// src/surface-placeholder.tsx
|
|
4923
|
-
import { jsx as
|
|
5768
|
+
import { jsx as jsx21, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
4924
5769
|
function SurfacePlaceholder({
|
|
4925
5770
|
title,
|
|
4926
5771
|
subtitle,
|
|
4927
5772
|
detail
|
|
4928
5773
|
}) {
|
|
4929
|
-
return /* @__PURE__ */
|
|
4930
|
-
/* @__PURE__ */
|
|
4931
|
-
/* @__PURE__ */
|
|
4932
|
-
/* @__PURE__ */
|
|
5774
|
+
return /* @__PURE__ */ jsxs20("div", { children: [
|
|
5775
|
+
/* @__PURE__ */ jsx21("div", { className: "vos-head", children: /* @__PURE__ */ jsxs20("div", { children: [
|
|
5776
|
+
/* @__PURE__ */ jsx21("h1", { children: title }),
|
|
5777
|
+
/* @__PURE__ */ jsx21("p", { children: subtitle })
|
|
4933
5778
|
] }) }),
|
|
4934
|
-
/* @__PURE__ */
|
|
5779
|
+
/* @__PURE__ */ jsx21("div", { className: "vos-empty", children: detail })
|
|
4935
5780
|
] });
|
|
4936
5781
|
}
|
|
4937
5782
|
|
|
4938
5783
|
// src/register-counts.tsx
|
|
4939
|
-
import { jsx as
|
|
5784
|
+
import { jsx as jsx22, jsxs as jsxs21 } from "react/jsx-runtime";
|
|
4940
5785
|
function RegisterCounts({
|
|
4941
5786
|
counts,
|
|
4942
5787
|
caption,
|
|
@@ -4946,8 +5791,8 @@ function RegisterCounts({
|
|
|
4946
5791
|
const registers = REGISTER_ORDER.filter(
|
|
4947
5792
|
(r) => counts[r] !== void 0
|
|
4948
5793
|
);
|
|
4949
|
-
return /* @__PURE__ */
|
|
4950
|
-
/* @__PURE__ */
|
|
5794
|
+
return /* @__PURE__ */ jsxs21("section", { "aria-label": "Register counts", children: [
|
|
5795
|
+
/* @__PURE__ */ jsx22("div", { className: "vos-tile-grid", children: registers.map((register) => /* @__PURE__ */ jsx22(
|
|
4951
5796
|
StatTile,
|
|
4952
5797
|
{
|
|
4953
5798
|
label: REGISTER_LABEL[register],
|
|
@@ -4957,18 +5802,23 @@ function RegisterCounts({
|
|
|
4957
5802
|
},
|
|
4958
5803
|
register
|
|
4959
5804
|
)) }),
|
|
4960
|
-
caption ? /* @__PURE__ */
|
|
5805
|
+
caption ? /* @__PURE__ */ jsx22("p", { className: "vos-hint", style: { marginTop: 16 }, children: caption }) : null
|
|
4961
5806
|
] });
|
|
4962
5807
|
}
|
|
4963
5808
|
export {
|
|
4964
5809
|
BeliefJourney,
|
|
5810
|
+
BeliefVerdicts,
|
|
4965
5811
|
CONFLICT_MESSAGE,
|
|
4966
5812
|
ConfidenceCell,
|
|
5813
|
+
ConnectClaudeCode,
|
|
5814
|
+
DEFAULT_TOKEN_ENV,
|
|
5815
|
+
DIRECT_CYCLE_KEY,
|
|
4967
5816
|
EditBeliefForm,
|
|
4968
5817
|
EditFields,
|
|
4969
5818
|
FIRST_RUN_LINE,
|
|
4970
5819
|
FieldInput,
|
|
4971
5820
|
GlossaryText,
|
|
5821
|
+
Markdown,
|
|
4972
5822
|
NextMoveSurface,
|
|
4973
5823
|
PipelineSurface,
|
|
4974
5824
|
REGISTER_GROUPS,
|
|
@@ -4997,6 +5847,8 @@ export {
|
|
|
4997
5847
|
ValidationOSDashboard,
|
|
4998
5848
|
WriteDecisionForm,
|
|
4999
5849
|
backlinkPanels,
|
|
5850
|
+
bodyPreview,
|
|
5851
|
+
buildCycles,
|
|
5000
5852
|
buildJourney,
|
|
5001
5853
|
buildPatch,
|
|
5002
5854
|
buildPipeline,
|
|
@@ -5005,9 +5857,11 @@ export {
|
|
|
5005
5857
|
cellValue,
|
|
5006
5858
|
coldStartFor,
|
|
5007
5859
|
columnsFor,
|
|
5860
|
+
composeConnectCommand,
|
|
5008
5861
|
confidenceTone,
|
|
5009
5862
|
configureRiskBands,
|
|
5010
5863
|
defaultTabId,
|
|
5864
|
+
detailRows,
|
|
5011
5865
|
dontConfuseWith,
|
|
5012
5866
|
draftFrom,
|
|
5013
5867
|
editableFields,
|
|
@@ -5034,8 +5888,12 @@ export {
|
|
|
5034
5888
|
movePresentation,
|
|
5035
5889
|
needsHumanCounts,
|
|
5036
5890
|
nestReadingsByPlan,
|
|
5891
|
+
ownerNames,
|
|
5037
5892
|
parseRoute,
|
|
5038
5893
|
primaryLabel,
|
|
5894
|
+
readingAssumptionChips,
|
|
5895
|
+
readingBeliefVerdicts,
|
|
5896
|
+
resolveBarLines,
|
|
5039
5897
|
riskBand,
|
|
5040
5898
|
riskFraction,
|
|
5041
5899
|
riskLevel,
|