@kontourai/survey 0.4.8 → 0.4.10
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/README.md +10 -0
- package/dist/src/review-workbench/review-workbench.css +73 -7
- package/dist/src/review-workbench/review-workbench.d.ts +12 -0
- package/dist/src/review-workbench/review-workbench.js +54 -0
- package/dist/src/review-workbench/review-workbench.standalone.css +73 -7
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -87,6 +87,16 @@ application's `body` or `:root` styles. Hosts should mount into an element like:
|
|
|
87
87
|
The package also exposes `@kontourai/survey/review-workbench/standalone.css` for
|
|
88
88
|
the standalone demo page. Use that only when Survey owns the whole page.
|
|
89
89
|
|
|
90
|
+
For the full consumer path from `ReviewItem` construction through persisted
|
|
91
|
+
review events, exported results, and optional Surface projection, see
|
|
92
|
+
[`docs/consumer-integration-guide.md`](docs/consumer-integration-guide.md).
|
|
93
|
+
That guide also covers the server-side apply boundary: producers should derive
|
|
94
|
+
write results from reviewed snapshots plus persisted events, not from
|
|
95
|
+
browser-computed decisions or exported result payloads.
|
|
96
|
+
For the current decision on why Survey is not adding a generic review adapter
|
|
97
|
+
builder yet, see
|
|
98
|
+
[`docs/consumer-adapter-abstraction-assessment.md`](docs/consumer-adapter-abstraction-assessment.md).
|
|
99
|
+
|
|
90
100
|
## Contributor checks
|
|
91
101
|
|
|
92
102
|
Install the repo-owned Git hooks once per clone:
|
|
@@ -231,6 +231,7 @@
|
|
|
231
231
|
.survey-workbench-embed .workbench{
|
|
232
232
|
position: relative;
|
|
233
233
|
z-index: 1;
|
|
234
|
+
container-type: inline-size;
|
|
234
235
|
min-height: 100vh;
|
|
235
236
|
padding: 30px 26px 60px;
|
|
236
237
|
}
|
|
@@ -239,7 +240,7 @@
|
|
|
239
240
|
display: grid;
|
|
240
241
|
grid-template-rows: auto minmax(0, 1fr);
|
|
241
242
|
gap: 22px;
|
|
242
|
-
max-width:
|
|
243
|
+
max-width: 1360px;
|
|
243
244
|
margin: 0 auto;
|
|
244
245
|
}
|
|
245
246
|
|
|
@@ -359,7 +360,7 @@
|
|
|
359
360
|
|
|
360
361
|
.survey-workbench-embed .queue-layout{
|
|
361
362
|
display: grid;
|
|
362
|
-
grid-template-columns:
|
|
363
|
+
grid-template-columns: 280px minmax(0, 1fr);
|
|
363
364
|
gap: 22px;
|
|
364
365
|
align-items: start;
|
|
365
366
|
}
|
|
@@ -636,10 +637,11 @@
|
|
|
636
637
|
|
|
637
638
|
.survey-workbench-embed .content-grid{
|
|
638
639
|
display: grid;
|
|
639
|
-
grid-template-columns: minmax(0, 1fr)
|
|
640
|
+
grid-template-columns: minmax(0, 1fr);
|
|
640
641
|
grid-template-areas:
|
|
641
|
-
"focus
|
|
642
|
-
"
|
|
642
|
+
"focus"
|
|
643
|
+
"decision"
|
|
644
|
+
"candidates";
|
|
643
645
|
gap: 22px;
|
|
644
646
|
align-items: start;
|
|
645
647
|
}
|
|
@@ -774,7 +776,7 @@
|
|
|
774
776
|
display: grid;
|
|
775
777
|
grid-template-rows: auto auto minmax(0, 1fr);
|
|
776
778
|
gap: 16px;
|
|
777
|
-
min-height:
|
|
779
|
+
min-height: 460px;
|
|
778
780
|
padding: 20px;
|
|
779
781
|
position: relative;
|
|
780
782
|
overflow: hidden;
|
|
@@ -916,6 +918,7 @@
|
|
|
916
918
|
.survey-workbench-embed .decision-column{
|
|
917
919
|
grid-area: decision;
|
|
918
920
|
display: grid;
|
|
921
|
+
grid-template-columns: minmax(0, 1fr);
|
|
919
922
|
gap: 18px;
|
|
920
923
|
animation: rise 0.6s cubic-bezier(0.22, 1, 0.36, 1) both;
|
|
921
924
|
animation-delay: 0.15s;
|
|
@@ -1068,7 +1071,7 @@
|
|
|
1068
1071
|
|
|
1069
1072
|
.survey-workbench-embed .preview-section-grid{
|
|
1070
1073
|
display: grid;
|
|
1071
|
-
grid-template-columns: minmax(0, 1fr);
|
|
1074
|
+
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
1072
1075
|
gap: 10px;
|
|
1073
1076
|
}
|
|
1074
1077
|
|
|
@@ -1271,6 +1274,69 @@
|
|
|
1271
1274
|
}
|
|
1272
1275
|
}
|
|
1273
1276
|
|
|
1277
|
+
@container (max-width: 1100px) {
|
|
1278
|
+
.survey-workbench-embed .topbar,
|
|
1279
|
+
.survey-workbench-embed .queue-layout,
|
|
1280
|
+
.survey-workbench-embed .focus-evidence{
|
|
1281
|
+
grid-template-columns: 1fr;
|
|
1282
|
+
}
|
|
1283
|
+
|
|
1284
|
+
.survey-workbench-embed .queue-layout{
|
|
1285
|
+
grid-template-areas:
|
|
1286
|
+
"content"
|
|
1287
|
+
"queue";
|
|
1288
|
+
}
|
|
1289
|
+
|
|
1290
|
+
.survey-workbench-embed .queue-panel{
|
|
1291
|
+
grid-area: queue;
|
|
1292
|
+
position: static;
|
|
1293
|
+
}
|
|
1294
|
+
|
|
1295
|
+
.survey-workbench-embed .content-grid{
|
|
1296
|
+
grid-area: content;
|
|
1297
|
+
grid-template-columns: 1fr;
|
|
1298
|
+
grid-template-areas:
|
|
1299
|
+
"focus"
|
|
1300
|
+
"decision"
|
|
1301
|
+
"candidates";
|
|
1302
|
+
}
|
|
1303
|
+
|
|
1304
|
+
.survey-workbench-embed .content-grid,
|
|
1305
|
+
.survey-workbench-embed .review-main,
|
|
1306
|
+
.survey-workbench-embed .candidate-grid,
|
|
1307
|
+
.survey-workbench-embed .decision-column{
|
|
1308
|
+
min-width: 0;
|
|
1309
|
+
}
|
|
1310
|
+
}
|
|
1311
|
+
|
|
1312
|
+
@container (max-width: 860px) {
|
|
1313
|
+
.survey-workbench-embed .candidate-grid,
|
|
1314
|
+
.survey-workbench-embed .focus-values,
|
|
1315
|
+
.survey-workbench-embed .preview-section-grid{
|
|
1316
|
+
grid-template-columns: 1fr;
|
|
1317
|
+
}
|
|
1318
|
+
|
|
1319
|
+
.survey-workbench-embed .candidate-grid::before{
|
|
1320
|
+
display: none;
|
|
1321
|
+
}
|
|
1322
|
+
|
|
1323
|
+
.survey-workbench-embed .candidate-card{
|
|
1324
|
+
min-height: auto;
|
|
1325
|
+
}
|
|
1326
|
+
}
|
|
1327
|
+
|
|
1328
|
+
@container (max-width: 620px) {
|
|
1329
|
+
.survey-workbench-embed .topbar .meta-grid{
|
|
1330
|
+
display: none;
|
|
1331
|
+
}
|
|
1332
|
+
|
|
1333
|
+
.survey-workbench-embed .decision-buttons,
|
|
1334
|
+
.survey-workbench-embed .summary-grid,
|
|
1335
|
+
.survey-workbench-embed .audit-grid{
|
|
1336
|
+
grid-template-columns: 1fr;
|
|
1337
|
+
}
|
|
1338
|
+
}
|
|
1339
|
+
|
|
1274
1340
|
@media (max-width: 560px) {
|
|
1275
1341
|
.survey-workbench-embed .workbench{
|
|
1276
1342
|
padding: 14px 10px 36px;
|
|
@@ -9,6 +9,15 @@ export interface ReviewWorkbenchSessionExport {
|
|
|
9
9
|
readonly decisions: readonly ReviewDecision[];
|
|
10
10
|
readonly results: readonly ReviewWorkbenchResult[];
|
|
11
11
|
}
|
|
12
|
+
export type ReviewSessionReplayIssueCode = "unknown-active-item" | "unknown-review-item" | "unknown-candidate";
|
|
13
|
+
export interface ReviewSessionReplayIssue {
|
|
14
|
+
readonly code: ReviewSessionReplayIssueCode;
|
|
15
|
+
readonly eventName: string;
|
|
16
|
+
readonly sequence: number;
|
|
17
|
+
readonly reviewItemName?: string;
|
|
18
|
+
readonly candidateId?: string;
|
|
19
|
+
readonly message: string;
|
|
20
|
+
}
|
|
12
21
|
export interface ReviewSessionEventStore {
|
|
13
22
|
load(session: ReviewQueueSessionState): readonly ReviewSessionEvent[] | undefined;
|
|
14
23
|
save(session: ReviewQueueSessionState, events: readonly ReviewSessionEvent[]): void;
|
|
@@ -54,6 +63,9 @@ export interface ReviewWorkbenchResult {
|
|
|
54
63
|
export declare function buildReviewDecisionsFromSession(session: ReviewQueueSessionState): ReviewDecision[];
|
|
55
64
|
export declare function buildReviewWorkbenchResultsFromSession(session: ReviewQueueSessionState): ReviewWorkbenchResult[];
|
|
56
65
|
export declare function buildReviewWorkbenchSessionExport(session: ReviewQueueSessionState, events?: readonly ReviewSessionEvent[]): ReviewWorkbenchSessionExport;
|
|
66
|
+
export declare function validateReviewSessionEventsForSnapshot(snapshot: ReviewQueueSessionState, events: readonly ReviewSessionEvent[]): ReviewSessionReplayIssue[];
|
|
67
|
+
export declare function replayReviewSessionEventsForSnapshot(snapshot: ReviewQueueSessionState, events: readonly ReviewSessionEvent[]): ReviewQueueSessionState;
|
|
68
|
+
export declare function buildReviewWorkbenchSessionExportForSnapshot(snapshot: ReviewQueueSessionState, events: readonly ReviewSessionEvent[]): ReviewWorkbenchSessionExport;
|
|
57
69
|
export declare function createInMemoryReviewSessionEventStore(initialEvents?: readonly ReviewSessionEvent[]): ReviewSessionEventStore & {
|
|
58
70
|
events(): readonly ReviewSessionEvent[];
|
|
59
71
|
};
|
|
@@ -89,6 +89,60 @@ export function buildReviewWorkbenchSessionExport(session, events = buildReviewS
|
|
|
89
89
|
results: buildReviewWorkbenchResultsFromSession(session),
|
|
90
90
|
};
|
|
91
91
|
}
|
|
92
|
+
export function validateReviewSessionEventsForSnapshot(snapshot, events) {
|
|
93
|
+
const itemsByName = new Map(snapshot.items.map((item) => [item.metadata.name, item]));
|
|
94
|
+
return events.flatMap((event) => {
|
|
95
|
+
const issues = [];
|
|
96
|
+
const activeItemName = event.spec.activeItemName;
|
|
97
|
+
const reviewItemName = event.spec.reviewItemName;
|
|
98
|
+
const itemName = reviewItemName ?? activeItemName;
|
|
99
|
+
const eventRef = {
|
|
100
|
+
eventName: event.metadata.name,
|
|
101
|
+
sequence: event.spec.sequence,
|
|
102
|
+
};
|
|
103
|
+
if (activeItemName && !itemsByName.has(activeItemName)) {
|
|
104
|
+
issues.push({
|
|
105
|
+
...eventRef,
|
|
106
|
+
code: "unknown-active-item",
|
|
107
|
+
reviewItemName: activeItemName,
|
|
108
|
+
message: `ReviewSessionEvent ${event.metadata.name} references active item ${activeItemName}, but the supplied session snapshot does not contain that ReviewItem.`,
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
if (reviewItemName && !itemsByName.has(reviewItemName)) {
|
|
112
|
+
issues.push({
|
|
113
|
+
...eventRef,
|
|
114
|
+
code: "unknown-review-item",
|
|
115
|
+
reviewItemName,
|
|
116
|
+
message: `ReviewSessionEvent ${event.metadata.name} references review item ${reviewItemName}, but the supplied session snapshot does not contain that ReviewItem.`,
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
if (event.spec.candidateId && itemName && itemsByName.has(itemName)) {
|
|
120
|
+
const item = itemsByName.get(itemName);
|
|
121
|
+
const hasCandidate = item?.spec.candidates.some((candidate) => candidate.id === event.spec.candidateId);
|
|
122
|
+
if (!hasCandidate) {
|
|
123
|
+
issues.push({
|
|
124
|
+
...eventRef,
|
|
125
|
+
code: "unknown-candidate",
|
|
126
|
+
reviewItemName: itemName,
|
|
127
|
+
candidateId: event.spec.candidateId,
|
|
128
|
+
message: `ReviewSessionEvent ${event.metadata.name} references candidate ${event.spec.candidateId}, but ReviewItem ${itemName} in the supplied session snapshot does not contain that candidate.`,
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return issues;
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
export function replayReviewSessionEventsForSnapshot(snapshot, events) {
|
|
136
|
+
const issues = validateReviewSessionEventsForSnapshot(snapshot, events);
|
|
137
|
+
if (issues.length > 0) {
|
|
138
|
+
throw new Error(`Review session events do not match the supplied session snapshot: ${issues.map((issue) => issue.message).join(" ")}`);
|
|
139
|
+
}
|
|
140
|
+
return replayReviewSessionEvents(snapshot, events);
|
|
141
|
+
}
|
|
142
|
+
export function buildReviewWorkbenchSessionExportForSnapshot(snapshot, events) {
|
|
143
|
+
const replayedSession = replayReviewSessionEventsForSnapshot(snapshot, events);
|
|
144
|
+
return buildReviewWorkbenchSessionExport(replayedSession, events);
|
|
145
|
+
}
|
|
92
146
|
export function createInMemoryReviewSessionEventStore(initialEvents = []) {
|
|
93
147
|
let savedEvents = [...initialEvents];
|
|
94
148
|
return {
|
|
@@ -78,6 +78,7 @@ p {
|
|
|
78
78
|
.workbench {
|
|
79
79
|
position: relative;
|
|
80
80
|
z-index: 1;
|
|
81
|
+
container-type: inline-size;
|
|
81
82
|
min-height: 100vh;
|
|
82
83
|
padding: 30px 26px 60px;
|
|
83
84
|
}
|
|
@@ -86,7 +87,7 @@ p {
|
|
|
86
87
|
display: grid;
|
|
87
88
|
grid-template-rows: auto minmax(0, 1fr);
|
|
88
89
|
gap: 22px;
|
|
89
|
-
max-width:
|
|
90
|
+
max-width: 1360px;
|
|
90
91
|
margin: 0 auto;
|
|
91
92
|
}
|
|
92
93
|
|
|
@@ -206,7 +207,7 @@ h1 {
|
|
|
206
207
|
|
|
207
208
|
.queue-layout {
|
|
208
209
|
display: grid;
|
|
209
|
-
grid-template-columns:
|
|
210
|
+
grid-template-columns: 280px minmax(0, 1fr);
|
|
210
211
|
gap: 22px;
|
|
211
212
|
align-items: start;
|
|
212
213
|
}
|
|
@@ -483,10 +484,11 @@ h1 {
|
|
|
483
484
|
|
|
484
485
|
.content-grid {
|
|
485
486
|
display: grid;
|
|
486
|
-
grid-template-columns: minmax(0, 1fr)
|
|
487
|
+
grid-template-columns: minmax(0, 1fr);
|
|
487
488
|
grid-template-areas:
|
|
488
|
-
"focus
|
|
489
|
-
"
|
|
489
|
+
"focus"
|
|
490
|
+
"decision"
|
|
491
|
+
"candidates";
|
|
490
492
|
gap: 22px;
|
|
491
493
|
align-items: start;
|
|
492
494
|
}
|
|
@@ -621,7 +623,7 @@ h1 {
|
|
|
621
623
|
display: grid;
|
|
622
624
|
grid-template-rows: auto auto minmax(0, 1fr);
|
|
623
625
|
gap: 16px;
|
|
624
|
-
min-height:
|
|
626
|
+
min-height: 460px;
|
|
625
627
|
padding: 20px;
|
|
626
628
|
position: relative;
|
|
627
629
|
overflow: hidden;
|
|
@@ -763,6 +765,7 @@ h1 {
|
|
|
763
765
|
.decision-column {
|
|
764
766
|
grid-area: decision;
|
|
765
767
|
display: grid;
|
|
768
|
+
grid-template-columns: minmax(0, 1fr);
|
|
766
769
|
gap: 18px;
|
|
767
770
|
animation: rise 0.6s cubic-bezier(0.22, 1, 0.36, 1) both;
|
|
768
771
|
animation-delay: 0.15s;
|
|
@@ -915,7 +918,7 @@ textarea:focus {
|
|
|
915
918
|
|
|
916
919
|
.preview-section-grid {
|
|
917
920
|
display: grid;
|
|
918
|
-
grid-template-columns: minmax(0, 1fr);
|
|
921
|
+
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
919
922
|
gap: 10px;
|
|
920
923
|
}
|
|
921
924
|
|
|
@@ -1118,6 +1121,69 @@ pre {
|
|
|
1118
1121
|
}
|
|
1119
1122
|
}
|
|
1120
1123
|
|
|
1124
|
+
@container (max-width: 1100px) {
|
|
1125
|
+
.topbar,
|
|
1126
|
+
.queue-layout,
|
|
1127
|
+
.focus-evidence {
|
|
1128
|
+
grid-template-columns: 1fr;
|
|
1129
|
+
}
|
|
1130
|
+
|
|
1131
|
+
.queue-layout {
|
|
1132
|
+
grid-template-areas:
|
|
1133
|
+
"content"
|
|
1134
|
+
"queue";
|
|
1135
|
+
}
|
|
1136
|
+
|
|
1137
|
+
.queue-panel {
|
|
1138
|
+
grid-area: queue;
|
|
1139
|
+
position: static;
|
|
1140
|
+
}
|
|
1141
|
+
|
|
1142
|
+
.content-grid {
|
|
1143
|
+
grid-area: content;
|
|
1144
|
+
grid-template-columns: 1fr;
|
|
1145
|
+
grid-template-areas:
|
|
1146
|
+
"focus"
|
|
1147
|
+
"decision"
|
|
1148
|
+
"candidates";
|
|
1149
|
+
}
|
|
1150
|
+
|
|
1151
|
+
.content-grid,
|
|
1152
|
+
.review-main,
|
|
1153
|
+
.candidate-grid,
|
|
1154
|
+
.decision-column {
|
|
1155
|
+
min-width: 0;
|
|
1156
|
+
}
|
|
1157
|
+
}
|
|
1158
|
+
|
|
1159
|
+
@container (max-width: 860px) {
|
|
1160
|
+
.candidate-grid,
|
|
1161
|
+
.focus-values,
|
|
1162
|
+
.preview-section-grid {
|
|
1163
|
+
grid-template-columns: 1fr;
|
|
1164
|
+
}
|
|
1165
|
+
|
|
1166
|
+
.candidate-grid::before {
|
|
1167
|
+
display: none;
|
|
1168
|
+
}
|
|
1169
|
+
|
|
1170
|
+
.candidate-card {
|
|
1171
|
+
min-height: auto;
|
|
1172
|
+
}
|
|
1173
|
+
}
|
|
1174
|
+
|
|
1175
|
+
@container (max-width: 620px) {
|
|
1176
|
+
.topbar .meta-grid {
|
|
1177
|
+
display: none;
|
|
1178
|
+
}
|
|
1179
|
+
|
|
1180
|
+
.decision-buttons,
|
|
1181
|
+
.summary-grid,
|
|
1182
|
+
.audit-grid {
|
|
1183
|
+
grid-template-columns: 1fr;
|
|
1184
|
+
}
|
|
1185
|
+
}
|
|
1186
|
+
|
|
1121
1187
|
@media (max-width: 560px) {
|
|
1122
1188
|
.workbench {
|
|
1123
1189
|
padding: 14px 10px 36px;
|
package/package.json
CHANGED