swarm-ui: try-out rows keyed by position, distinct names, and accurate storage wording
Two classifications sharing a name made the result table's row key collide, so the form now refuses duplicate names and the table keys rows by position anyway. The page said it stores nothing in the browser, but the result table remembers its column filters like every table does; the header comment and the docs now say that. The row cap's comment says to keep it in step with the endpoint's own cap.
This commit is contained in:
parent
b67517e41b
commit
a4a4381cf6
4 changed files with 26 additions and 7 deletions
|
|
@ -64,8 +64,9 @@ and the head commit the run read. A failed run shows its error, for example when
|
|||
has no API key yet.
|
||||
|
||||
What you typed stays after a run, so you can edit the classification and run it
|
||||
again. The page saves nothing and posts nothing to the forge. It shows no token
|
||||
counts, cache counts or cost.
|
||||
again. The page saves no classification and no result, and posts nothing to the
|
||||
forge; like every table in the UI, the result table remembers its column
|
||||
filters in the browser. It shows no token counts, cache counts or cost.
|
||||
|
||||
### Scheduled prompts
|
||||
|
||||
|
|
|
|||
|
|
@ -7,8 +7,9 @@
|
|||
// `failed`. A run takes a minute or more, so the page says it is running.
|
||||
//
|
||||
// The inputs stay as typed after a run, so the operator can edit and run
|
||||
// again. The page stores nothing (not even in the browser) and posts nothing
|
||||
// to the forge.
|
||||
// again. The page keeps nothing you typed and no result, and posts nothing to
|
||||
// the forge; the only thing the browser remembers is the result table's
|
||||
// column filters, as for every table in the UI.
|
||||
import { useEffect, useState } from "preact/hooks";
|
||||
import { ApiErrorPanel } from "@hive/shared/api-error-panel.js";
|
||||
import { readApiError, type ProblemDetails } from "@hive/shared/api-error.js";
|
||||
|
|
@ -19,6 +20,7 @@ import { ClassificationEditor } from "./ClassificationEditor.js";
|
|||
import { TryOutResult } from "./TryOutResult.js";
|
||||
import {
|
||||
draftProblem,
|
||||
duplicateName,
|
||||
prNumber,
|
||||
repoProblem,
|
||||
toBody,
|
||||
|
|
@ -29,8 +31,9 @@ import "./ReviewTryOutPage.css";
|
|||
|
||||
const TRY_OUT = "/api/review-classifier/try-out";
|
||||
const POLL_MS = 2000;
|
||||
// More classifications than this are not offered a row; the backend has its
|
||||
// own cap and says so with a 400, which the page shows as it is.
|
||||
// More classifications than this are not offered a row. Keep it in step with
|
||||
// the try-out endpoint's own cap, which answers a longer list with a 400 that
|
||||
// the page shows as it is; the backend has no way to report it yet.
|
||||
const MAX_CLASSIFICATIONS = 10;
|
||||
|
||||
let nextKey = 0;
|
||||
|
|
@ -115,6 +118,7 @@ export function ReviewTryOutPage() {
|
|||
repoProblem(repo) ??
|
||||
(prNumber(pr) === null ? "a PR number is a whole number above 0" : null) ??
|
||||
drafts.map(draftProblem).find((p) => p !== null) ??
|
||||
duplicateName(drafts) ??
|
||||
null;
|
||||
|
||||
async function run(e: Event) {
|
||||
|
|
|
|||
|
|
@ -51,7 +51,9 @@ export function TryOutResult({ result }: { result: Result }) {
|
|||
<Table
|
||||
columns={COLUMNS}
|
||||
rows={rows}
|
||||
rowKey={(r) => r.name}
|
||||
// By position: two classifications may share a name, and a shared key
|
||||
// would let one result render over the other.
|
||||
rowKey={(r) => String(rows.indexOf(r))}
|
||||
storageKey="swarm-ui:review-tryout:table-filters"
|
||||
emptyMessage="the run returned no classifications"
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -81,6 +81,18 @@ export function draftProblem(d: ClassificationDraft): string | null {
|
|||
return null;
|
||||
}
|
||||
|
||||
/** A name two classifications share, as a problem, or null: the result table
|
||||
* names its rows by it, so a shared name leaves two rows nobody can tell apart. */
|
||||
export function duplicateName(drafts: ClassificationDraft[]): string | null {
|
||||
const seen = new Set<string>();
|
||||
for (const d of drafts) {
|
||||
const name = d.name.trim();
|
||||
if (seen.has(name)) return `two classifications are named ${name}`;
|
||||
seen.add(name);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export function toBody(d: ClassificationDraft): ClassificationBody {
|
||||
return {
|
||||
name: d.name.trim(),
|
||||
|
|
|
|||
Loading…
Reference in a new issue