@crvouga/atlas 1.18.0 → 1.19.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 +8 -1
- package/dist/reports/src/evidence-detail.js +13 -3
- package/dist/reports/src/evidence-types.d.ts +4 -0
- package/dist/schema/src/api.d.ts +50 -0
- package/dist/schema/src/api.js +2 -0
- package/docs/reference/reports.md +4 -0
- package/docs/rich-evidence.md +1 -0
- package/docs/ui.md +40 -1
- package/llms-full.txt +41 -1
- package/package.json +1 -1
- package/packages/schema/schemas/effective-delta.schema.json +18 -0
- package/packages/schema/schemas/effective-evidence.schema.json +18 -0
- package/packages/schema/schemas/evidence-page.schema.json +9 -0
- package/packages/schema/schemas/layer-rows.schema.json +9 -0
- package/packages/schema/schemas/report-run.schema.json +9 -0
- package/packages/schema/schemas/review-collection.schema.json +9 -0
- package/packages/schema/schemas/review-manifest.schema.json +9 -0
- package/packages/schema/schemas/test-catalog.schema.json +9 -0
- package/packages/schema/schemas/test-history.schema.json +18 -0
- package/packages/server/openapi.json +126 -0
- package/packages/visualizer/src/app/AppShell.tsx +2 -2
- package/packages/visualizer/src/app/router.tsx +25 -1
- package/packages/visualizer/src/components/Header.tsx +15 -4
- package/packages/visualizer/src/evidence/behavior-index.test.ts +119 -0
- package/packages/visualizer/src/evidence/behavior-index.ts +162 -0
- package/packages/visualizer/src/evidence/behavior-panel.tsx +36 -22
- package/packages/visualizer/src/evidence/behavior-return.test.ts +41 -0
- package/packages/visualizer/src/evidence/behavior-return.ts +59 -0
- package/packages/visualizer/src/evidence/behavior.ts +32 -1
- package/packages/visualizer/src/evidence/behaviors-page.tsx +465 -0
- package/packages/visualizer/src/evidence/feature-page.tsx +5 -26
- package/packages/visualizer/src/evidence/scoped-summary-view.tsx +110 -0
- package/packages/visualizer/src/evidence/scoped-summary.test.ts +62 -0
- package/packages/visualizer/src/evidence/scoped-summary.ts +118 -0
- package/packages/visualizer/src/evidence/spec-texts.ts +88 -0
- package/packages/visualizer/src/explorer/ArtifactsView.tsx +4 -4
- package/packages/visualizer/src/explorer/Explorer.tsx +1 -1
- package/packages/visualizer/src/explorer/RunsView.tsx +4 -4
- package/packages/visualizer/src/explorer/collections.tsx +5 -5
- package/packages/visualizer/src/explorer/navigate.ts +17 -0
- package/packages/visualizer/src/explorer/playlist-entries.test.ts +10 -1
- package/packages/visualizer/src/explorer/playlist-entries.ts +10 -0
- package/packages/visualizer/src/explorer/playlist.tsx +43 -8
- package/packages/visualizer/src/explorer/search.ts +7 -1
- package/packages/visualizer/src/find/Finder.tsx +1 -62
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
import { Badge, Button, Group, Kbd, List, Modal, Stack, Text } from '@mantine/core';
|
|
2
2
|
import { Spotlight, useSpotlight } from '@mantine/spotlight';
|
|
3
|
-
import { useQueryClient } from '@tanstack/react-query';
|
|
4
3
|
import { useNavigate, useSearch } from '@tanstack/react-router';
|
|
5
4
|
import { useEffect, useLayoutEffect, useMemo, useRef, useState, type KeyboardEvent as ReactKeyboardEvent } from 'react';
|
|
6
5
|
import { useAtlas } from '../app/atlas-context';
|
|
7
6
|
import { useTestCatalog } from '../explorer/catalog';
|
|
8
7
|
import { SearchNotes } from '../explorer/search-notes';
|
|
9
|
-
import { keys, specKey, useAdapter } from '../data/queries';
|
|
10
8
|
import { useEvidence } from '../evidence/evidence-context';
|
|
11
9
|
import { plural } from '../evidence/format';
|
|
10
|
+
import { useSpecTexts } from '../evidence/spec-texts';
|
|
12
11
|
import { StatusMark } from '../evidence/marks';
|
|
13
12
|
import { kindOfFile } from '../spec-kind';
|
|
14
13
|
import { describeHit } from './behaviors';
|
|
@@ -51,66 +50,6 @@ function isTypingTarget(target: EventTarget | null) {
|
|
|
51
50
|
const tag = target.tagName;
|
|
52
51
|
return target.isContentEditable || tag === 'INPUT' || tag === 'TEXTAREA' || tag === 'SELECT' || tag === 'BUTTON' || tag === 'A';
|
|
53
52
|
}
|
|
54
|
-
/**
|
|
55
|
-
* Reads the text of every spec for search, a few at a time, once `enabled`. Each file lands as it arrives, so a search
|
|
56
|
-
* can use what is read so far; `read` of `total` say how far it is, and `failed` how many could not be read at all.
|
|
57
|
-
*/
|
|
58
|
-
function useSpecTexts(files: readonly string[], enabled: boolean, open: boolean) {
|
|
59
|
-
const adapter = useAdapter();
|
|
60
|
-
const client = useQueryClient();
|
|
61
|
-
const source = specKey(adapter);
|
|
62
|
-
const cache = useRef(new Map<string, string>());
|
|
63
|
-
const unreadable = useRef(new Set<string>());
|
|
64
|
-
const [texts, setTexts] = useState<ReadonlyMap<string, string>>(() => new Map());
|
|
65
|
-
const [pending, setPending] = useState(false);
|
|
66
|
-
const [failedFiles, setFailedFiles] = useState<ReadonlySet<string>>(() => new Set());
|
|
67
|
-
const key = files.join('\n');
|
|
68
|
-
// Opening the finder is another chance for the files that could not be read.
|
|
69
|
-
useEffect(() => {
|
|
70
|
-
if (!open || unreadable.current.size === 0) return;
|
|
71
|
-
for (const file of unreadable.current) cache.current.delete(file);
|
|
72
|
-
unreadable.current.clear();
|
|
73
|
-
setFailedFiles(new Set());
|
|
74
|
-
}, [open]);
|
|
75
|
-
useEffect(() => {
|
|
76
|
-
if (!enabled) return;
|
|
77
|
-
const wanted = key.length === 0 ? [] : key.split('\n');
|
|
78
|
-
let cancelled = false;
|
|
79
|
-
const missing = wanted.filter((file) => !cache.current.has(file));
|
|
80
|
-
if (missing.length === 0) {
|
|
81
|
-
setPending(false);
|
|
82
|
-
return;
|
|
83
|
-
}
|
|
84
|
-
setPending(true);
|
|
85
|
-
let cursor = 0;
|
|
86
|
-
const pull = async () => {
|
|
87
|
-
for (;;) {
|
|
88
|
-
const file = missing[cursor++];
|
|
89
|
-
if (file === undefined || cancelled) return;
|
|
90
|
-
let text = '';
|
|
91
|
-
try {
|
|
92
|
-
text = await client.fetchQuery({ queryKey: keys.specFile(source, file), queryFn: () => adapter.specFile(file), retry: false });
|
|
93
|
-
} catch {
|
|
94
|
-
text = '';
|
|
95
|
-
unreadable.current.add(file);
|
|
96
|
-
}
|
|
97
|
-
if (cancelled) return;
|
|
98
|
-
cache.current.set(file, text);
|
|
99
|
-
setTexts(new Map(cache.current));
|
|
100
|
-
if (unreadable.current.has(file)) setFailedFiles(new Set(unreadable.current));
|
|
101
|
-
}
|
|
102
|
-
};
|
|
103
|
-
void Promise.all([pull(), pull(), pull(), pull()]).then(() => {
|
|
104
|
-
if (!cancelled) setPending(false);
|
|
105
|
-
});
|
|
106
|
-
return () => {
|
|
107
|
-
cancelled = true;
|
|
108
|
-
};
|
|
109
|
-
}, [adapter, client, enabled, key, source]);
|
|
110
|
-
const read = useMemo(() => files.filter((file) => texts.has(file)).length, [files, texts]);
|
|
111
|
-
const failed = useMemo(() => files.filter((file) => failedFiles.has(file)).length, [files, failedFiles]);
|
|
112
|
-
return { texts, pending, total: files.length, read, failed };
|
|
113
|
-
}
|
|
114
53
|
export function Finder() {
|
|
115
54
|
const open = useFinderOpen();
|
|
116
55
|
const help = useHelpOpen();
|