@crvouga/atlas 1.13.0 → 1.15.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/CHANGELOG.md +14 -1
- package/dist/playwright/src/index.d.ts +4 -0
- package/dist/playwright/src/index.js +4 -0
- package/dist/playwright/src/ui-catalog.d.ts +51 -0
- package/dist/playwright/src/ui-catalog.js +44 -0
- package/dist/reports/src/evidence-detail.d.ts +19 -0
- package/dist/reports/src/evidence-detail.js +31 -4
- package/dist/reports/src/evidence-types.d.ts +5 -2
- package/dist/reports/src/layer-merge.d.ts +5 -1
- package/dist/reports/src/layer-merge.js +13 -5
- package/dist/reports/src/layer-store.d.ts +1 -1
- package/dist/reports/src/layer-store.js +4 -2
- package/dist/reports/src/layer-types.d.ts +2 -0
- package/dist/reports/src/report-index.js +9 -5
- package/dist/reports/src/run-compare.d.ts +182 -0
- package/dist/reports/src/run-compare.js +329 -0
- package/dist/reports/src/test-catalog.d.ts +8 -0
- package/dist/reports/src/test-catalog.js +14 -1
- package/dist/reports/src/ui-catalog-publish.d.ts +92 -0
- package/dist/reports/src/ui-catalog-publish.js +68 -0
- package/dist/reports/src/ui-catalog.d.ts +229 -0
- package/dist/reports/src/ui-catalog.js +273 -0
- package/dist/reports/src/ui-state.d.ts +70 -0
- package/dist/reports/src/ui-state.js +66 -0
- package/dist/schema/src/api.d.ts +354 -0
- package/dist/schema/src/api.js +78 -3
- package/dist/server/src/app.js +15 -0
- package/dist/server/src/openapi.js +22 -2
- package/docs/reference/http-api.md +46 -0
- package/docs/reference/playwright.md +63 -0
- package/docs/reference/reports.md +942 -4
- package/docs/reference/schema.md +33 -0
- package/docs/report-contract.md +2 -2
- package/docs/rich-evidence.md +5 -0
- package/docs/server.md +2 -0
- package/docs/ui-catalog.md +173 -0
- package/docs/ui.md +45 -1
- package/llms-full.txt +276 -3
- package/llms.txt +1 -0
- package/package.json +2 -1
- package/packages/schema/schemas/effective-delta.schema.json +75 -2
- package/packages/schema/schemas/effective-evidence.schema.json +75 -2
- package/packages/schema/schemas/evidence-page.schema.json +1 -1
- package/packages/schema/schemas/layer-rows.schema.json +74 -1
- package/packages/schema/schemas/report-run.schema.json +25 -3
- package/packages/schema/schemas/report-runs.schema.json +1 -1
- package/packages/schema/schemas/review-collection.schema.json +1 -1
- package/packages/schema/schemas/review-manifest.schema.json +1 -1
- package/packages/schema/schemas/test-catalog.schema.json +1 -1
- package/packages/schema/schemas/test-history.schema.json +2 -2
- package/packages/server/openapi.json +1559 -175
- package/packages/visualizer/src/app/AppShell.tsx +36 -30
- package/packages/visualizer/src/app/router.tsx +10 -1
- package/packages/visualizer/src/catalog/UiCatalogFilters.tsx +65 -0
- package/packages/visualizer/src/catalog/UiCatalogPage.tsx +342 -0
- package/packages/visualizer/src/catalog/provider.tsx +25 -0
- package/packages/visualizer/src/catalog/search.ts +68 -0
- package/packages/visualizer/src/catalog/words.ts +26 -0
- package/packages/visualizer/src/components/Header.tsx +17 -4
- package/packages/visualizer/src/explorer/ComparePair.tsx +597 -0
- package/packages/visualizer/src/explorer/CompareView.tsx +340 -0
- package/packages/visualizer/src/explorer/Explorer.tsx +6 -2
- package/packages/visualizer/src/explorer/RunsView.tsx +10 -0
- package/packages/visualizer/src/explorer/playlist.tsx +1 -1
- package/packages/visualizer/src/explorer/search.ts +15 -3
package/dist/schema/src/api.d.ts
CHANGED
|
@@ -325,6 +325,26 @@ export declare const LayerRowSchema: z.ZodObject<{
|
|
|
325
325
|
}, z.core.$loose>>;
|
|
326
326
|
}, z.core.$loose>>>;
|
|
327
327
|
}, z.core.$loose>>;
|
|
328
|
+
state: z.ZodOptional<z.ZodObject<{
|
|
329
|
+
route: z.ZodOptional<z.ZodString>;
|
|
330
|
+
fixture: z.ZodOptional<z.ZodString>;
|
|
331
|
+
cohort: z.ZodOptional<z.ZodString>;
|
|
332
|
+
area: z.ZodOptional<z.ZodString>;
|
|
333
|
+
flags: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
334
|
+
covers: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
335
|
+
inventory: z.ZodOptional<z.ZodBoolean>;
|
|
336
|
+
screenshot: z.ZodOptional<z.ZodObject<{
|
|
337
|
+
name: z.ZodString;
|
|
338
|
+
bundleKey: z.ZodOptional<z.ZodString>;
|
|
339
|
+
uri: z.ZodOptional<z.ZodString>;
|
|
340
|
+
contentType: z.ZodOptional<z.ZodString>;
|
|
341
|
+
width: z.ZodOptional<z.ZodNumber>;
|
|
342
|
+
height: z.ZodOptional<z.ZodNumber>;
|
|
343
|
+
bytes: z.ZodOptional<z.ZodNumber>;
|
|
344
|
+
sha256: z.ZodOptional<z.ZodString>;
|
|
345
|
+
omitted: z.ZodOptional<z.ZodString>;
|
|
346
|
+
}, z.core.$loose>>;
|
|
347
|
+
}, z.core.$loose>>;
|
|
328
348
|
recording: z.ZodOptional<z.ZodObject<{
|
|
329
349
|
state: z.ZodString;
|
|
330
350
|
reason: z.ZodOptional<z.ZodString>;
|
|
@@ -410,6 +430,26 @@ export declare const LayerRowsSchema: z.ZodObject<{
|
|
|
410
430
|
}, z.core.$loose>>;
|
|
411
431
|
}, z.core.$loose>>>;
|
|
412
432
|
}, z.core.$loose>>;
|
|
433
|
+
state: z.ZodOptional<z.ZodObject<{
|
|
434
|
+
route: z.ZodOptional<z.ZodString>;
|
|
435
|
+
fixture: z.ZodOptional<z.ZodString>;
|
|
436
|
+
cohort: z.ZodOptional<z.ZodString>;
|
|
437
|
+
area: z.ZodOptional<z.ZodString>;
|
|
438
|
+
flags: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
439
|
+
covers: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
440
|
+
inventory: z.ZodOptional<z.ZodBoolean>;
|
|
441
|
+
screenshot: z.ZodOptional<z.ZodObject<{
|
|
442
|
+
name: z.ZodString;
|
|
443
|
+
bundleKey: z.ZodOptional<z.ZodString>;
|
|
444
|
+
uri: z.ZodOptional<z.ZodString>;
|
|
445
|
+
contentType: z.ZodOptional<z.ZodString>;
|
|
446
|
+
width: z.ZodOptional<z.ZodNumber>;
|
|
447
|
+
height: z.ZodOptional<z.ZodNumber>;
|
|
448
|
+
bytes: z.ZodOptional<z.ZodNumber>;
|
|
449
|
+
sha256: z.ZodOptional<z.ZodString>;
|
|
450
|
+
omitted: z.ZodOptional<z.ZodString>;
|
|
451
|
+
}, z.core.$loose>>;
|
|
452
|
+
}, z.core.$loose>>;
|
|
413
453
|
recording: z.ZodOptional<z.ZodObject<{
|
|
414
454
|
state: z.ZodString;
|
|
415
455
|
reason: z.ZodOptional<z.ZodString>;
|
|
@@ -497,6 +537,26 @@ export declare const LayerEvidenceSchema: z.ZodObject<{
|
|
|
497
537
|
}, z.core.$loose>>;
|
|
498
538
|
}, z.core.$loose>>>;
|
|
499
539
|
}, z.core.$loose>>;
|
|
540
|
+
state: z.ZodOptional<z.ZodObject<{
|
|
541
|
+
route: z.ZodOptional<z.ZodString>;
|
|
542
|
+
fixture: z.ZodOptional<z.ZodString>;
|
|
543
|
+
cohort: z.ZodOptional<z.ZodString>;
|
|
544
|
+
area: z.ZodOptional<z.ZodString>;
|
|
545
|
+
flags: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
546
|
+
covers: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
547
|
+
inventory: z.ZodOptional<z.ZodBoolean>;
|
|
548
|
+
screenshot: z.ZodOptional<z.ZodObject<{
|
|
549
|
+
name: z.ZodString;
|
|
550
|
+
bundleKey: z.ZodOptional<z.ZodString>;
|
|
551
|
+
uri: z.ZodOptional<z.ZodString>;
|
|
552
|
+
contentType: z.ZodOptional<z.ZodString>;
|
|
553
|
+
width: z.ZodOptional<z.ZodNumber>;
|
|
554
|
+
height: z.ZodOptional<z.ZodNumber>;
|
|
555
|
+
bytes: z.ZodOptional<z.ZodNumber>;
|
|
556
|
+
sha256: z.ZodOptional<z.ZodString>;
|
|
557
|
+
omitted: z.ZodOptional<z.ZodString>;
|
|
558
|
+
}, z.core.$loose>>;
|
|
559
|
+
}, z.core.$loose>>;
|
|
500
560
|
recording: z.ZodOptional<z.ZodObject<{
|
|
501
561
|
state: z.ZodString;
|
|
502
562
|
reason: z.ZodOptional<z.ZodString>;
|
|
@@ -674,6 +734,26 @@ export declare const EffectiveEvidenceSchema: z.ZodObject<{
|
|
|
674
734
|
}, z.core.$loose>>;
|
|
675
735
|
}, z.core.$loose>>>;
|
|
676
736
|
}, z.core.$loose>>;
|
|
737
|
+
state: z.ZodOptional<z.ZodObject<{
|
|
738
|
+
route: z.ZodOptional<z.ZodString>;
|
|
739
|
+
fixture: z.ZodOptional<z.ZodString>;
|
|
740
|
+
cohort: z.ZodOptional<z.ZodString>;
|
|
741
|
+
area: z.ZodOptional<z.ZodString>;
|
|
742
|
+
flags: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
743
|
+
covers: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
744
|
+
inventory: z.ZodOptional<z.ZodBoolean>;
|
|
745
|
+
screenshot: z.ZodOptional<z.ZodObject<{
|
|
746
|
+
name: z.ZodString;
|
|
747
|
+
bundleKey: z.ZodOptional<z.ZodString>;
|
|
748
|
+
uri: z.ZodOptional<z.ZodString>;
|
|
749
|
+
contentType: z.ZodOptional<z.ZodString>;
|
|
750
|
+
width: z.ZodOptional<z.ZodNumber>;
|
|
751
|
+
height: z.ZodOptional<z.ZodNumber>;
|
|
752
|
+
bytes: z.ZodOptional<z.ZodNumber>;
|
|
753
|
+
sha256: z.ZodOptional<z.ZodString>;
|
|
754
|
+
omitted: z.ZodOptional<z.ZodString>;
|
|
755
|
+
}, z.core.$loose>>;
|
|
756
|
+
}, z.core.$loose>>;
|
|
677
757
|
recording: z.ZodOptional<z.ZodObject<{
|
|
678
758
|
state: z.ZodString;
|
|
679
759
|
reason: z.ZodOptional<z.ZodString>;
|
|
@@ -872,6 +952,26 @@ export declare const EffectiveDeltaSchema: z.ZodObject<{
|
|
|
872
952
|
}, z.core.$loose>>;
|
|
873
953
|
}, z.core.$loose>>>;
|
|
874
954
|
}, z.core.$loose>>;
|
|
955
|
+
state: z.ZodOptional<z.ZodObject<{
|
|
956
|
+
route: z.ZodOptional<z.ZodString>;
|
|
957
|
+
fixture: z.ZodOptional<z.ZodString>;
|
|
958
|
+
cohort: z.ZodOptional<z.ZodString>;
|
|
959
|
+
area: z.ZodOptional<z.ZodString>;
|
|
960
|
+
flags: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
961
|
+
covers: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
962
|
+
inventory: z.ZodOptional<z.ZodBoolean>;
|
|
963
|
+
screenshot: z.ZodOptional<z.ZodObject<{
|
|
964
|
+
name: z.ZodString;
|
|
965
|
+
bundleKey: z.ZodOptional<z.ZodString>;
|
|
966
|
+
uri: z.ZodOptional<z.ZodString>;
|
|
967
|
+
contentType: z.ZodOptional<z.ZodString>;
|
|
968
|
+
width: z.ZodOptional<z.ZodNumber>;
|
|
969
|
+
height: z.ZodOptional<z.ZodNumber>;
|
|
970
|
+
bytes: z.ZodOptional<z.ZodNumber>;
|
|
971
|
+
sha256: z.ZodOptional<z.ZodString>;
|
|
972
|
+
omitted: z.ZodOptional<z.ZodString>;
|
|
973
|
+
}, z.core.$loose>>;
|
|
974
|
+
}, z.core.$loose>>;
|
|
875
975
|
recording: z.ZodOptional<z.ZodObject<{
|
|
876
976
|
state: z.ZodString;
|
|
877
977
|
reason: z.ZodOptional<z.ZodString>;
|
|
@@ -3524,6 +3624,10 @@ export declare const RunDetailSchema: z.ZodObject<{
|
|
|
3524
3624
|
extensions: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
3525
3625
|
}, z.core.$loose>>;
|
|
3526
3626
|
}, z.core.$loose>>>;
|
|
3627
|
+
kind: z.ZodOptional<z.ZodString>;
|
|
3628
|
+
parameters: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
3629
|
+
specRevision: z.ZodOptional<z.ZodString>;
|
|
3630
|
+
recordedTitle: z.ZodOptional<z.ZodString>;
|
|
3527
3631
|
}, z.core.$loose>>;
|
|
3528
3632
|
layers: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
3529
3633
|
id: z.ZodString;
|
|
@@ -3540,3 +3644,253 @@ export declare const RunDetailSchema: z.ZodObject<{
|
|
|
3540
3644
|
}, z.core.$loose>>;
|
|
3541
3645
|
}, z.core.$loose>>>;
|
|
3542
3646
|
}, z.core.$loose>;
|
|
3647
|
+
/** A state's profile: the client and the choices it was captured under. */
|
|
3648
|
+
export declare const UiProfileSchema: z.ZodObject<{
|
|
3649
|
+
key: z.ZodString;
|
|
3650
|
+
environment: z.ZodNullable<z.ZodString>;
|
|
3651
|
+
parameters: z.ZodRecord<z.ZodString, z.ZodString>;
|
|
3652
|
+
label: z.ZodString;
|
|
3653
|
+
}, z.core.$loose>;
|
|
3654
|
+
/** The picture of a capture. */
|
|
3655
|
+
export declare const UiImageSchema: z.ZodObject<{
|
|
3656
|
+
name: z.ZodString;
|
|
3657
|
+
contentType: z.ZodOptional<z.ZodString>;
|
|
3658
|
+
width: z.ZodOptional<z.ZodNumber>;
|
|
3659
|
+
height: z.ZodOptional<z.ZodNumber>;
|
|
3660
|
+
bytes: z.ZodOptional<z.ZodNumber>;
|
|
3661
|
+
sha256: z.ZodOptional<z.ZodString>;
|
|
3662
|
+
bundleKey: z.ZodOptional<z.ZodString>;
|
|
3663
|
+
uri: z.ZodOptional<z.ZodString>;
|
|
3664
|
+
path: z.ZodOptional<z.ZodString>;
|
|
3665
|
+
omitted: z.ZodOptional<z.ZodString>;
|
|
3666
|
+
}, z.core.$loose>;
|
|
3667
|
+
/** One state in one profile. */
|
|
3668
|
+
export declare const UiCellSchema: z.ZodObject<{
|
|
3669
|
+
profile: z.ZodObject<{
|
|
3670
|
+
key: z.ZodString;
|
|
3671
|
+
environment: z.ZodNullable<z.ZodString>;
|
|
3672
|
+
parameters: z.ZodRecord<z.ZodString, z.ZodString>;
|
|
3673
|
+
label: z.ZodString;
|
|
3674
|
+
}, z.core.$loose>;
|
|
3675
|
+
coverage: z.ZodEnum<{
|
|
3676
|
+
failed: "failed";
|
|
3677
|
+
skipped: "skipped";
|
|
3678
|
+
missing: "missing";
|
|
3679
|
+
captured: "captured";
|
|
3680
|
+
capturing: "capturing";
|
|
3681
|
+
}>;
|
|
3682
|
+
expected: z.ZodEnum<{
|
|
3683
|
+
unknown: "unknown";
|
|
3684
|
+
declared: "declared";
|
|
3685
|
+
undeclared: "undeclared";
|
|
3686
|
+
}>;
|
|
3687
|
+
capture: z.ZodNullable<z.ZodObject<{
|
|
3688
|
+
status: z.ZodEnum<{
|
|
3689
|
+
passed: "passed";
|
|
3690
|
+
failed: "failed";
|
|
3691
|
+
running: "running";
|
|
3692
|
+
"not-run": "not-run";
|
|
3693
|
+
}>;
|
|
3694
|
+
detail: z.ZodString;
|
|
3695
|
+
durationMs: z.ZodNullable<z.ZodNumber>;
|
|
3696
|
+
image: z.ZodNullable<z.ZodObject<{
|
|
3697
|
+
name: z.ZodString;
|
|
3698
|
+
contentType: z.ZodOptional<z.ZodString>;
|
|
3699
|
+
width: z.ZodOptional<z.ZodNumber>;
|
|
3700
|
+
height: z.ZodOptional<z.ZodNumber>;
|
|
3701
|
+
bytes: z.ZodOptional<z.ZodNumber>;
|
|
3702
|
+
sha256: z.ZodOptional<z.ZodString>;
|
|
3703
|
+
bundleKey: z.ZodOptional<z.ZodString>;
|
|
3704
|
+
uri: z.ZodOptional<z.ZodString>;
|
|
3705
|
+
path: z.ZodOptional<z.ZodString>;
|
|
3706
|
+
omitted: z.ZodOptional<z.ZodString>;
|
|
3707
|
+
}, z.core.$loose>>;
|
|
3708
|
+
labels: z.ZodRecord<z.ZodString, z.ZodString>;
|
|
3709
|
+
origin: z.ZodObject<{
|
|
3710
|
+
layer: z.ZodString;
|
|
3711
|
+
backend: z.ZodString;
|
|
3712
|
+
producer: z.ZodString;
|
|
3713
|
+
recordedAtMs: z.ZodNumber;
|
|
3714
|
+
sha: z.ZodNullable<z.ZodString>;
|
|
3715
|
+
branch: z.ZodNullable<z.ZodString>;
|
|
3716
|
+
runUrl: z.ZodNullable<z.ZodString>;
|
|
3717
|
+
freshness: z.ZodOptional<z.ZodEnum<{
|
|
3718
|
+
unknown: "unknown";
|
|
3719
|
+
modified: "modified";
|
|
3720
|
+
}>>;
|
|
3721
|
+
}, z.core.$loose>;
|
|
3722
|
+
alternatives: z.ZodNumber;
|
|
3723
|
+
}, z.core.$loose>>;
|
|
3724
|
+
planned: z.ZodNullable<z.ZodObject<{
|
|
3725
|
+
layer: z.ZodString;
|
|
3726
|
+
backend: z.ZodString;
|
|
3727
|
+
}, z.core.$loose>>;
|
|
3728
|
+
}, z.core.$loose>;
|
|
3729
|
+
/**
|
|
3730
|
+
* `GET /api/reports/ui-catalog`: the UI catalog, computed from the winning results of the `ui-state` and `ui-plan` parts
|
|
3731
|
+
* of every layer. States are in id order and cells in profile order, so the same layers always give the same document.
|
|
3732
|
+
*/
|
|
3733
|
+
export declare const UiCatalogSchema: z.ZodObject<{
|
|
3734
|
+
schemaVersion: z.ZodLiteral<1>;
|
|
3735
|
+
version: z.ZodOptional<z.ZodString>;
|
|
3736
|
+
summary: z.ZodObject<{
|
|
3737
|
+
states: z.ZodNumber;
|
|
3738
|
+
profiles: z.ZodNumber;
|
|
3739
|
+
cells: z.ZodNumber;
|
|
3740
|
+
coverage: z.ZodObject<{
|
|
3741
|
+
captured: z.ZodNumber;
|
|
3742
|
+
failed: z.ZodNumber;
|
|
3743
|
+
capturing: z.ZodNumber;
|
|
3744
|
+
skipped: z.ZodNumber;
|
|
3745
|
+
missing: z.ZodNumber;
|
|
3746
|
+
}, z.core.$loose>;
|
|
3747
|
+
undeclared: z.ZodNumber;
|
|
3748
|
+
planned: z.ZodBoolean;
|
|
3749
|
+
surfaces: z.ZodNumber;
|
|
3750
|
+
uncoveredSurfaces: z.ZodNumber;
|
|
3751
|
+
}, z.core.$loose>;
|
|
3752
|
+
profiles: z.ZodArray<z.ZodObject<{
|
|
3753
|
+
key: z.ZodString;
|
|
3754
|
+
environment: z.ZodNullable<z.ZodString>;
|
|
3755
|
+
parameters: z.ZodRecord<z.ZodString, z.ZodString>;
|
|
3756
|
+
label: z.ZodString;
|
|
3757
|
+
}, z.core.$loose>>;
|
|
3758
|
+
states: z.ZodArray<z.ZodObject<{
|
|
3759
|
+
id: z.ZodString;
|
|
3760
|
+
title: z.ZodString;
|
|
3761
|
+
route: z.ZodNullable<z.ZodString>;
|
|
3762
|
+
fixture: z.ZodNullable<z.ZodString>;
|
|
3763
|
+
cohort: z.ZodNullable<z.ZodString>;
|
|
3764
|
+
area: z.ZodNullable<z.ZodString>;
|
|
3765
|
+
flags: z.ZodArray<z.ZodString>;
|
|
3766
|
+
covers: z.ZodArray<z.ZodString>;
|
|
3767
|
+
producers: z.ZodArray<z.ZodString>;
|
|
3768
|
+
cells: z.ZodArray<z.ZodObject<{
|
|
3769
|
+
profile: z.ZodObject<{
|
|
3770
|
+
key: z.ZodString;
|
|
3771
|
+
environment: z.ZodNullable<z.ZodString>;
|
|
3772
|
+
parameters: z.ZodRecord<z.ZodString, z.ZodString>;
|
|
3773
|
+
label: z.ZodString;
|
|
3774
|
+
}, z.core.$loose>;
|
|
3775
|
+
coverage: z.ZodEnum<{
|
|
3776
|
+
failed: "failed";
|
|
3777
|
+
skipped: "skipped";
|
|
3778
|
+
missing: "missing";
|
|
3779
|
+
captured: "captured";
|
|
3780
|
+
capturing: "capturing";
|
|
3781
|
+
}>;
|
|
3782
|
+
expected: z.ZodEnum<{
|
|
3783
|
+
unknown: "unknown";
|
|
3784
|
+
declared: "declared";
|
|
3785
|
+
undeclared: "undeclared";
|
|
3786
|
+
}>;
|
|
3787
|
+
capture: z.ZodNullable<z.ZodObject<{
|
|
3788
|
+
status: z.ZodEnum<{
|
|
3789
|
+
passed: "passed";
|
|
3790
|
+
failed: "failed";
|
|
3791
|
+
running: "running";
|
|
3792
|
+
"not-run": "not-run";
|
|
3793
|
+
}>;
|
|
3794
|
+
detail: z.ZodString;
|
|
3795
|
+
durationMs: z.ZodNullable<z.ZodNumber>;
|
|
3796
|
+
image: z.ZodNullable<z.ZodObject<{
|
|
3797
|
+
name: z.ZodString;
|
|
3798
|
+
contentType: z.ZodOptional<z.ZodString>;
|
|
3799
|
+
width: z.ZodOptional<z.ZodNumber>;
|
|
3800
|
+
height: z.ZodOptional<z.ZodNumber>;
|
|
3801
|
+
bytes: z.ZodOptional<z.ZodNumber>;
|
|
3802
|
+
sha256: z.ZodOptional<z.ZodString>;
|
|
3803
|
+
bundleKey: z.ZodOptional<z.ZodString>;
|
|
3804
|
+
uri: z.ZodOptional<z.ZodString>;
|
|
3805
|
+
path: z.ZodOptional<z.ZodString>;
|
|
3806
|
+
omitted: z.ZodOptional<z.ZodString>;
|
|
3807
|
+
}, z.core.$loose>>;
|
|
3808
|
+
labels: z.ZodRecord<z.ZodString, z.ZodString>;
|
|
3809
|
+
origin: z.ZodObject<{
|
|
3810
|
+
layer: z.ZodString;
|
|
3811
|
+
backend: z.ZodString;
|
|
3812
|
+
producer: z.ZodString;
|
|
3813
|
+
recordedAtMs: z.ZodNumber;
|
|
3814
|
+
sha: z.ZodNullable<z.ZodString>;
|
|
3815
|
+
branch: z.ZodNullable<z.ZodString>;
|
|
3816
|
+
runUrl: z.ZodNullable<z.ZodString>;
|
|
3817
|
+
freshness: z.ZodOptional<z.ZodEnum<{
|
|
3818
|
+
unknown: "unknown";
|
|
3819
|
+
modified: "modified";
|
|
3820
|
+
}>>;
|
|
3821
|
+
}, z.core.$loose>;
|
|
3822
|
+
alternatives: z.ZodNumber;
|
|
3823
|
+
}, z.core.$loose>>;
|
|
3824
|
+
planned: z.ZodNullable<z.ZodObject<{
|
|
3825
|
+
layer: z.ZodString;
|
|
3826
|
+
backend: z.ZodString;
|
|
3827
|
+
}, z.core.$loose>>;
|
|
3828
|
+
}, z.core.$loose>>;
|
|
3829
|
+
}, z.core.$loose>>;
|
|
3830
|
+
surfaces: z.ZodArray<z.ZodObject<{
|
|
3831
|
+
id: z.ZodString;
|
|
3832
|
+
inventoried: z.ZodBoolean;
|
|
3833
|
+
states: z.ZodNumber;
|
|
3834
|
+
captured: z.ZodNumber;
|
|
3835
|
+
status: z.ZodEnum<{
|
|
3836
|
+
covered: "covered";
|
|
3837
|
+
uncaptured: "uncaptured";
|
|
3838
|
+
uncovered: "uncovered";
|
|
3839
|
+
}>;
|
|
3840
|
+
}, z.core.$loose>>;
|
|
3841
|
+
facets: z.ZodObject<{
|
|
3842
|
+
profiles: z.ZodArray<z.ZodObject<{
|
|
3843
|
+
value: z.ZodString;
|
|
3844
|
+
count: z.ZodNumber;
|
|
3845
|
+
label: z.ZodOptional<z.ZodString>;
|
|
3846
|
+
}, z.core.$loose>>;
|
|
3847
|
+
coverage: z.ZodArray<z.ZodObject<{
|
|
3848
|
+
value: z.ZodString;
|
|
3849
|
+
count: z.ZodNumber;
|
|
3850
|
+
label: z.ZodOptional<z.ZodString>;
|
|
3851
|
+
}, z.core.$loose>>;
|
|
3852
|
+
areas: z.ZodArray<z.ZodObject<{
|
|
3853
|
+
value: z.ZodString;
|
|
3854
|
+
count: z.ZodNumber;
|
|
3855
|
+
label: z.ZodOptional<z.ZodString>;
|
|
3856
|
+
}, z.core.$loose>>;
|
|
3857
|
+
routes: z.ZodArray<z.ZodObject<{
|
|
3858
|
+
value: z.ZodString;
|
|
3859
|
+
count: z.ZodNumber;
|
|
3860
|
+
label: z.ZodOptional<z.ZodString>;
|
|
3861
|
+
}, z.core.$loose>>;
|
|
3862
|
+
cohorts: z.ZodArray<z.ZodObject<{
|
|
3863
|
+
value: z.ZodString;
|
|
3864
|
+
count: z.ZodNumber;
|
|
3865
|
+
label: z.ZodOptional<z.ZodString>;
|
|
3866
|
+
}, z.core.$loose>>;
|
|
3867
|
+
flags: z.ZodArray<z.ZodObject<{
|
|
3868
|
+
value: z.ZodString;
|
|
3869
|
+
count: z.ZodNumber;
|
|
3870
|
+
label: z.ZodOptional<z.ZodString>;
|
|
3871
|
+
}, z.core.$loose>>;
|
|
3872
|
+
surfaces: z.ZodArray<z.ZodObject<{
|
|
3873
|
+
value: z.ZodString;
|
|
3874
|
+
count: z.ZodNumber;
|
|
3875
|
+
label: z.ZodOptional<z.ZodString>;
|
|
3876
|
+
}, z.core.$loose>>;
|
|
3877
|
+
producers: z.ZodArray<z.ZodObject<{
|
|
3878
|
+
value: z.ZodString;
|
|
3879
|
+
count: z.ZodNumber;
|
|
3880
|
+
label: z.ZodOptional<z.ZodString>;
|
|
3881
|
+
}, z.core.$loose>>;
|
|
3882
|
+
}, z.core.$loose>;
|
|
3883
|
+
sources: z.ZodObject<{
|
|
3884
|
+
layers: z.ZodNumber;
|
|
3885
|
+
backends: z.ZodArray<z.ZodObject<{
|
|
3886
|
+
id: z.ZodString;
|
|
3887
|
+
label: z.ZodString;
|
|
3888
|
+
live: z.ZodBoolean;
|
|
3889
|
+
available: z.ZodBoolean;
|
|
3890
|
+
}, z.core.$loose>>;
|
|
3891
|
+
notices: z.ZodArray<z.ZodString>;
|
|
3892
|
+
}, z.core.$loose>;
|
|
3893
|
+
total: z.ZodOptional<z.ZodNumber>;
|
|
3894
|
+
offset: z.ZodOptional<z.ZodNumber>;
|
|
3895
|
+
limit: z.ZodOptional<z.ZodNumber>;
|
|
3896
|
+
}, z.core.$loose>;
|
package/dist/schema/src/api.js
CHANGED
|
@@ -70,14 +70,14 @@ export const VideoRefSchema = z.looseObject({
|
|
|
70
70
|
step: z.string().optional().describe('The name of the step that holds it'),
|
|
71
71
|
tags: z.array(z.string()).optional().describe('The normalized tags of this attachment itself. Absent when it has none (and in documents of older servers)'),
|
|
72
72
|
recording: z.string().optional().describe('What identifies the bytes; references with the same value are one recording. Absent when it cannot be played'),
|
|
73
|
-
available: z.boolean().describe('False when the reference names no bytes
|
|
73
|
+
available: z.boolean().describe('False when the reference names no bytes: no bundle key, address or inline text, or a bundle key that the layer\'s own bundle does not hold'),
|
|
74
74
|
scope: EvidenceScopeSchema.optional().describe('What this recording shows as its producer declared it: its own `scope`, else its attempt\'s, check\'s, part\'s or layer\'s. Absent: the scope is unknown, never live, physical or audible')
|
|
75
75
|
});
|
|
76
76
|
/** Video references as counts: how many are referenced, how many distinct recordings can be played, how many cannot. */
|
|
77
77
|
export const VideoCountsSchema = z.looseObject({
|
|
78
78
|
references: z.number().int().nonnegative().describe('Every reference to a video; identical bytes referenced twice count twice'),
|
|
79
79
|
recordings: z.number().int().nonnegative().describe('Distinct playable recordings'),
|
|
80
|
-
unavailable: z.number().int().nonnegative().describe('References that name no bytes')
|
|
80
|
+
unavailable: z.number().int().nonnegative().describe('References that name no bytes, or bytes the layer does not hold')
|
|
81
81
|
});
|
|
82
82
|
/** What a result carries beyond its outcome, as counts and short facts. Present only when there is something. */
|
|
83
83
|
export const EvidenceSummarySchema = z.looseObject({
|
|
@@ -130,6 +130,16 @@ export const LayerRowSchema = z.looseObject({
|
|
|
130
130
|
variant: z.record(z.string(), z.string()),
|
|
131
131
|
durationMs: z.number().nullable(),
|
|
132
132
|
evidence: EvidenceSummarySchema.optional(),
|
|
133
|
+
state: z.looseObject({
|
|
134
|
+
route: z.string().optional(), fixture: z.string().optional(), cohort: z.string().optional(), area: z.string().optional(),
|
|
135
|
+
flags: z.array(z.string()).optional(), covers: z.array(z.string()).optional(),
|
|
136
|
+
inventory: z.boolean().optional().describe('A `ui-plan` entry that names a surface of the product\'s inventory, not a state'),
|
|
137
|
+
screenshot: z.looseObject({
|
|
138
|
+
name: z.string(), bundleKey: z.string().optional(), uri: z.string().optional(), contentType: z.string().optional(),
|
|
139
|
+
width: z.number().optional(), height: z.number().optional(), bytes: z.number().optional(), sha256: z.string().optional(),
|
|
140
|
+
omitted: z.string().optional().describe('Why the producer left the bytes out')
|
|
141
|
+
}).optional().describe('The check\'s picture: its `screenshot` attachment, else its first image')
|
|
142
|
+
}).optional().describe('Only for a check of a `ui-state` or `ui-plan` part: its picture and the facts its producer declared under the `atlas.ui-state` extension. See the UI catalog guide. Never decides a result'),
|
|
133
143
|
recording: z.looseObject({ state: z.string(), reason: z.string().optional() }).optional().describe('What became of the check\'s expected recording: uploaded, referenced, skipped, unresolved or not-applicable. Independent of `status`')
|
|
134
144
|
});
|
|
135
145
|
/** A layer with its checks: the rows of one layer, read apart from its header. */
|
|
@@ -661,7 +671,11 @@ export const RunDetailSchema = z.looseObject({
|
|
|
661
671
|
results: z.array(z.looseObject({
|
|
662
672
|
key: z.string(), id: z.string(), title: z.string(), specPath: z.string().nullable(), environment: z.string().nullable(), producer: z.string(),
|
|
663
673
|
status: EvidenceStatusSchema, durationMs: z.number().nullable(), at: z.number(), layer: z.string(), detail: z.string(),
|
|
664
|
-
videos: z.array(VideoRefSchema).optional().describe('Every video its evidence references, with who holds it')
|
|
674
|
+
videos: z.array(VideoRefSchema).optional().describe('Every video its evidence references, with who holds it'),
|
|
675
|
+
kind: z.string().optional().describe('The kind of the part that held it. With the producer, environment and parameters it is the condition the result was recorded under. Absent from an older server'),
|
|
676
|
+
parameters: z.record(z.string(), z.string()).optional().describe('The other choices that made it its own result (a device size, a locale…). Absent when there are none, and from an older server'),
|
|
677
|
+
specRevision: z.string().optional().describe('The fingerprint of its spec file the layer recorded. Absent means not recorded, never "the same"'),
|
|
678
|
+
recordedTitle: z.string().optional().describe('The title this run\'s layer gave the check. `title` is the check\'s newest title in the whole history; this is the wording as recorded. Absent from an older server')
|
|
665
679
|
})),
|
|
666
680
|
layers: z.array(z.looseObject({
|
|
667
681
|
id: z.string().describe('The layer id; read its files with `/api/reports/evidence/detail/{backend}/{id}`'),
|
|
@@ -671,3 +685,64 @@ export const RunDetailSchema = z.looseObject({
|
|
|
671
685
|
videos: VideoCountsSchema.optional()
|
|
672
686
|
})).optional().describe('Every layer of the run, oldest first. Absent from an older server')
|
|
673
687
|
});
|
|
688
|
+
/** A state's profile: the client and the choices it was captured under. */
|
|
689
|
+
export const UiProfileSchema = z.looseObject({
|
|
690
|
+
key: z.string().describe('Identifies the profile across layers: the environment and the sorted parameters'),
|
|
691
|
+
environment: z.string().nullable(), parameters: z.record(z.string(), z.string()),
|
|
692
|
+
label: z.string().describe('For a person: the client and each parameter\'s value')
|
|
693
|
+
});
|
|
694
|
+
/** The picture of a capture. */
|
|
695
|
+
export const UiImageSchema = z.looseObject({
|
|
696
|
+
name: z.string(), contentType: z.string().optional(), width: z.number().optional(), height: z.number().optional(), bytes: z.number().optional(), sha256: z.string().optional(),
|
|
697
|
+
bundleKey: z.string().optional(), uri: z.string().optional().describe('An http(s) address, when the picture lives elsewhere'),
|
|
698
|
+
path: z.string().optional().describe('Where the stored bytes are, relative to the reports API root (`/api/reports` on a server): `/layers/<layer>/blobs/attachments/<sha256>`'),
|
|
699
|
+
omitted: z.string().optional().describe('Why the producer left the bytes out. A picture that is left out is not a picture that was never taken')
|
|
700
|
+
});
|
|
701
|
+
/** One state in one profile. */
|
|
702
|
+
export const UiCellSchema = z.looseObject({
|
|
703
|
+
profile: UiProfileSchema,
|
|
704
|
+
coverage: z.enum(['captured', 'failed', 'capturing', 'skipped', 'missing']).describe('`captured` only when the winning capture passed. Every other value means there is no picture to trust'),
|
|
705
|
+
expected: z.enum(['declared', 'undeclared', 'unknown']).describe('`declared`: a plan expects it. `undeclared`: plans exist and none names it. `unknown`: no plan was published, so nothing is known to be unexpected'),
|
|
706
|
+
capture: z.looseObject({
|
|
707
|
+
status: EvidenceStatusSchema, detail: z.string(), durationMs: z.number().nullable(), image: UiImageSchema.nullable(),
|
|
708
|
+
labels: z.record(z.string(), z.string()).describe('What describes the capture without splitting it: a `shard`, a `browser`'),
|
|
709
|
+
origin: z.looseObject({
|
|
710
|
+
layer: z.string(), backend: z.string(), producer: z.string(), recordedAtMs: z.number(), sha: z.string().nullable(), branch: z.string().nullable(), runUrl: z.string().nullable(),
|
|
711
|
+
freshness: z.enum(['unknown', 'modified']).optional()
|
|
712
|
+
}),
|
|
713
|
+
alternatives: z.number().int().nonnegative().describe('Other captures of this cell from other producers; the winner is the one the report contract picks')
|
|
714
|
+
}).nullable(),
|
|
715
|
+
planned: z.looseObject({ layer: z.string(), backend: z.string() }).nullable().describe('The plan layer that expects this cell')
|
|
716
|
+
});
|
|
717
|
+
const UiFacetSchema = z.array(z.looseObject({ value: z.string(), count: z.number().int().nonnegative(), label: z.string().optional() }));
|
|
718
|
+
/**
|
|
719
|
+
* `GET /api/reports/ui-catalog`: the UI catalog, computed from the winning results of the `ui-state` and `ui-plan` parts
|
|
720
|
+
* of every layer. States are in id order and cells in profile order, so the same layers always give the same document.
|
|
721
|
+
*/
|
|
722
|
+
export const UiCatalogSchema = z.looseObject({
|
|
723
|
+
schemaVersion: z.literal(1),
|
|
724
|
+
version: z.string().optional().describe('The report version this was computed from; equal exactly when the report is'),
|
|
725
|
+
summary: z.looseObject({
|
|
726
|
+
states: z.number().int().nonnegative(), profiles: z.number().int().nonnegative(), cells: z.number().int().nonnegative(),
|
|
727
|
+
coverage: z.looseObject({ captured: z.number(), failed: z.number(), capturing: z.number(), skipped: z.number(), missing: z.number() }),
|
|
728
|
+
undeclared: z.number().int().nonnegative().describe('Cells captured or failed that no plan expects. Zero when no plan was published'),
|
|
729
|
+
planned: z.boolean().describe('Whether any plan was published. Without one `missing` is always zero: what should exist is unknown'),
|
|
730
|
+
surfaces: z.number().int().nonnegative(), uncoveredSurfaces: z.number().int().nonnegative()
|
|
731
|
+
}),
|
|
732
|
+
profiles: z.array(UiProfileSchema),
|
|
733
|
+
states: z.array(z.looseObject({
|
|
734
|
+
id: z.string(), title: z.string(),
|
|
735
|
+
route: z.string().nullable(), fixture: z.string().nullable(), cohort: z.string().nullable(), area: z.string().nullable(),
|
|
736
|
+
flags: z.array(z.string()), covers: z.array(z.string()).describe('The surfaces it covers'), producers: z.array(z.string()),
|
|
737
|
+
cells: z.array(UiCellSchema)
|
|
738
|
+
})),
|
|
739
|
+
surfaces: z.array(z.looseObject({
|
|
740
|
+
id: z.string(), inventoried: z.boolean().describe('A `ui-plan` inventory entry names it: the product is known to have it'),
|
|
741
|
+
states: z.number().int().nonnegative(), captured: z.number().int().nonnegative(),
|
|
742
|
+
status: z.enum(['covered', 'uncaptured', 'uncovered'])
|
|
743
|
+
})),
|
|
744
|
+
facets: z.looseObject({ profiles: UiFacetSchema, coverage: UiFacetSchema, areas: UiFacetSchema, routes: UiFacetSchema, cohorts: UiFacetSchema, flags: UiFacetSchema, surfaces: UiFacetSchema, producers: UiFacetSchema }),
|
|
745
|
+
sources: z.looseObject({ layers: z.number().int().nonnegative(), backends: z.array(BackendInfoSchema), notices: z.array(z.string()) }).describe('What was read. A backend that is unavailable, or a layer that could not be read, is named here; what depended on it is not shown as captured'),
|
|
746
|
+
total: z.number().int().nonnegative().optional().describe('States that matched, before `offset` and `limit`'),
|
|
747
|
+
offset: z.number().int().nonnegative().optional(), limit: z.number().int().nonnegative().optional()
|
|
748
|
+
});
|
package/dist/server/src/app.js
CHANGED
|
@@ -28,6 +28,7 @@ import { listRunSummaries, readRunFile } from '../../reports/src/run-bundle.js';
|
|
|
28
28
|
import { latestSpecSet, readSpecBody } from '../../reports/src/spec-set.js';
|
|
29
29
|
import { catalogHealth, healthMarkdown, parseRootMappings } from '../../reports/src/catalog-health.js';
|
|
30
30
|
import { parseArtifactFilter } from '../../reports/src/artifact-query.js';
|
|
31
|
+
import { filterUiCatalog, pageUiCatalog, parseUiCatalogQuery, uiCatalog, uiCatalogMarkdown } from '../../reports/src/ui-catalog.js';
|
|
31
32
|
import { parseReliabilityScope, reliability, reliabilityMarkdown } from '../../reports/src/reliability.js';
|
|
32
33
|
import { artifactList, artifactsMarkdown, catalogMarkdown, catalogModel, historyMarkdown, parseTestQuery, runDetail, runList, runMarkdown, runsMarkdown, testCatalog, testHistory } from '../../reports/src/test-catalog.js';
|
|
33
34
|
import { llmsTxt } from './llms.js';
|
|
@@ -418,6 +419,7 @@ function createProjectApplication(options) {
|
|
|
418
419
|
}
|
|
419
420
|
return model.value;
|
|
420
421
|
};
|
|
422
|
+
let uiModel;
|
|
421
423
|
const wantsMarkdown = (c) => {
|
|
422
424
|
const format = c.req.query('format');
|
|
423
425
|
return format === 'markdown' || format === 'md' || (format === undefined && /\btext\/markdown\b/.test(c.req.header('accept') ?? ''));
|
|
@@ -502,6 +504,19 @@ function createProjectApplication(options) {
|
|
|
502
504
|
const document = () => artifactList(index.history, found.version, parseArtifactFilter(search), { limit: number('limit', 100), offset: number('offset', 0), domainOf: path => domains.get(path) });
|
|
503
505
|
return answer(c, found.version, document, () => artifactsMarkdown(document()), `artifacts|${search.toString()}|${wantsMarkdown(c)}`);
|
|
504
506
|
});
|
|
507
|
+
app.get('/api/reports/ui-catalog', async (c) => {
|
|
508
|
+
if (!index.ready)
|
|
509
|
+
return notReady(c);
|
|
510
|
+
const snapshot = index.snapshot();
|
|
511
|
+
const search = new URL(c.req.url).searchParams;
|
|
512
|
+
const number = (name, fallback) => (/^\d+$/.test(search.get(name) ?? '') ? Number(search.get(name)) : fallback);
|
|
513
|
+
// The catalog is a function of the report, so it is built once per version and narrowed per question.
|
|
514
|
+
if (uiModel?.version !== snapshot.version)
|
|
515
|
+
uiModel = { version: snapshot.version, value: uiCatalog(snapshot.layers, { version: snapshot.version, backends: snapshot.backends, notices: snapshot.notices }) };
|
|
516
|
+
const whole = uiModel.value;
|
|
517
|
+
const document = () => pageUiCatalog(filterUiCatalog(whole, parseUiCatalogQuery(search)), { limit: number('limit', 200), offset: number('offset', 0) });
|
|
518
|
+
return answer(c, snapshot.version, document, () => uiCatalogMarkdown(document()), `ui-catalog|${search.toString()}|${wantsMarkdown(c)}`);
|
|
519
|
+
});
|
|
505
520
|
app.get('/api/reports/runs/detail', async (c) => {
|
|
506
521
|
if (!index.ready)
|
|
507
522
|
return notReady(c);
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
*/
|
|
15
15
|
import { z } from 'zod/v4';
|
|
16
16
|
import { ProjectsSchema } from '../../schema/src/project.js';
|
|
17
|
-
import { EffectiveDeltaSchema, EffectiveEvidenceSchema, EvidencePageSchema, HealthSchema, LayerRowsSchema, CheckDetailSchema, OutlineSchema, ProblemSchema, ReadySchema, ServerInfoSchema, StoreListingSchema, StoreWriteResultSchema, ChecksResultSchema, HelloEventSchema, ReportEventSchema, PingEventSchema, TestCatalogSchema, CatalogHealthSchema, TestHistorySchema, TestReliabilitySchema, RunListSchema, RunDetailSchema, ArtifactListSchema, ArtifactTagEditSchema, ArtifactTagEntrySchema, ArtifactTagsSchema, ReviewCollectionRequestSchema, ReviewCollectionSchema, ReviewCollectionListSchema, ReviewCollectionDetailSchema, ReviewNoteInputSchema, ReviewNoteSchema, ReviewManifestSchema } from '../../schema/src/api.js';
|
|
17
|
+
import { EffectiveDeltaSchema, EffectiveEvidenceSchema, EvidencePageSchema, HealthSchema, LayerRowsSchema, CheckDetailSchema, OutlineSchema, ProblemSchema, ReadySchema, ServerInfoSchema, StoreListingSchema, StoreWriteResultSchema, ChecksResultSchema, HelloEventSchema, ReportEventSchema, PingEventSchema, TestCatalogSchema, CatalogHealthSchema, TestHistorySchema, TestReliabilitySchema, RunListSchema, RunDetailSchema, ArtifactListSchema, UiCatalogSchema, ArtifactTagEditSchema, ArtifactTagEntrySchema, ArtifactTagsSchema, ReviewCollectionRequestSchema, ReviewCollectionSchema, ReviewCollectionListSchema, ReviewCollectionDetailSchema, ReviewNoteInputSchema, ReviewNoteSchema, ReviewManifestSchema } from '../../schema/src/api.js';
|
|
18
18
|
import { LiveRunSchema, LiveRunStartSchema, LiveRunUpdateSchema, ServerEditableSettingsSchema, ServerSettingsSnapshotSchema, GcPolicySchema, GcSnapshotSchema, GcRunResultSchema, AtlasChangeSchema, PublishChecksSchema, ReportSourcesSchema, ReportStatusSchema, RunsIndexSchema, SpecIndexSchema } from '../../schema/src/index.js';
|
|
19
19
|
/** The version of the API described, `major.minor.patch`: the minor grows when an operation or field is added, the major never within `/api`. */
|
|
20
20
|
export const API_VERSION = '1.6.0';
|
|
@@ -38,7 +38,7 @@ const COMPONENTS = {
|
|
|
38
38
|
Outline: [OutlineSchema, 'output'], EvidencePage: [EvidencePageSchema, 'output'], LayerRows: [LayerRowsSchema, 'output'], CheckDetail: [CheckDetailSchema, 'output'],
|
|
39
39
|
ArtifactTagEdit: [ArtifactTagEditSchema, 'input'], ArtifactTagEntry: [ArtifactTagEntrySchema, 'output'], ArtifactTags: [ArtifactTagsSchema, 'output'],
|
|
40
40
|
ReviewCollectionRequest: [ReviewCollectionRequestSchema, 'input'], ReviewCollection: [ReviewCollectionSchema, 'output'], ReviewCollectionList: [ReviewCollectionListSchema, 'output'], ReviewCollectionDetail: [ReviewCollectionDetailSchema, 'output'], ReviewNoteInput: [ReviewNoteInputSchema, 'input'], ReviewNote: [ReviewNoteSchema, 'output'], ReviewManifest: [ReviewManifestSchema, 'output'],
|
|
41
|
-
TestCatalog: [TestCatalogSchema, 'output'], CatalogHealth: [CatalogHealthSchema, 'output'], TestHistory: [TestHistorySchema, 'output'], TestReliability: [TestReliabilitySchema, 'output'], RunList: [RunListSchema, 'output'], ArtifactList: [ArtifactListSchema, 'output'], RunDetail: [RunDetailSchema, 'output'],
|
|
41
|
+
TestCatalog: [TestCatalogSchema, 'output'], CatalogHealth: [CatalogHealthSchema, 'output'], TestHistory: [TestHistorySchema, 'output'], TestReliability: [TestReliabilitySchema, 'output'], RunList: [RunListSchema, 'output'], ArtifactList: [ArtifactListSchema, 'output'], UiCatalog: [UiCatalogSchema, 'output'], RunDetail: [RunDetailSchema, 'output'],
|
|
42
42
|
SpecIndex: [SpecIndexSchema, 'output'], ReportSources: [ReportSourcesSchema, 'output'], RunsIndex: [RunsIndexSchema, 'output'],
|
|
43
43
|
RunEvent: [LiveRunSchema, 'output'], HelloEvent: [HelloEventSchema, 'output'], ReportEvent: [ReportEventSchema, 'output'], AtlasChangeEvent: [AtlasChangeSchema, 'output'], PingEvent: [PingEventSchema, 'output']
|
|
44
44
|
};
|
|
@@ -460,6 +460,26 @@ const BASE_OPERATIONS = [
|
|
|
460
460
|
],
|
|
461
461
|
responses: { '200': json('The matching results and the facets.', 'ArtifactList'), '304': { description: 'Unchanged since the `If-None-Match` ETag.' }, '401': UNAUTHORIZED, '503': NOT_READY }
|
|
462
462
|
},
|
|
463
|
+
{
|
|
464
|
+
route: 'GET /api/reports/ui-catalog', path: '/api/reports/ui-catalog', operationId: 'getUiCatalog', tag: 'Report', role: 'read',
|
|
465
|
+
summary: 'The UI catalog: captured UI states per profile, and what is still expected',
|
|
466
|
+
description: 'A browsable inventory of the product\'s user interface, computed from the winning results of the `ui-state` and `ui-plan` parts of every layer (see the UI catalog guide). Each state is a check id; each cell is one profile of it (the layer\'s environment and parameters) with its coverage: `captured` only when the winning capture passed, `failed`, `capturing`, `skipped`, or `missing` when a plan expects it and nothing has been captured. A picture is read from the cell\'s `capture.image.path` under the reports API root, or `uri`. What is expected is itself a layer, so a shard that never published leaves its states `missing`, never captured. The document equals what the viewer computes from the same report. Narrow it by `q` (words), `coverage`, `profile` (a profile `key`), `area`, `route`, `cohort`, `flag`, `surface` and `producer`: AND across parameters, OR within one; a state keeps only the cells that match `profile` and `coverage`. Page the states with `limit` and `offset`. Viewers need not poll: they hold the report over `/api/events` and read changes with `/api/reports/evidence/effective?since=`.',
|
|
467
|
+
parameters: [
|
|
468
|
+
{ name: 'limit', in: 'query', description: 'At most this many states (default 200).', schema: { type: 'integer', minimum: 0 } },
|
|
469
|
+
{ name: 'offset', in: 'query', description: 'Skip this many states (default 0).', schema: { type: 'integer', minimum: 0 } },
|
|
470
|
+
{ name: 'q', in: 'query', description: 'Words that must all appear in a state\'s id, title, route, fixture, cohort, area, flags, surfaces or producers.', schema: str },
|
|
471
|
+
{ name: 'coverage', in: 'query', description: 'Coverage values: `captured`, `failed`, `capturing`, `skipped`, `missing`. Comma-separated.', schema: str },
|
|
472
|
+
{ name: 'profile', in: 'query', description: 'Profile keys, as listed in `profiles[].key`.', schema: str },
|
|
473
|
+
{ name: 'area', in: 'query', description: 'Areas.', schema: str },
|
|
474
|
+
{ name: 'route', in: 'query', description: 'Routes.', schema: str },
|
|
475
|
+
{ name: 'cohort', in: 'query', description: 'Cohorts.', schema: str },
|
|
476
|
+
{ name: 'flag', in: 'query', description: 'Feature flags a state was captured with.', schema: str },
|
|
477
|
+
{ name: 'surface', in: 'query', description: 'Surfaces a state covers.', schema: str },
|
|
478
|
+
{ name: 'producer', in: 'query', description: 'Producers that captured or planned a state.', schema: str },
|
|
479
|
+
{ name: 'format', in: 'query', description: '`markdown` for Markdown instead of JSON.', schema: { type: 'string', enum: ['json', 'markdown'] } }
|
|
480
|
+
],
|
|
481
|
+
responses: { '200': json('The catalog.', 'UiCatalog'), '304': { description: 'Unchanged since the `If-None-Match` ETag.' }, '401': UNAUTHORIZED, '503': NOT_READY }
|
|
482
|
+
},
|
|
463
483
|
{
|
|
464
484
|
route: 'GET /api/reports/runs/detail', path: '/api/reports/runs/detail', operationId: 'getReportRun', tag: 'Report', role: 'read',
|
|
465
485
|
summary: 'Every test one run recorded',
|
|
@@ -926,6 +926,52 @@ Scoped to one project. The same project may be selected on the unprefixed API us
|
|
|
926
926
|
|
|
927
927
|
Responses: `200` The matching results and the facets.; `304` Unchanged since the `If-None-Match` ETag.; `401` No token, or an unknown one. Send `Authorization: Bearer <token>`.; `503` The server is still reading its backends. Retry after the number of seconds in `Retry-After`.
|
|
928
928
|
|
|
929
|
+
### The UI catalog: captured UI states per profile, and what is still expected
|
|
930
|
+
|
|
931
|
+
`GET /api/reports/ui-catalog` · role: read
|
|
932
|
+
|
|
933
|
+
A browsable inventory of the product's user interface, computed from the winning results of the `ui-state` and `ui-plan` parts of every layer (see the UI catalog guide). Each state is a check id; each cell is one profile of it (the layer's environment and parameters) with its coverage: `captured` only when the winning capture passed, `failed`, `capturing`, `skipped`, or `missing` when a plan expects it and nothing has been captured. A picture is read from the cell's `capture.image.path` under the reports API root, or `uri`. What is expected is itself a layer, so a shard that never published leaves its states `missing`, never captured. The document equals what the viewer computes from the same report. Narrow it by `q` (words), `coverage`, `profile` (a profile `key`), `area`, `route`, `cohort`, `flag`, `surface` and `producer`: AND across parameters, OR within one; a state keeps only the cells that match `profile` and `coverage`. Page the states with `limit` and `offset`. Viewers need not poll: they hold the report over `/api/events` and read changes with `/api/reports/evidence/effective?since=`.
|
|
934
|
+
|
|
935
|
+
- `limit` (query): At most this many states (default 200).
|
|
936
|
+
- `offset` (query): Skip this many states (default 0).
|
|
937
|
+
- `q` (query): Words that must all appear in a state's id, title, route, fixture, cohort, area, flags, surfaces or producers.
|
|
938
|
+
- `coverage` (query): Coverage values: `captured`, `failed`, `capturing`, `skipped`, `missing`. Comma-separated.
|
|
939
|
+
- `profile` (query): Profile keys, as listed in `profiles[].key`.
|
|
940
|
+
- `area` (query): Areas.
|
|
941
|
+
- `route` (query): Routes.
|
|
942
|
+
- `cohort` (query): Cohorts.
|
|
943
|
+
- `flag` (query): Feature flags a state was captured with.
|
|
944
|
+
- `surface` (query): Surfaces a state covers.
|
|
945
|
+
- `producer` (query): Producers that captured or planned a state.
|
|
946
|
+
- `format` (query): `markdown` for Markdown instead of JSON.
|
|
947
|
+
- `project` (query): Project slug. Alternatively send X-Atlas-Project or use the project-prefixed route. Omit for the default project. Conflicting selectors are refused.
|
|
948
|
+
|
|
949
|
+
Responses: `200` The catalog.; `304` Unchanged since the `If-None-Match` ETag.; `401` No token, or an unknown one. Send `Authorization: Bearer <token>`.; `503` The server is still reading its backends. Retry after the number of seconds in `Retry-After`.
|
|
950
|
+
|
|
951
|
+
### The UI catalog: captured UI states per profile, and what is still expected
|
|
952
|
+
|
|
953
|
+
`GET /api/projects/{project}/reports/ui-catalog` · role: read
|
|
954
|
+
|
|
955
|
+
A browsable inventory of the product's user interface, computed from the winning results of the `ui-state` and `ui-plan` parts of every layer (see the UI catalog guide). Each state is a check id; each cell is one profile of it (the layer's environment and parameters) with its coverage: `captured` only when the winning capture passed, `failed`, `capturing`, `skipped`, or `missing` when a plan expects it and nothing has been captured. A picture is read from the cell's `capture.image.path` under the reports API root, or `uri`. What is expected is itself a layer, so a shard that never published leaves its states `missing`, never captured. The document equals what the viewer computes from the same report. Narrow it by `q` (words), `coverage`, `profile` (a profile `key`), `area`, `route`, `cohort`, `flag`, `surface` and `producer`: AND across parameters, OR within one; a state keeps only the cells that match `profile` and `coverage`. Page the states with `limit` and `offset`. Viewers need not poll: they hold the report over `/api/events` and read changes with `/api/reports/evidence/effective?since=`.
|
|
956
|
+
|
|
957
|
+
Scoped to one project. The same project may be selected on the unprefixed API using ?project= or X-Atlas-Project. Unknown projects return 404 on reads and are created by an authenticated upload.
|
|
958
|
+
|
|
959
|
+
- `project` (path, required): Project slug. Alternatively send X-Atlas-Project or use the project-prefixed route. Omit for the default project. Conflicting selectors are refused.
|
|
960
|
+
- `limit` (query): At most this many states (default 200).
|
|
961
|
+
- `offset` (query): Skip this many states (default 0).
|
|
962
|
+
- `q` (query): Words that must all appear in a state's id, title, route, fixture, cohort, area, flags, surfaces or producers.
|
|
963
|
+
- `coverage` (query): Coverage values: `captured`, `failed`, `capturing`, `skipped`, `missing`. Comma-separated.
|
|
964
|
+
- `profile` (query): Profile keys, as listed in `profiles[].key`.
|
|
965
|
+
- `area` (query): Areas.
|
|
966
|
+
- `route` (query): Routes.
|
|
967
|
+
- `cohort` (query): Cohorts.
|
|
968
|
+
- `flag` (query): Feature flags a state was captured with.
|
|
969
|
+
- `surface` (query): Surfaces a state covers.
|
|
970
|
+
- `producer` (query): Producers that captured or planned a state.
|
|
971
|
+
- `format` (query): `markdown` for Markdown instead of JSON.
|
|
972
|
+
|
|
973
|
+
Responses: `200` The catalog.; `304` Unchanged since the `If-None-Match` ETag.; `401` No token, or an unknown one. Send `Authorization: Bearer <token>`.; `503` The server is still reading its backends. Retry after the number of seconds in `Retry-After`.
|
|
974
|
+
|
|
929
975
|
### Every test one run recorded
|
|
930
976
|
|
|
931
977
|
`GET /api/reports/runs/detail` · role: read
|