@crvouga/atlas 0.10.2 → 0.11.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 +6 -0
- package/README.md +7 -0
- package/dist/server/src/settings-page.d.ts +4 -4
- package/dist/server/src/settings-page.js +17 -78
- package/docs/reference/server.md +4 -4
- package/docs/ui.md +142 -0
- package/docs/workspaces.md +130 -0
- package/llms-full.txt +278 -0
- package/llms.txt +2 -0
- package/package.json +17 -10
- package/packages/visualizer/src/admin/SettingsPage.tsx +456 -0
- package/packages/visualizer/src/admin/main.tsx +11 -0
- package/packages/visualizer/src/app/AppShell.tsx +62 -38
- package/packages/visualizer/src/app/gazetteer.tsx +90 -83
- package/packages/visualizer/src/app/router.tsx +33 -15
- package/packages/visualizer/src/components/ActivityIndicator.tsx +4 -5
- package/packages/visualizer/src/components/DataIssues.tsx +36 -54
- package/packages/visualizer/src/components/Header.tsx +197 -125
- package/packages/visualizer/src/components/Legend.tsx +13 -41
- package/packages/visualizer/src/components/ProjectPicker.tsx +61 -26
- package/packages/visualizer/src/components/Screen.tsx +80 -71
- package/packages/visualizer/src/components/SpecLogo.tsx +15 -0
- package/packages/visualizer/src/components/Status.tsx +20 -34
- package/packages/visualizer/src/components/labels.tsx +8 -3
- package/packages/visualizer/src/components/spec-logos/APACHE-2.0.txt +206 -0
- package/packages/visualizer/src/components/spec-logos/CAMUNDA-MIT.txt +21 -0
- package/packages/visualizer/src/components/spec-logos/FILE-ICONS-ISC.txt +13 -0
- package/packages/visualizer/src/components/spec-logos/README.md +23 -0
- package/packages/visualizer/src/components/spec-logos/SIMPLE-ICONS-CC0.txt +30 -0
- package/packages/visualizer/src/components/spec-logos/alloy.svg +1 -0
- package/packages/visualizer/src/components/spec-logos/dmn.svg +3 -0
- package/packages/visualizer/src/components/spec-logos/gherkin.svg +1 -0
- package/packages/visualizer/src/components/spec-logos/openslo.svg +63 -0
- package/packages/visualizer/src/components/spec-logos/quint.svg +1 -0
- package/packages/visualizer/src/evidence/artifacts.tsx +263 -110
- package/packages/visualizer/src/evidence/chart-source.tsx +18 -0
- package/packages/visualizer/src/evidence/check-detail.tsx +283 -139
- package/packages/visualizer/src/evidence/decision-table.tsx +35 -26
- package/packages/visualizer/src/evidence/document-page.tsx +51 -29
- package/packages/visualizer/src/evidence/feature-page.tsx +121 -53
- package/packages/visualizer/src/evidence/marks.tsx +112 -79
- package/packages/visualizer/src/evidence/model-page.tsx +77 -46
- package/packages/visualizer/src/evidence/model-trace.tsx +55 -35
- package/packages/visualizer/src/evidence/overview.tsx +137 -69
- package/packages/visualizer/src/evidence/recording-page.tsx +70 -31
- package/packages/visualizer/src/evidence/recording.tsx +135 -68
- package/packages/visualizer/src/evidence/snapshot.tsx +99 -43
- package/packages/visualizer/src/evidence/source-text.tsx +33 -0
- package/packages/visualizer/src/evidence/sources-panel.tsx +138 -144
- package/packages/visualizer/src/evidence/spec-header.tsx +52 -36
- package/packages/visualizer/src/evidence/spec-index.tsx +61 -32
- package/packages/visualizer/src/evidence/spec-page.tsx +56 -25
- package/packages/visualizer/src/evidence/test-filter.tsx +38 -14
- package/packages/visualizer/src/explorer/Explorer.tsx +688 -261
- package/packages/visualizer/src/explorer/ExplorerIndex.tsx +136 -68
- package/packages/visualizer/src/explorer/RunsView.tsx +307 -94
- package/packages/visualizer/src/explorer/TestDetail.tsx +393 -118
- package/packages/visualizer/src/explorer/parts.tsx +35 -13
- package/packages/visualizer/src/find/Finder.tsx +106 -90
- package/packages/visualizer/src/find/open.ts +17 -20
- package/packages/visualizer/src/live/test-progress.tsx +60 -22
- package/packages/visualizer/src/looks/Stage.tsx +223 -110
- package/packages/visualizer/src/main.tsx +9 -11
- package/packages/visualizer/src/map/ChartMap.tsx +125 -69
- package/packages/visualizer/src/map/EventEdge.tsx +59 -37
- package/packages/visualizer/src/map/map.module.css +12 -546
- package/packages/visualizer/src/map/nodes.tsx +124 -70
- package/packages/visualizer/src/reachable.test.ts +3 -2
- package/packages/visualizer/src/spec-kind.ts +2 -2
- package/packages/visualizer/src/ui/grammars/ALLOY-MIT.txt +21 -0
- package/packages/visualizer/src/ui/grammars/QUINT-APACHE-2.0.txt +206 -0
- package/packages/visualizer/src/ui/grammars/README.md +14 -0
- package/packages/visualizer/src/ui/grammars/alloy.json +71 -0
- package/packages/visualizer/src/ui/grammars/quint.json +152 -0
- package/packages/visualizer/src/ui/highlight.ts +50 -0
- package/packages/visualizer/src/ui/theme.tsx +109 -0
- package/packages/visualizer/src/views/ChartPage.tsx +46 -26
- package/packages/visualizer/src/views/ChartTests.tsx +59 -22
- package/packages/visualizer/src/views/ProductPage.tsx +16 -15
- package/packages/visualizer/src/views/SidePanel.tsx +241 -131
- package/packages/visualizer/src/app/gazetteer.module.css +0 -107
- package/packages/visualizer/src/components/ActivityIndicator.module.css +0 -4
- package/packages/visualizer/src/components/DataIssues.module.css +0 -136
- package/packages/visualizer/src/components/Header.module.css +0 -114
- package/packages/visualizer/src/components/Legend.module.css +0 -84
- package/packages/visualizer/src/components/Screen.module.css +0 -312
- package/packages/visualizer/src/components/Status.module.css +0 -116
- package/packages/visualizer/src/components/icons.tsx +0 -156
- package/packages/visualizer/src/evidence/artifacts.module.css +0 -213
- package/packages/visualizer/src/evidence/evidence.module.css +0 -907
- package/packages/visualizer/src/evidence/recording.module.css +0 -460
- package/packages/visualizer/src/evidence/sources.module.css +0 -168
- package/packages/visualizer/src/evidence/spec-snapshot.tsx +0 -26
- package/packages/visualizer/src/explorer/explorer.module.css +0 -1238
- package/packages/visualizer/src/find/Finder.module.css +0 -168
- package/packages/visualizer/src/looks/stage.module.css +0 -300
- package/packages/visualizer/src/styles/global.css +0 -105
- package/packages/visualizer/src/styles/tokens.css +0 -80
- package/packages/visualizer/src/views/views.module.css +0 -546
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg viewBox="0 0 512 512" version="1.1" xmlns="http://www.w3.org/2000/svg" width="512px" height="512px"><path d="M505.9067383,391.3167419c-1.9882202-1.2072144-4.0441284-2.4555664-4.4449768-2.7857971c-2.7047119-2.2290649-5.3686829-4.631134-7.9449463-6.954071c-3.5515137-3.202301-7.2239075-6.5136414-11.1118469-9.4763184c-1.2219543-0.9310303-2.4984741-1.8641357-3.7954407-2.6467285c10.8281555-6.5928955,21.0152893-11.00177,31.0691223-13.4526672c0.7668457-0.1868896,1.5579529-0.3283386,2.3213501-0.4414368v36.8015747c-1.4026794,0.0848083-2.6984253,0.1762695-3.9220276,0.2768555C507.3363953,392.1847839,506.6029663,391.739502,505.9067383,391.3167419z M334.6712341,368.9454346c0.0527954,0.238739,0.0791321,0.4535828,0.0915833,0.6474609c1.5794678,1.552002,3.085968,2.8637695,4.5900269,3.997467c0.5892029,0.3833618,1.1938171,0.7979736,1.7983704,1.2331238c1.6985474,1.131012,3.114502,1.9319153,4.4543152,2.5195923c2.3634033,1.0365295,4.4266968,1.5449219,6.3057556,1.5536499c-0.9069214-21.1407166-1.0591736-46.5664978-1.2201538-73.4483643c-0.2966614-49.5463562-0.6329346-105.7034607-5.954895-148.6080475c-6.01828-48.5173798-17.2938232-72.1024704-34.4709473-72.1030884c-1.7828979-0.000061-3.6660767,0.2585373-5.5970764,0.7685394c-25.2353821,6.6658325-58.4373016,10.3368149-93.4897308,10.3368149c-30.3443756,0-75.8174133-2.8103485-120.1284485-16.1987991C49.5760689,67.1125336,18.9527874,48.2956772,0,23.7037697l0.0000614,268.9431458c4.6186762-0.2954407,9.5692539-0.4340515,15.4223356-0.4340515c4.9925718,0,9.9637766,0.1021423,14.7712431,0.2009277c1.3553543,0.027832,2.7019901,0.0555725,4.038496,0.0807495c10.3425217,0.1950378,20.9237442,0.6860352,31.4640846,1.4597778c8.4638367-10.2627563,25.273941-24.5184021,57.6892166-35.4081421c16.0383759-5.3879547,32.3448486-8.1199036,48.4665375-8.1199036c12.0640411,0,23.9324646,1.5531006,35.2755432,4.6160889c37.770752,10.1995239,70.5679779,36.0386963,103.1838837,81.2988281c3.1065063,1.293396,6.3551636,4.48703,8.6299133,7.0718079c-0.6476746-2.3256836-1.2742615-4.524292-1.8992615-6.6658936c-6.65448-22.8026123-14.6377563-43.8547363-23.7279053-62.5716248c-15.2195435-31.3377991-32.0744019-54.4687653-51.5276794-70.7145844c-11.1168976-9.2838898-33.3225098-24.8586121-57.1380768-24.8596497c-1.7100372-0.000061-3.4225769,0.082077-5.0900116,0.2440491c-0.327713,0.037262-0.678833,0.0574036-1.0198212,0.0574036c-4.867691,0-7.6378937-3.9600983-7.8586731-7.871994c-0.2095337-3.7145844,1.9100647-7.9781494,7.0592499-8.5610962c2.0975494-0.1867523,4.1960907-0.2795258,6.2736969-0.2795258c17.9443207,0,36.2525177,6.7342224,54.4160156,20.0157166c18.4157562,13.4660492,32.1970062,30.3768463,40.515152,42.1921082c15.5446472,22.0800629,28.1781616,48.6380157,39.7585449,83.5795746C325.6146851,328.8337402,330.5695496,350.383606,334.6712341,368.9454346z M232.8213959,499.6643066c-0.7213287,0-1.4414215,0.0063171-2.1629333,0.0190125c-2.8770905,0.0505981-5.9026947,0.23172-9.4755096,0.5683899c-3.0326538,3.8323364-5.9365082,7.7721863-8.6596832,11.748291h74.8784332c-0.6366577-0.3006592-1.2580872-0.587677-1.8710022-0.8642578C268.9049072,503.631012,250.6782837,499.6643066,232.8213959,499.6643066z M391.27948,428.6816101c6.0384216,0,10.5497131-7.0609131,13.843811-12.2165527l0.482605-0.754303c2.0703735-3.2259216,4.0874329-6.5734253,6.038269-9.8106384c2.5160217-4.1755981,5.1177979-8.4933167,7.8818054-12.6326904c14.1216125-21.1487427,23.6819153-24.0001831,31.1713562-24.0001831c1.5512695,0,3.132843,0.1671753,4.7120056,0.4974976C474.1539307,354.1101379,492.6838684,344.1481934,512,339.3430786v-16.0788269c-1.6700745-0.8259583-3.2780457-1.7054443-4.8405457-2.5599365c-4.083252-2.2331848-7.940033-4.3424683-12.6175842-5.4407349c-3.2544861-0.7641296-6.5870056-1.1516724-9.9049683-1.1516724c-20.2616577,0-38.2507935,14.4998169-49.7738647,26.6635742c-14.3085938,15.104248-26.8860474,34.3274841-39.5820923,60.4964294l-0.023407,0.0480652c-3.7885437,7.80896-7.7018433,15.874939-10.9719238,24.1673889c1.5927734,1.5735474,3.1387939,2.4897461,4.9230652,2.9328918C389.9066772,428.593689,390.6033936,428.6816101,391.27948,428.6816101z M498.2315063,490.2285767c-13.388916,5.6862183-27.5002441,12.829071-43.0007324,21.7714233H512v-26.5100098C507.0099487,486.8546143,502.5917969,488.376709,498.2315063,490.2285767z M425.3007812,499.4590454l0.2105103-0.001709c1.5509033-0.0248108,4.0146179-0.8549805,6.6229858-1.7339172c3.3512878-1.129364,7.1496277-2.4093323,10.3510437-2.4093323c2.3826294,0,4.2497559,0.7137756,5.5494385,2.121521c1.4094849,1.5264587,1.6169434,3.3591614,1.4503784,5.1261597c9.816925-6.5220337,19.519165-12.5127869,28.8831787-17.833313C489.9494019,478.1482544,500.508606,472.3953247,512,468.8170471v-16.8721313c-0.1316223-0.0272522-0.262207-0.0543213-0.3916931-0.0812073c-0.8528442-0.1771851-1.6584778-0.3444824-2.3416748-0.4498596c-7.7167053-1.1896362-15.8641357-1.7928467-24.2159729-1.7928467c-7.2407227,0-14.8301392,0.4534607-22.5574036,1.3478699c-10.2573853,1.1871338-20.8169861,3.2503662-31.3879089,6.1326599c-14.4362183,8.6638184-11.4327087,33.0924072-9.9276123,41.4022217C422.2686157,499.1379395,423.6523132,499.4590454,425.3007812,499.4590454z M512,305.5908508V0h-77.7280884c-11.6720886,7.4448676-38.1645203,27.3103504-41.3017578,55.7893524c-2.2252502,20.1995316-8.6766357,269.3074951-10.6762085,355.6675415c0.6743774-1.5868225,1.3470154-3.1384583,2.0351868-4.6792908c10.5391235-23.5948486,21.3808899-42.9328918,33.1449585-59.1192932c21.4612122-29.5282288,38.2827148-38.4454041,49.0686951-42.5840454c6.9026489-2.6484985,14.0892029-3.9914551,21.3600769-3.9914551C495.7207642,301.0828247,503.6248779,302.5596619,512,305.5908508z M401.1506653,459.5325317c3.6091614-1.8826599,7.4124451-3.7037659,11.6066284-5.5572815c8.4682617-16.1976318,20.9973755-30.7404785,35.3268738-40.993988c11.2789917-8.0707703,23.9174194-13.662323,38.6065979-17.076355c0.3656006-4.1283875-0.5410156-7.4679565-2.700592-9.9382935c-2.4505005-2.8031921-6.4874573-4.3469543-11.3674927-4.3469543c-3.0109558,0-6.2440491,0.6000061-9.3497925,1.735199c-3.0959473,1.1316223-6.2703857,2.5321045-9.6998291,4.2796021c-20.5230103,17.1070557-39.6418762,38.1210022-56.8291321,62.4608765c-0.9249878,2.4291687-2.5976257,6.8633423-1.3722534,8.6340942c0.2004089,0.2896729,0.8099976,1.1706238,2.9428406,1.1706238C399.1213684,459.9000549,400.0508423,459.7796631,401.1506653,459.5325317z M512,435.8431396v-27.0612183c-0.6609802-0.0187683-1.3134155-0.0545654-1.9509583-0.0895691c-0.8413391-0.0461731-1.6360474-0.0898132-2.368103-0.0898132l-0.1881104,0.0010376c-15.0732422,0.166687-29.0137634,3.09552-41.434021,8.7050476c-14.3737488,6.4918518-27.7913818,17.2885132-38.1764526,30.6508484c23.3139343-8.1933289,48.1202087-12.3441162,73.8115234-12.3442383C505.1119995,435.6152344,508.571228,435.691803,512,435.8431396z M218.1866455,482.7236023c-18.8322754-4.7961121-34.8102264-7.1305237-48.7727203-7.1305237c-12.0540314,0-22.8657227,1.7673035-32.1347656,5.2528687c-1.0392303,0.4208069-2.1173248,0.6409607-3.1698151,0.6409607c-4.3018188,0-7.1706772-3.580719-7.781311-7.1177368c-0.7022324-4.0677185,1.3449783-7.5860901,5.2154999-8.9634094c9.583374-3.2192383,20.4962463-4.8471375,32.4608307-4.8471375c16.2374725,0,34.9786224,3.0162048,55.7027283,8.9648438c3.0140533,0.8651733,6.2578583,1.8719177,9.8934174,3.0707092c14.412323-11.5157166,28.5320282-18.34552,41.9784393-20.3037109c4.898407-0.7583008,17.2876892-3.117218,23.1791077-5.8934937c-4.875824-2.3903503-9.7303772-4.4091187-14.4644165-6.0137939c-14.416687-4.8869324-28.766449-7.408844-42.65065-7.4956665c-0.2998505-0.0018921-0.6005096-0.0028076-0.9005432-0.0028076c-15.528183-0.0001221-30.6141357,2.4609985-44.8387146,7.3150024c-1.2014313,0.4100647-2.6768188,1.1234741-4.2389526,1.8787537c-3.3673859,1.6283875-7.1839905,3.4739075-10.5986633,3.4739075c-0.6139374,0-1.2048645-0.0604858-1.7563171-0.1798096c-3.5195312-0.7618103-6.0051575-3.6321411-6.3323364-7.3123779c-0.3275909-3.6847534,1.6186829-6.9539185,4.958374-8.3286743c15.0740509-6.3076477,32.590683-9.3754883,53.5428009-9.3754883c6.6641693,0,13.5708466,0.3052673,21.114563,0.9332275c6.4182129,0.5341797,12.0974426,0.8049927,16.8800354,0.8049927c16.4429016,0,17.3446045-3.1721497,17.3748779-3.3072205c0.1922913-0.855835-1.4028931-3.019043-6.5854797-5.4711914l-0.059967-0.0283813l-0.0573425-0.0335693c-0.2958069-0.1733398-0.6802063-0.3950806-1.0291748-0.5733032c-9.4683228-4.8323975-19.4544983-8.7861023-29.6805573-11.7512512c-12.3604431-3.5838013-24.7378387-5.4011536-36.78862-5.4014587c-9.2161713-0.0001831-18.2914886,1.0728149-26.9739685,3.1893005c-9.4209747,2.2964783-18.8284607,5.9985657-27.9640808,11.0041504c-14.5600433,16.9994507-27.995575,39.1376648-39.9385376,65.8077393C107.3662186,489.8301697,103.1642303,501.1779175,100.2788544,512h43.2884369c19.9890747-13.483551,44.7906952-22.2330627,69.9508209-24.6784058L218.1866455,482.7236023z M293.5035706,462.1083069c-4.7232971-2.8439331-9.5757141-3.3801575-14.1224976-3.5219116c-2.2225647,0.2644043-4.0562439,0.5905457-5.7622681,1.0246582c-10.1026611,2.5702515-20.2217712,8.3619385-30.8748779,17.6808777c17.8566284,6.8173523,36.0757446,15.5748901,58.4962463,28.110199c1.5149841-4.2584534,2.7310181-8.9302979,3.6211853-13.916748C304.8018188,479.1054688,303.8786926,468.3557739,293.5035706,462.1083069z M198.6313171,504.3270569c-7.385498,1.9719238-14.6631165,4.5405273-21.7407227,7.6729431h16.1026459c0.2182617-0.4779663,0.474472-0.9147949,0.7730865-1.3196106C195.3208466,508.575592,196.9489136,506.449646,198.6313171,504.3270569z M116.9049606,438.7043762c-11.4611359,12.0882263-22.0529251,26.4790039-31.5902481,42.9377441C79.2779312,492.059845,74.3686142,502.7828369,70.3426437,512H83.451561c4.9470749-20.57724,15.0034943-40.5792542,24.229126-57.4843445C110.6285629,449.1136475,113.7129211,443.8276672,116.9049606,438.7043762z M274.1224976,376.0948486c-4.9735413-2.2328491-9.552063-3.9964294-13.9944153-5.3908386c-7.8893738-2.4761658-17.1880035-3.8398743-26.1828461-3.8398743c-3.1059113,0-6.1356201,0.1627502-9.0049133,0.4836731c-6.621994,0.7409058-14.7272797,2.662262-20.6491852,4.8950195c-9.8444824,3.711792-19.421051,9.1605835-28.544693,16.2337952c8.8646851-2.1094055,18.0254059-3.1759644,27.3220673-3.1759644c24.3227539,0,49.7184448,6.9590454,77.6342163,21.2741089c2.9433899,0.9047241,5.5387878,1.3634033,7.7162781,1.3634033c2.5661926,0,4.5647888-0.6400452,5.940155-1.9021912c1.0259094-0.9413757,1.657959-2.0238953,2.1598816-2.9320984C291.1136475,391.3270569,283.581665,382.2431335,274.1224976,376.0948486z M146.3314056,399.8283997l0.6604919-0.7109375c1.0017242-1.0799561,2.0375671-2.1967163,3.0969391-3.2725525c19.1668091-19.4646301,39.5576477-31.7660217,60.6051025-36.5626221c0.2848816-0.0822754,0.5389862-0.1644592,0.7644958-0.2446594c-0.0642853-0.0079651-0.1308899-0.0157776-0.1999054-0.0233765c-10.5660553-1.1651611-19.8023682-1.7315369-28.2368622-1.7315369c-1.6999512,0-3.3873291,0.0237732-5.0153503,0.0707397c-43.7891693,1.2623901-83.9879608,16.3554077-113.1914825,42.4987183C35.4439468,426.1454468,15.0298996,461.8154602,0.6600565,512h52.7514114c-0.0608406-1.1967773,0.142189-2.3753662,0.6061516-3.4794922c9.5460472-22.7148132,22.4001732-44.2469177,37.1728859-62.2686157C107.6790924,426.1370239,126.2296143,410.5193481,146.3314056,399.8283997z M302.2546082,352.1455078c0.4702148-2.4465942,0.5567932-5.0545959,0.5195923-8.2078857c-0.0037537-0.3177185-0.019104-0.6517639-0.0344543-0.9940491c-0.0210571-0.4679565-0.0426025-0.9475708-0.041626-1.4370117c-6.1270752-8.7380066-12.7108765-17.1125793-19.5745239-24.8985596c-14.5324097-16.4848938-30.8231964-29.6563721-48.4198303-39.1487732c-18.214325-9.8256226-38.9366302-15.019165-59.9267578-15.019165c-25.5462189,0-50.7083054,7.4155884-72.7660217,21.4451294c-5.4580612,3.4715576-10.5303268,7.4133606-15.4297028,11.9959412c7.4983444,0.835907,14.8109055,1.8021851,21.781311,2.8786926c24.3635254,3.7625122,45.0170746,8.4888306,63.1408386,14.4489136c22.4605865,7.3861694,41.4681396,16.7114563,58.1087341,28.5085449c1.1655273,0.7752991,11.3788147,4.7902527,19.2092285,4.7902527c1.5245667,0,2.8677673-0.1549988,3.9922638-0.4608154c6.0761414-1.6521912,14.0704956-3.5487976,22.0229187-3.5487976c8.164032,0,15.4377441,1.9484253,22.2367249,5.9565735C298.8320923,349.4915161,300.5151672,350.6884766,302.2546082,352.1455078z M92.4402618,365.7033997c17.4549408-8.5953979,36.2481537-14.4567261,55.8576813-17.4211121c10.251236-1.54953,20.9550629-2.3352661,31.8139191-2.3353271c3.1395569,0,6.3416595,0.065979,9.5173798,0.1960754c5.9248505,0.2427673,11.6092224,0.7050781,16.8952484,1.3741455c0.684494,0.0867004,1.3527222,0.1305847,1.9861908,0.1305847c3.1363525,0,5.4457855-1.0815735,5.8834076-2.7555237c0.3993225-1.5275574-0.7566833-4.0481873-5.1989746-6.5413818c-10.9342499-6.1367798-22.9043427-10.2626343-34.2110748-13.8070374c-23.9891357-7.52005-50.9696732-12.5457153-82.4832993-15.3641968c-5.7657242-0.5156555-11.7086258-0.95578-17.6792755-1.3093567c-1.9574509,3.116272-5.9399567,8.6774902-9.4254074,8.6774902c-0.9333878,0-1.7492638-0.3783569-2.3594055-1.0941772c-1.1761398-1.3797302-1.5022697-3.9440613-1.0031319-8.0057678c-7.8656654-0.3160706-15.0199509-0.4699097-21.8223839-0.4699097c-8.9654331,0-17.6211929,0.2662048-26.46175,0.8139038c-5.0504665,0.3127441-9.5640965,0.6854858-13.7493248,1.1359863v158.1146851c11.9763632-27.1571045,26.6814842-49.2485962,44.8174133-67.364563C58.6049843,385.9055786,74.6275787,374.474823,92.4402618,365.7033997z"/></svg>
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
|
2
|
+
<path d="M4.99929,2.99597 C3.895,2.99597 2.99968,3.89098 2.9993,4.99527 L2.99435987,19.0076 C2.99397,20.1124 3.88951,21.0083 4.99435987,21.0083 L18.9944,21.0083 C20.0987,21.0083 20.994,20.1133 20.9944,19.009 L20.9993001,4.99667 C20.9997,3.89183 20.1041,2.99597 18.9993,2.99597 L4.99929,2.99597 Z M11,11 L18.9937,11.0081 L18.9937,14.0041 L11,13.996 L11,11 Z M11,5.0041 L18.9937,5.01488526 L18.9937,9.0041 L11,8.99331474 L11,5.0041 Z M5,5.0041 L9,5.01488526 L9,9.0041 L5,8.99331474 L5,5.0041 Z M8.97665,13.996 L4.99365,14 L4.99365,11.0041 L8.97665,11 L8.97665,13.996 Z M4.99365,16 L8.97665,15.996 L8.97665,19 L4.99365,19.0042 L4.99365,16 Z M11,19.0042 L11,15.9919 L18.9937,16 L18.9937,19.0083 L11,19.0042 Z" fill="currentColor" ></path>
|
|
3
|
+
</svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Cucumber</title><path d="M12.16 0C7.523-.03 3.223 3.007 1.886 7.715.241 13.51 3.746 19.51 9.601 20.925V24l.626-.094c6.715-1.008 11.876-6.254 12.271-12.472.258-4.041-1.795-8.064-5.108-10.01a9.62 9.62 0 0 0-1.999-.895A10.606 10.606 0 0 0 12.16 0zm-.084 1.087h.013c1.011 0 2.015.161 2.976.477a8.511 8.511 0 0 1 1.769.792c2.97 1.744 4.809 5.363 4.576 9.008-.35 5.52-4.816 10.208-10.72 11.36V20.04l-.44-.085a9.518 9.518 0 0 1 1.826-18.868zm2.042 4.306a.958.958 0 0 0-.843.333 3.83 3.83 0 0 0-.366.632c-.321.743-.436 1.803.043 2.385l-.001.003a3.08 3.08 0 0 0 1.918-1.641 1.68 1.68 0 0 0 .165-.698.996.996 0 0 0-.916-1.014zm-4.061.092a1.014 1.014 0 0 0-.926.982c.01.241.07.478.18.694a3.282 3.282 0 0 0 2.062 1.6c.413-.593.216-1.65-.118-2.386a2.17 2.17 0 0 0-.377-.574.934.934 0 0 0-.821-.316zM7.628 8c-.858.035-1.2 1.126-.516 1.645.198.146.41.273.632.38a3 3 0 0 0 2.53-.07A3.17 3.17 0 0 0 8.54 8.167 1.993 1.993 0 0 0 7.628 8zm7.762 3.216a3.32 3.32 0 0 0-1.228.296 3.087 3.087 0 0 0 1.718 1.755c.236.105.49.161.747.166a.933.933 0 0 0 .681-1.663c-.659-.46-1.105-.575-1.918-.554zm-5.85.03c-.297-.012-.635.01-.983.026-.559 0-1.228.278-1.494.565-.695.61-.188 1.751.73 1.644a1.71 1.71 0 0 0 .747-.167c.744-.322 1.628-1.202 1.734-1.89-.182-.12-.438-.165-.735-.178zm2.086 1.214c-.863.32-1.56.975-1.93 1.817a1.601 1.601 0 0 0-.167.681c-.02.908 1.091 1.361 1.711.698.14-.199.262-.41.362-.632.322-.69.449-1.928.024-2.564zm1.497.173a2.792 2.792 0 0 0-.116 2.442c.089.211.21.408.362.58.577.627 1.81.186 1.763-.63a1.62 1.62 0 0 0-.167-.697 3.043 3.043 0 0 0-1.842-1.695z"/></svg>
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
2
|
+
<svg
|
|
3
|
+
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
|
4
|
+
xmlns:cc="http://creativecommons.org/ns#"
|
|
5
|
+
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
|
6
|
+
xmlns:svg="http://www.w3.org/2000/svg"
|
|
7
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
8
|
+
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
|
9
|
+
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
|
10
|
+
width="28mm"
|
|
11
|
+
height="28mm"
|
|
12
|
+
viewBox="0 0 28 28"
|
|
13
|
+
version="1.1"
|
|
14
|
+
id="svg146"
|
|
15
|
+
inkscape:version="1.0.2 (e86c870879, 2021-01-15, custom)"
|
|
16
|
+
sodipodi:docname="logo2.svg">
|
|
17
|
+
<defs
|
|
18
|
+
id="defs140" />
|
|
19
|
+
<sodipodi:namedview
|
|
20
|
+
id="base"
|
|
21
|
+
pagecolor="#ffffff"
|
|
22
|
+
bordercolor="#666666"
|
|
23
|
+
borderopacity="1.0"
|
|
24
|
+
inkscape:pageopacity="0.0"
|
|
25
|
+
inkscape:pageshadow="2"
|
|
26
|
+
inkscape:zoom="3.959798"
|
|
27
|
+
inkscape:cx="221.86556"
|
|
28
|
+
inkscape:cy="101.82051"
|
|
29
|
+
inkscape:document-units="mm"
|
|
30
|
+
inkscape:current-layer="layer1"
|
|
31
|
+
inkscape:document-rotation="0"
|
|
32
|
+
showgrid="false"
|
|
33
|
+
inkscape:window-width="3159"
|
|
34
|
+
inkscape:window-height="1669"
|
|
35
|
+
inkscape:window-x="0"
|
|
36
|
+
inkscape:window-y="38"
|
|
37
|
+
inkscape:window-maximized="0" />
|
|
38
|
+
<metadata
|
|
39
|
+
id="metadata143">
|
|
40
|
+
<rdf:RDF>
|
|
41
|
+
<cc:Work
|
|
42
|
+
rdf:about="">
|
|
43
|
+
<dc:format>image/svg+xml</dc:format>
|
|
44
|
+
<dc:type
|
|
45
|
+
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
|
46
|
+
<dc:title></dc:title>
|
|
47
|
+
</cc:Work>
|
|
48
|
+
</rdf:RDF>
|
|
49
|
+
</metadata>
|
|
50
|
+
<g
|
|
51
|
+
inkscape:label="Layer 1"
|
|
52
|
+
inkscape:groupmode="layer"
|
|
53
|
+
id="layer1">
|
|
54
|
+
<g
|
|
55
|
+
id="g56"
|
|
56
|
+
transform="matrix(0.15739557,0,0,-0.15739557,25.12113,17.835388)">
|
|
57
|
+
<path
|
|
58
|
+
d="m 0,0 -32.173,-40.343 c -1.892,-2.375 -4.721,-3.739 -7.759,-3.744 -3.868,0 -7.407,2.259 -9.032,5.753 l -6.701,14.423 c -0.584,1.257 -0.637,2.663 -0.149,3.96 0.487,1.297 1.454,2.32 2.723,2.882 0.625,0.276 1.287,0.417 1.969,0.417 2.052,0 3.953,-1.239 4.843,-3.154 l 2.266,-4.877 c 1.007,-2.168 3.119,-3.513 5.514,-3.513 1.853,0 3.579,0.833 4.738,2.286 l 14.422,18.086 c 1.33,1.667 1.688,3.859 0.959,5.862 -0.73,2.003 -2.413,3.451 -4.504,3.873 l -5.812,1.174 c -2.84,0.574 -4.747,3.257 -4.252,5.979 0.443,2.439 2.558,4.209 5.027,4.209 0.34,0 0.685,-0.035 1.023,-0.103 l 6.897,-1.393 c 0.402,-0.082 0.813,-0.123 1.218,-0.123 1.846,0 3.571,0.836 4.734,2.293 1.155,1.449 1.581,3.32 1.168,5.131 l -5.272,23.102 c -0.635,2.78 -3.075,4.722 -5.933,4.722 -1.362,0 -2.655,-0.449 -3.738,-1.3 l -5.197,-4.086 c -0.911,-0.716 -2.003,-1.095 -3.16,-1.095 -1.732,0 -3.338,0.868 -4.293,2.323 -1.444,2.196 -0.872,5.254 1.301,6.961 l 5.176,4.069 c 1.657,1.304 2.511,3.333 2.282,5.431 -0.229,2.098 -1.5,3.897 -3.401,4.811 l -21.738,10.468 c -0.835,0.404 -1.721,0.607 -2.633,0.607 -1.604,0 -3.177,-0.657 -4.317,-1.804 -1.141,-1.146 -1.764,-2.676 -1.756,-4.305 l 0.037,-6.505 c 0.006,-1.373 -0.522,-2.666 -1.491,-3.639 -0.967,-0.974 -2.257,-1.51 -3.631,-1.51 -0.104,0 -0.209,0.003 -0.315,0.009 -2.68,0.159 -4.791,2.497 -4.807,5.321 l -0.035,6.418 c -0.016,3.331 -2.74,6.043 -6.069,6.043 -0.913,0 -1.799,-0.205 -2.635,-0.607 l -21.571,-10.388 c -1.901,-0.915 -3.172,-2.714 -3.401,-4.811 -0.228,-2.096 0.625,-4.127 2.283,-5.431 l 5.314,-4.178 c 2.172,-1.706 2.743,-4.763 1.302,-6.957 -0.956,-1.456 -2.563,-2.326 -4.296,-2.326 -1.155,0 -2.248,0.379 -3.159,1.096 l -5.504,4.327 c -1.083,0.851 -2.376,1.301 -3.738,1.301 -2.859,0 -5.298,-1.942 -5.933,-4.723 l -5.324,-23.326 c -0.413,-1.813 0.012,-3.684 1.169,-5.133 1.162,-1.456 2.886,-2.292 4.732,-2.292 0.406,0 0.817,0.041 1.22,0.123 l 6.814,1.376 c 0.338,0.068 0.681,0.103 1.021,0.103 2.469,0 4.584,-1.767 5.029,-4.203 0.5,-2.725 -1.407,-5.41 -4.25,-5.985 l -5.746,-1.16 c -2.091,-0.422 -3.773,-1.869 -4.503,-3.873 -0.729,-2.003 -0.372,-4.195 0.958,-5.863 l 14.555,-18.251 c 1.158,-1.454 2.886,-2.286 4.737,-2.286 2.395,0 4.508,1.346 5.515,3.513 l 2.433,5.24 c 0.838,1.801 2.662,2.964 4.649,2.964 0.745,0 1.471,-0.161 2.154,-0.478 2.561,-1.19 3.676,-4.241 2.486,-6.802 l -6.769,-14.569 c -1.623,-3.495 -5.162,-5.753 -9.017,-5.753 l -0.112,10e-4 c -3.008,0.033 -5.8,1.397 -7.67,3.742 l -32.291,40.491 c -0.977,1.226 -1.336,2.805 -0.987,4.332 l 13.212,57.886 c 0.347,1.528 1.358,2.794 2.769,3.473 l 53.494,25.761 c 0.69,0.332 1.458,0.507 2.222,0.507 0.765,0 1.532,-0.175 2.223,-0.507 l 53.493,-25.761 c 1.412,-0.679 2.422,-1.945 2.769,-3.473 L 0.989,4.333 C 1.338,2.806 0.978,1.227 0,0 m -73.747,10.642 c -3.348,1.669 -5.381,5.581 -4.094,9.776 0.752,2.452 2.706,4.401 5.158,5.148 4.218,1.287 8.144,-0.781 9.793,-4.162 l 21.139,-30.996 c 0.501,-0.733 -0.386,-1.616 -1.117,-1.112 l -30.613,21.081 c -0.11,0.073 -0.195,0.165 -0.266,0.265 M 15.402,8.019 2.336,65.264 C 0.93,71.429 -3.145,76.538 -8.841,79.281 l -52.905,25.478 c -2.779,1.338 -5.879,2.046 -8.963,2.046 -3.084,0 -6.183,-0.708 -8.963,-2.046 l -52.903,-25.478 c -5.697,-2.743 -9.773,-7.852 -11.178,-14.015 L -156.819,8.021 c -1.408,-6.165 0.046,-12.535 3.988,-17.48 l 31.935,-40.045 c 4.782,-5.996 11.922,-9.486 19.592,-9.573 h 0.296 60.761 c 7.768,0.012 15,3.646 19.842,9.719 l 31.819,39.9 c 3.942,4.944 5.396,11.314 3.988,17.477"
|
|
59
|
+
style="fill:#231f20;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
|
60
|
+
id="path58" />
|
|
61
|
+
</g>
|
|
62
|
+
</g>
|
|
63
|
+
</svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?><svg id="Layer_2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 124.1 137.72"><defs><style>.cls-1{fill:#2d0075;}.cls-1,.cls-2{stroke-width:0px;}.cls-2{fill:#9d6ce5;}</style></defs><g id="Logos"><path class="cls-1" d="m32.19,112.13l11.59-14.99c-4.37-2.04-8.37-4.89-11.98-8.56-8.16-8.27-12.24-18.53-12.24-30.77s4.08-22.5,12.24-30.77c3.61-3.66,7.59-6.5,11.95-8.54l-11.35-14.68c-5.12,2.76-9.89,6.3-14.29,10.64C6.03,26.37,0,40.93,0,58.16s5.92,31.68,17.76,43.35c4.42,4.35,9.23,7.89,14.42,10.62Z"/><path class="cls-2" d="m115.34,89.35c5.84-9.58,8.75-20.2,8.75-31.88,0-17.23-5.89-31.68-17.68-43.35-6.61-6.54-14.13-11.25-22.55-14.13l-12.08,15.63c7.91,1.67,14.78,5.47,20.61,11.42,8.1,8.27,12.15,18.53,12.15,30.77s-4.05,22.5-12.15,30.77c-8.1,8.27-18.22,12.41-30.34,12.41-.12,0-.23,0-.34,0l28.39,36.73h22.78l-21.08-26.35c9.86-5.1,17.71-12.44,23.54-22.01Z"/></g></svg>
|
|
@@ -1,16 +1,14 @@
|
|
|
1
|
-
import type { LayerHeader, LayerRow } from '@crvouga/atlas/reports/evidence-types';
|
|
2
1
|
import type { CheckDetail, EvidenceHolder } from '@crvouga/atlas/reports/evidence-detail';
|
|
3
2
|
import { roleOfType } from '@crvouga/atlas/reports/evidence-detail';
|
|
3
|
+
import type { LayerHeader, LayerRow } from '@crvouga/atlas/reports/evidence-types';
|
|
4
4
|
import { contentTypeOf } from '@crvouga/atlas/reports/media-types';
|
|
5
5
|
import type { Annotation, Attachment, Attempt, Step } from '@crvouga/atlas/schema';
|
|
6
|
+
import { Accordion, Alert, Anchor, Box, Code, Flex, Image, List, Stack, Text, Title } from '@mantine/core';
|
|
6
7
|
import { useQuery } from '@tanstack/react-query';
|
|
7
8
|
import { useMemo, type ReactNode } from 'react';
|
|
8
|
-
|
|
9
9
|
import { reportAssetUrl, reportJson, reportText } from './api';
|
|
10
|
-
import styles from './artifacts.module.css';
|
|
11
10
|
import { duration, plural } from './format';
|
|
12
11
|
import { StatusMark } from './marks';
|
|
13
|
-
|
|
14
12
|
/**
|
|
15
13
|
* How one kind of attachment is shown. The first renderer that matches wins, so a new kind of artifact (a
|
|
16
14
|
* flame graph, a HAR, a coverage map) is one more entry, and an attachment nobody has a renderer for is still
|
|
@@ -20,14 +18,20 @@ export type ArtifactRenderer = {
|
|
|
20
18
|
readonly id: string;
|
|
21
19
|
readonly matches: (attachment: Attachment, type: string) => boolean;
|
|
22
20
|
/** `url` is where the bytes are, if they are anywhere a browser can reach; `path` is the report API path of a stored file. */
|
|
23
|
-
readonly render: (
|
|
21
|
+
readonly render: (
|
|
22
|
+
attachment: Attachment,
|
|
23
|
+
context: {
|
|
24
|
+
url: string | null;
|
|
25
|
+
path: string | null;
|
|
26
|
+
type: string;
|
|
27
|
+
}
|
|
28
|
+
) => ReactNode;
|
|
24
29
|
/** Wide renderers take a whole row of the gallery. */
|
|
25
30
|
readonly wide?: boolean;
|
|
26
31
|
};
|
|
27
|
-
|
|
28
|
-
|
|
32
|
+
const mediaType = (attachment: Attachment) =>
|
|
33
|
+
(attachment.contentType ?? contentTypeOf(attachment.name)).split(';')[0]!.trim().toLowerCase();
|
|
29
34
|
const label = (attachment: Attachment) => attachment.description ?? attachment.name;
|
|
30
|
-
|
|
31
35
|
/** Only addresses a browser may follow: never `javascript:` or `data:` from a producer. */
|
|
32
36
|
function safeUri(uri: string | undefined): string | null {
|
|
33
37
|
if (!uri) return null;
|
|
@@ -38,21 +42,34 @@ function safeUri(uri: string | undefined): string | null {
|
|
|
38
42
|
return null;
|
|
39
43
|
}
|
|
40
44
|
}
|
|
41
|
-
|
|
42
45
|
function TextValue({ attachment, path }: { attachment: Attachment; path: string | null }) {
|
|
43
|
-
const stored = useQuery({
|
|
46
|
+
const stored = useQuery({
|
|
47
|
+
queryKey: ['artifact-text', path ?? ''],
|
|
48
|
+
queryFn: ({ signal }) => reportText(path!, signal),
|
|
49
|
+
enabled: attachment.text === undefined && path !== null,
|
|
50
|
+
staleTime: Number.POSITIVE_INFINITY,
|
|
51
|
+
retry: false
|
|
52
|
+
});
|
|
44
53
|
const raw = attachment.text ?? stored.data;
|
|
45
|
-
if (raw === undefined)
|
|
46
|
-
|
|
54
|
+
if (raw === undefined)
|
|
55
|
+
return (
|
|
56
|
+
<Text component="div" c="dimmed">
|
|
57
|
+
{stored.isError ? 'Could not be read.' : 'Loading…'}
|
|
58
|
+
</Text>
|
|
59
|
+
);
|
|
60
|
+
const shown = raw.length > 200000 ? raw.slice(0, 200000) : raw;
|
|
47
61
|
const pretty = /json/.test(mediaType(attachment)) ? tryPretty(shown) : shown;
|
|
48
62
|
return (
|
|
49
63
|
<>
|
|
50
|
-
<
|
|
51
|
-
{shown.length < raw.length &&
|
|
64
|
+
<Code block>{pretty}</Code>
|
|
65
|
+
{shown.length < raw.length && (
|
|
66
|
+
<Text component="div" c="dimmed">
|
|
67
|
+
Showing the first 200 000 characters.
|
|
68
|
+
</Text>
|
|
69
|
+
)}
|
|
52
70
|
</>
|
|
53
71
|
);
|
|
54
72
|
}
|
|
55
|
-
|
|
56
73
|
function tryPretty(text: string) {
|
|
57
74
|
try {
|
|
58
75
|
return JSON.stringify(JSON.parse(text), null, 2);
|
|
@@ -60,64 +77,131 @@ function tryPretty(text: string) {
|
|
|
60
77
|
return text;
|
|
61
78
|
}
|
|
62
79
|
}
|
|
63
|
-
|
|
64
80
|
/** In order: the first that matches. Add to the front with {@link registerArtifactRenderer}. */
|
|
65
81
|
export const artifactRenderers: ArtifactRenderer[] = [
|
|
66
|
-
{
|
|
82
|
+
{
|
|
83
|
+
id: 'image',
|
|
84
|
+
matches: (_, type) => type.startsWith('image/') && type !== 'image/svg+xml',
|
|
85
|
+
render: (a, { url }) =>
|
|
86
|
+
url ? (
|
|
87
|
+
<Anchor href={url} target="_blank" rel="noreferrer">
|
|
88
|
+
<Image src={url} alt={label(a)} loading="lazy" width={a.width} height={a.height} fit="contain" maw="100%" />
|
|
89
|
+
</Anchor>
|
|
90
|
+
) : null
|
|
91
|
+
},
|
|
67
92
|
// SVG can carry script: shown as a picture only, never inlined.
|
|
68
|
-
{
|
|
69
|
-
|
|
70
|
-
|
|
93
|
+
{
|
|
94
|
+
id: 'svg',
|
|
95
|
+
matches: (_, type) => type === 'image/svg+xml',
|
|
96
|
+
render: (a, { url }) => (url ? <Image src={url} alt={label(a)} loading="lazy" fit="contain" maw="100%" /> : null)
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
id: 'video',
|
|
100
|
+
wide: true,
|
|
101
|
+
matches: (_, type) => type.startsWith('video/'),
|
|
102
|
+
render: (a, { url }) =>
|
|
103
|
+
url ? <Box src={url} controls preload="metadata" aria-label={label(a)} component="video" maw="100%" w="100%" /> : null
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
id: 'audio',
|
|
107
|
+
matches: (_, type) => type.startsWith('audio/'),
|
|
108
|
+
render: (a, { url }) => (url ? <audio src={url} controls preload="none" aria-label={label(a)} /> : null)
|
|
109
|
+
},
|
|
71
110
|
// A page snapshot runs nothing: the frame has no permissions and the file is served sandboxed.
|
|
72
|
-
{
|
|
73
|
-
|
|
74
|
-
|
|
111
|
+
{
|
|
112
|
+
id: 'snapshot',
|
|
113
|
+
wide: true,
|
|
114
|
+
matches: (_, type) => type === 'text/html' || type === 'application/xhtml+xml',
|
|
115
|
+
render: (a, { url }) =>
|
|
116
|
+
url ? <Box component="iframe" w="100%" h="32rem" bd="0" sandbox="" src={url} title={label(a)} loading="lazy" /> : null
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
id: 'pdf',
|
|
120
|
+
wide: true,
|
|
121
|
+
matches: (_, type) => type === 'application/pdf',
|
|
122
|
+
render: (a, { url }) =>
|
|
123
|
+
url ? <Box component="iframe" w="100%" h="32rem" bd="0" sandbox="" src={url} title={label(a)} loading="lazy" /> : null
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
id: 'text',
|
|
127
|
+
wide: true,
|
|
128
|
+
matches: (a, type) => a.text !== undefined || type.startsWith('text/') || /(json|xml|yaml|x-ndjson|x-diff)/.test(type),
|
|
129
|
+
render: (a, { path }) => <TextValue attachment={a} path={path} />
|
|
130
|
+
}
|
|
75
131
|
];
|
|
76
|
-
|
|
77
132
|
export function registerArtifactRenderer(renderer: ArtifactRenderer) {
|
|
78
133
|
artifactRenderers.unshift(renderer);
|
|
79
134
|
}
|
|
80
|
-
|
|
81
135
|
function sizeOf(bytes: number | undefined) {
|
|
82
136
|
if (bytes === undefined) return '';
|
|
83
137
|
if (bytes < 1024) return `${bytes} B`;
|
|
84
138
|
return bytes < 1024 * 1024 ? `${(bytes / 1024).toFixed(0)} KiB` : `${(bytes / 1024 / 1024).toFixed(1)} MiB`;
|
|
85
139
|
}
|
|
86
|
-
|
|
87
140
|
function Artifact({ attachment, layer }: { attachment: Attachment; layer: string }) {
|
|
88
141
|
const type = mediaType(attachment);
|
|
89
|
-
const path = attachment.bundleKey
|
|
142
|
+
const path = attachment.bundleKey
|
|
143
|
+
? `/layers/${encodeURIComponent(layer)}/blobs/${attachment.bundleKey.split('/').map(encodeURIComponent).join('/')}`
|
|
144
|
+
: null;
|
|
90
145
|
const url = path ? reportAssetUrl(path) : safeUri(attachment.uri);
|
|
91
146
|
const renderer = artifactRenderers.find((candidate) => candidate.matches(attachment, type));
|
|
92
147
|
const body = renderer?.render(attachment, { url, path, type });
|
|
93
148
|
return (
|
|
94
|
-
<
|
|
149
|
+
<List.Item data-wide={renderer?.wide || undefined} data-role={attachment.role ?? roleOfType(type)}>
|
|
95
150
|
{body}
|
|
96
|
-
<figcaption>
|
|
97
|
-
<
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
{
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
151
|
+
<Box component="figcaption">
|
|
152
|
+
<Text span inherit fw={600}>
|
|
153
|
+
{attachment.name}
|
|
154
|
+
</Text>
|
|
155
|
+
{attachment.role && (
|
|
156
|
+
<Text span inherit>
|
|
157
|
+
{attachment.role}
|
|
158
|
+
</Text>
|
|
159
|
+
)}
|
|
160
|
+
<Text span inherit>
|
|
161
|
+
{[type, sizeOf(attachment.bytes), attachment.durationMs ? duration(attachment.durationMs) : ''].filter(Boolean).join(' · ')}
|
|
162
|
+
</Text>
|
|
163
|
+
{url && (
|
|
164
|
+
<Anchor href={url} download={attachment.name} target="_blank" rel="noreferrer">
|
|
165
|
+
{body ? 'Download' : 'Open'}
|
|
166
|
+
</Anchor>
|
|
167
|
+
)}
|
|
168
|
+
{!url && attachment.text === undefined && (
|
|
169
|
+
<Text span inherit>
|
|
170
|
+
No file to show
|
|
171
|
+
</Text>
|
|
172
|
+
)}
|
|
173
|
+
</Box>
|
|
174
|
+
</List.Item>
|
|
104
175
|
);
|
|
105
176
|
}
|
|
106
|
-
|
|
107
177
|
export function Attachments({ attachments, layer }: { attachments: readonly Attachment[]; layer: string }) {
|
|
108
178
|
if (!attachments.length) return null;
|
|
109
179
|
return (
|
|
110
|
-
<
|
|
111
|
-
<
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
180
|
+
<Box aria-label="Attachments" component="section" mb="lg">
|
|
181
|
+
<Title order={4} mb="sm">
|
|
182
|
+
{plural(attachments.length, 'attachment', 'attachments')}
|
|
183
|
+
</Title>
|
|
184
|
+
<List spacing="xs" listStyleType="none">
|
|
185
|
+
{attachments.map((attachment, index) => (
|
|
186
|
+
<Artifact key={`${attachment.id ?? attachment.name}:${index}`} attachment={attachment} layer={layer} />
|
|
187
|
+
))}
|
|
188
|
+
</List>
|
|
189
|
+
</Box>
|
|
116
190
|
);
|
|
117
191
|
}
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
192
|
+
const STEP_STATUS: Record<string, 'passed' | 'failed' | 'running' | 'not-run'> = {
|
|
193
|
+
passed: 'passed',
|
|
194
|
+
pass: 'passed',
|
|
195
|
+
ok: 'passed',
|
|
196
|
+
failed: 'failed',
|
|
197
|
+
fail: 'failed',
|
|
198
|
+
error: 'failed',
|
|
199
|
+
running: 'running',
|
|
200
|
+
skipped: 'not-run',
|
|
201
|
+
'not-run': 'not-run',
|
|
202
|
+
'not-reached': 'not-run',
|
|
203
|
+
pending: 'not-run'
|
|
204
|
+
};
|
|
121
205
|
/** The timeline: ordered by when each step started, nested by `parentId`. A step whose parent is missing is shown at the top. */
|
|
122
206
|
export function Timeline({ steps, layer }: { steps: readonly Step[]; layer: string }) {
|
|
123
207
|
const tree = useMemo(() => {
|
|
@@ -131,105 +215,157 @@ export function Timeline({ steps, layer }: { steps: readonly Step[]; layer: stri
|
|
|
131
215
|
return children;
|
|
132
216
|
}, [steps]);
|
|
133
217
|
const render = (parent: string | null): ReactNode => (
|
|
134
|
-
<
|
|
218
|
+
<List spacing="xs" listStyleType="none" type="ordered">
|
|
135
219
|
{(tree.get(parent) ?? []).map((step, index) => {
|
|
136
220
|
const status = STEP_STATUS[(step.status ?? '').toLowerCase()];
|
|
137
221
|
return (
|
|
138
|
-
<
|
|
139
|
-
<
|
|
222
|
+
<List.Item data-evidence-step key={`${step.id ?? step.name}:${index}`} data-status={status ?? step.status ?? 'none'}>
|
|
223
|
+
<Flex gap="xs" align="center" wrap="wrap">
|
|
140
224
|
<StatusMark status={status ?? 'none'} size={14} />
|
|
141
|
-
<span
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
225
|
+
<Text span inherit>
|
|
226
|
+
{step.name}
|
|
227
|
+
</Text>
|
|
228
|
+
{step.kind && (
|
|
229
|
+
<Text span inherit>
|
|
230
|
+
{step.kind}
|
|
231
|
+
</Text>
|
|
232
|
+
)}
|
|
233
|
+
{step.status && !status && (
|
|
234
|
+
<Text span inherit>
|
|
235
|
+
{step.status}
|
|
236
|
+
</Text>
|
|
237
|
+
)}
|
|
238
|
+
<Box flex={1} />
|
|
239
|
+
<Text span inherit c="dimmed">
|
|
240
|
+
{[step.offsetMs !== undefined ? `+${duration(step.offsetMs)}` : '', duration(step.durationMs)].filter(Boolean).join(' · ')}
|
|
241
|
+
</Text>
|
|
242
|
+
</Flex>
|
|
243
|
+
{step.detail && <Text component="div">{step.detail}</Text>}
|
|
148
244
|
{step.annotations && <Notes notes={step.annotations} />}
|
|
149
245
|
{step.attachments && <Attachments attachments={step.attachments} layer={layer} />}
|
|
150
246
|
{step.id && tree.has(step.id) && render(step.id)}
|
|
151
|
-
</
|
|
247
|
+
</List.Item>
|
|
152
248
|
);
|
|
153
249
|
})}
|
|
154
|
-
</
|
|
250
|
+
</List>
|
|
155
251
|
);
|
|
156
252
|
return (
|
|
157
|
-
<
|
|
158
|
-
<
|
|
253
|
+
<Box aria-label="Timeline" component="section" mb="lg">
|
|
254
|
+
<Title order={4} mb="sm">
|
|
255
|
+
{plural(steps.length, 'step', 'steps')}
|
|
256
|
+
</Title>
|
|
159
257
|
{render(null)}
|
|
160
|
-
</
|
|
258
|
+
</Box>
|
|
161
259
|
);
|
|
162
260
|
}
|
|
163
|
-
|
|
164
261
|
export function Notes({ notes }: { notes: readonly Annotation[] }) {
|
|
165
262
|
if (!notes.length) return null;
|
|
166
263
|
return (
|
|
167
|
-
<
|
|
264
|
+
<List aria-label="Annotations" spacing="xs" listStyleType="none">
|
|
168
265
|
{notes.map((note, index) => (
|
|
169
|
-
<
|
|
170
|
-
<
|
|
171
|
-
|
|
266
|
+
<Alert key={index} color={'blue'} my="sm">
|
|
267
|
+
<Text data-level={note.level ?? 'info'} span inherit>
|
|
268
|
+
{note.level && ['info', 'warning', 'error'].includes(note.level) ? note.level : note.type}
|
|
269
|
+
</Text>
|
|
270
|
+
<Text span inherit>
|
|
172
271
|
{note.message}
|
|
173
|
-
{note.source?.file &&
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
272
|
+
{note.source?.file && (
|
|
273
|
+
<Text span inherit c="dimmed">
|
|
274
|
+
{' '}
|
|
275
|
+
{note.source.file}
|
|
276
|
+
{note.source.line ? `:${note.source.line}` : ''}
|
|
277
|
+
</Text>
|
|
278
|
+
)}
|
|
279
|
+
{note.level && !['info', 'warning', 'error'].includes(note.level) && (
|
|
280
|
+
<Text span inherit c="dimmed">
|
|
281
|
+
{' '}
|
|
282
|
+
({note.level})
|
|
283
|
+
</Text>
|
|
284
|
+
)}
|
|
285
|
+
</Text>
|
|
286
|
+
</Alert>
|
|
177
287
|
))}
|
|
178
|
-
</
|
|
288
|
+
</List>
|
|
179
289
|
);
|
|
180
290
|
}
|
|
181
|
-
|
|
182
291
|
function Tries({ attempts, layer }: { attempts: readonly Attempt[]; layer: string }) {
|
|
183
292
|
if (!attempts.length) return null;
|
|
184
293
|
return (
|
|
185
|
-
<
|
|
186
|
-
<
|
|
187
|
-
|
|
294
|
+
<Box aria-label="Tries" component="section" mb="lg">
|
|
295
|
+
<Title order={4} mb="sm">
|
|
296
|
+
{plural(attempts.length, 'try', 'tries')}
|
|
297
|
+
</Title>
|
|
298
|
+
<List spacing="xs" listStyleType="none" type="ordered">
|
|
188
299
|
{attempts.map((attempt) => (
|
|
189
|
-
<
|
|
190
|
-
<
|
|
300
|
+
<List.Item key={attempt.index}>
|
|
301
|
+
<Flex gap="xs" align="center" wrap="wrap">
|
|
191
302
|
<StatusMark status={attempt.status} size={14} />
|
|
192
|
-
<span
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
303
|
+
<Text span inherit>
|
|
304
|
+
Try {attempt.index + 1}
|
|
305
|
+
</Text>
|
|
306
|
+
<Box flex={1} />
|
|
307
|
+
<Text span inherit c="dimmed">
|
|
308
|
+
{duration(attempt.durationMs)}
|
|
309
|
+
</Text>
|
|
310
|
+
</Flex>
|
|
311
|
+
{attempt.detail && <Text component="div">{attempt.detail}</Text>}
|
|
197
312
|
{attempt.attachments && <Attachments attachments={attempt.attachments} layer={layer} />}
|
|
198
|
-
</
|
|
313
|
+
</List.Item>
|
|
199
314
|
))}
|
|
200
|
-
</
|
|
201
|
-
</
|
|
315
|
+
</List>
|
|
316
|
+
</Box>
|
|
202
317
|
);
|
|
203
318
|
}
|
|
204
|
-
|
|
205
319
|
/** What is not known: kept, and shown as it is, so nothing a tool recorded is out of reach. */
|
|
206
320
|
function Raw({ extensions }: { extensions: Readonly<Record<string, unknown>> }) {
|
|
207
321
|
const names = Object.keys(extensions);
|
|
208
322
|
if (!names.length) return null;
|
|
209
323
|
return (
|
|
210
|
-
<
|
|
211
|
-
<
|
|
212
|
-
|
|
213
|
-
|
|
324
|
+
<Accordion variant="separated" my="sm">
|
|
325
|
+
<Accordion.Item value="content">
|
|
326
|
+
<Accordion.Control>
|
|
327
|
+
{plural(names.length, 'extension', 'extensions')}: {names.join(', ')}
|
|
328
|
+
</Accordion.Control>
|
|
329
|
+
<Accordion.Panel>
|
|
330
|
+
<Code block>{JSON.stringify(extensions, null, 2)}</Code>
|
|
331
|
+
</Accordion.Panel>
|
|
332
|
+
</Accordion.Item>
|
|
333
|
+
</Accordion>
|
|
214
334
|
);
|
|
215
335
|
}
|
|
216
|
-
|
|
217
336
|
function Facts({ holder }: { holder: EvidenceHolder }) {
|
|
218
337
|
const labels = Object.entries(holder.labels ?? {});
|
|
219
338
|
const tags = holder.tags ?? [];
|
|
220
|
-
const links = (holder.links ?? []).flatMap((link) => {
|
|
339
|
+
const links = (holder.links ?? []).flatMap((link) => {
|
|
340
|
+
const url = safeUri(link.url);
|
|
341
|
+
return url ? [{ ...link, url }] : [];
|
|
342
|
+
});
|
|
221
343
|
if (!labels.length && !tags.length && !links.length) return null;
|
|
222
344
|
return (
|
|
223
|
-
<
|
|
224
|
-
<
|
|
225
|
-
{tags.map((tag) =>
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
345
|
+
<Stack gap="sm">
|
|
346
|
+
<List aria-label="Facts" spacing="xs" listStyleType="none">
|
|
347
|
+
{tags.map((tag) => (
|
|
348
|
+
<List.Item key={`t:${tag}`}>{tag}</List.Item>
|
|
349
|
+
))}
|
|
350
|
+
{labels.map(([name, value]) => (
|
|
351
|
+
<List.Item key={`l:${name}`}>
|
|
352
|
+
{name}
|
|
353
|
+
<Text span inherit fw={600}>
|
|
354
|
+
{value}
|
|
355
|
+
</Text>
|
|
356
|
+
</List.Item>
|
|
357
|
+
))}
|
|
358
|
+
{links.map((link) => (
|
|
359
|
+
<List.Item key={`k:${link.url}`}>
|
|
360
|
+
<Anchor href={link.url} target="_blank" rel="noreferrer">
|
|
361
|
+
{link.name ?? link.rel ?? link.url}
|
|
362
|
+
</Anchor>
|
|
363
|
+
</List.Item>
|
|
364
|
+
))}
|
|
365
|
+
</List>
|
|
366
|
+
</Stack>
|
|
230
367
|
);
|
|
231
368
|
}
|
|
232
|
-
|
|
233
369
|
function Evidence({ holder, layer, steps }: { holder: EvidenceHolder; layer: string; steps?: boolean }) {
|
|
234
370
|
return (
|
|
235
371
|
<>
|
|
@@ -242,31 +378,48 @@ function Evidence({ holder, layer, steps }: { holder: EvidenceHolder; layer: str
|
|
|
242
378
|
</>
|
|
243
379
|
);
|
|
244
380
|
}
|
|
245
|
-
|
|
246
381
|
/** Everything one result carries beyond its outcome, read when it is opened, and what the run around it carried. */
|
|
247
382
|
export function ResultEvidence({ layer, row }: { layer: LayerHeader; row: LayerRow }) {
|
|
248
383
|
const wanted = row.evidence !== undefined || layer.evidence !== undefined;
|
|
249
384
|
const detail = useQuery({
|
|
250
385
|
queryKey: ['evidence-detail', layer.backend, layer.id, row.kind, row.id],
|
|
251
|
-
queryFn: ({ signal }) =>
|
|
386
|
+
queryFn: ({ signal }) =>
|
|
387
|
+
reportJson<CheckDetail>(
|
|
388
|
+
`/evidence/detail/${encodeURIComponent(layer.backend)}/${encodeURIComponent(layer.id)}?check=${encodeURIComponent(row.id)}&kind=${encodeURIComponent(row.kind)}`,
|
|
389
|
+
signal
|
|
390
|
+
),
|
|
252
391
|
enabled: wanted && /^[0-9a-f]{64}$/.test(layer.id),
|
|
253
392
|
staleTime: Number.POSITIVE_INFINITY,
|
|
254
393
|
retry: false
|
|
255
394
|
});
|
|
256
395
|
if (!wanted) return null;
|
|
257
|
-
if (detail.isLoading)
|
|
258
|
-
|
|
396
|
+
if (detail.isLoading)
|
|
397
|
+
return (
|
|
398
|
+
<Text role="status" component="div" c="dimmed">
|
|
399
|
+
Loading what this result carries…
|
|
400
|
+
</Text>
|
|
401
|
+
);
|
|
402
|
+
if (detail.isError || !detail.data)
|
|
403
|
+
return (
|
|
404
|
+
<Text role="alert" component="div" c="dimmed">
|
|
405
|
+
What this result carries could not be read.
|
|
406
|
+
</Text>
|
|
407
|
+
);
|
|
259
408
|
const { check, run } = detail.data;
|
|
260
|
-
const hasRun = Object.values(run).some((value) =>
|
|
409
|
+
const hasRun = Object.values(run).some((value) =>
|
|
410
|
+
Array.isArray(value) ? value.length > 0 : value && typeof value === 'object' ? Object.keys(value).length > 0 : false
|
|
411
|
+
);
|
|
261
412
|
return (
|
|
262
|
-
<
|
|
413
|
+
<Stack aria-label="Evidence" gap="sm" miw={0}>
|
|
263
414
|
<Evidence holder={check} layer={layer.id} steps />
|
|
264
415
|
{hasRun && (
|
|
265
|
-
<
|
|
266
|
-
<
|
|
416
|
+
<Box aria-label="From the run" component="section" mb="lg">
|
|
417
|
+
<Title order={4} mb="sm">
|
|
418
|
+
From the run
|
|
419
|
+
</Title>
|
|
267
420
|
<Evidence holder={run} layer={layer.id} />
|
|
268
|
-
</
|
|
421
|
+
</Box>
|
|
269
422
|
)}
|
|
270
|
-
</
|
|
423
|
+
</Stack>
|
|
271
424
|
);
|
|
272
425
|
}
|