@@ -38,7 +38,7 @@ const initialDataset = generateFixtures(initialParsed.model, {
|
||||
invalidPercent: 0,
|
||||
});
|
||||
|
||||
type View = "model" | "data" | "violations";
|
||||
type View = "model" | "data" | "coverage" | "violations";
|
||||
const TYPES: FixtureType[] = [
|
||||
"string",
|
||||
"integer",
|
||||
@@ -334,6 +334,7 @@ export function Workbench() {
|
||||
const [rows, setRows] = useState(8);
|
||||
const [boundaryPercent, setBoundaryPercent] = useState(10);
|
||||
const [invalidPercent, setInvalidPercent] = useState(0);
|
||||
const [providerProfile, setProviderProfile] = useState("auto");
|
||||
const [selectedTable, setSelectedTable] = useState(model.tables[0]!.name);
|
||||
const [outputFormat, setOutputFormat] = useState<OutputFormat>("json");
|
||||
const [view, setView] = useState<View>("data");
|
||||
@@ -381,6 +382,7 @@ export function Workbench() {
|
||||
rows,
|
||||
boundaryPercent,
|
||||
invalidPercent,
|
||||
providerProfile,
|
||||
});
|
||||
setModel(validated);
|
||||
setDataset(next);
|
||||
@@ -584,6 +586,18 @@ export function Workbench() {
|
||||
}
|
||||
/>
|
||||
</label>
|
||||
<label>
|
||||
Deterministic provider profile
|
||||
<select
|
||||
value={providerProfile}
|
||||
onChange={(event) => setProviderProfile(event.target.value)}
|
||||
>
|
||||
<option value="auto">Auto by field name</option>
|
||||
<option value="person">People</option>
|
||||
<option value="network">Network</option>
|
||||
<option value="commerce">Commerce</option>
|
||||
</select>
|
||||
</label>
|
||||
<button className="primary-button" type="button" onClick={generate}>
|
||||
Generate fixtures
|
||||
</button>
|
||||
@@ -591,7 +605,7 @@ export function Workbench() {
|
||||
</section>
|
||||
|
||||
<nav className="tabs" aria-label="Fixture workspaces">
|
||||
{(["model", "data", "violations"] as View[]).map((name) => (
|
||||
{(["model", "data", "coverage", "violations"] as View[]).map((name) => (
|
||||
<button
|
||||
type="button"
|
||||
key={name}
|
||||
@@ -818,6 +832,53 @@ export function Workbench() {
|
||||
)}
|
||||
</section>
|
||||
) : null}
|
||||
|
||||
{view === "coverage" ? (
|
||||
<section className="panel">
|
||||
<div className="panel-heading">
|
||||
<div>
|
||||
<h2>Constraint coverage matrix</h2>
|
||||
<p>
|
||||
Generation order:{" "}
|
||||
{(dataset.generationOrder ?? []).join(" → ") || "not recorded"}.
|
||||
Counts distinguish valid, boundary and intentionally invalid
|
||||
evidence.
|
||||
</p>
|
||||
</div>
|
||||
<span className="count-pill">
|
||||
{dataset.coverage?.length ?? 0} rules
|
||||
</span>
|
||||
</div>
|
||||
<div className="table-scroll" tabIndex={0}>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Table</th>
|
||||
<th>Constraint</th>
|
||||
<th>Support</th>
|
||||
<th>Positive</th>
|
||||
<th>Boundary</th>
|
||||
<th>Negative</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{(dataset.coverage ?? []).map((entry, index) => (
|
||||
<tr key={`${entry.table}-${entry.constraint}-${index}`}>
|
||||
<td>{entry.table}</td>
|
||||
<td>
|
||||
<code>{entry.constraint}</code>
|
||||
</td>
|
||||
<td>{entry.support}</td>
|
||||
<td>{entry.positiveCases}</td>
|
||||
<td>{entry.boundaryCases}</td>
|
||||
<td>{entry.negativeCases}</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
) : null}
|
||||
</main>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user