diff --git a/frontend/packages/swarm-ui/src/pages/ComponentsPage.tsx b/frontend/packages/swarm-ui/src/pages/ComponentsPage.tsx index 3f02ef59..c5024a27 100644 --- a/frontend/packages/swarm-ui/src/pages/ComponentsPage.tsx +++ b/frontend/packages/swarm-ui/src/pages/ComponentsPage.tsx @@ -41,6 +41,7 @@ import { ExpandableCardListSkeleton, } from "../ui/expandable-card/ExpandableCard.js"; import { ExternalLink } from "../ui/external-link/ExternalLink.js"; +import { FieldGrid, FieldGridFull } from "../ui/field-grid/FieldGrid.js"; import { FormStack } from "../ui/form-stack/FormStack.js"; import { Hint, type HintTone } from "../ui/hint/Hint.js"; import { FormResult } from "../ui/submit/FormResult.js"; @@ -649,6 +650,39 @@ export function ComponentsPage() { +
+ + + {}} + /> + {}} + /> + {}} + /> + + {}} + /> + + + +
+
e.preventDefault()}> diff --git a/frontend/packages/swarm-ui/src/pages/review-settings/ClassifierSettings.css b/frontend/packages/swarm-ui/src/pages/review-settings/ClassifierSettings.css index 17f43a36..1d373ce1 100644 --- a/frontend/packages/swarm-ui/src/pages/review-settings/ClassifierSettings.css +++ b/frontend/packages/swarm-ui/src/pages/review-settings/ClassifierSettings.css @@ -1,23 +1,11 @@ -/* The settings form: the fields wrap in a row, the provider fields on a row of - * their own under the ACP runtime, then the save action. */ +/* The settings form: the fields sit on a `FieldGrid`, the provider fields in a + * group of their own under the ACP runtime, then the save action. */ .ui-classifier-settings { display: flex; flex-direction: column; gap: 1em; margin-top: 1em; } -/* One grid for every group of fields: each field has the same width and the - same edges at any width, and a label that wraps cannot push one input lower - than its neighbour's. */ -.ui-classifier-settings-fields { - display: grid; - grid-template-columns: repeat(auto-fill, minmax(14em, 1fr)); - gap: 0.75em; -} -/* A field that needs the whole row (a URL, a model name). */ -.ui-classifier-settings-wide { - grid-column: 1 / -1; -} /* The provider fields, under their own heading. */ .ui-classifier-settings-group { display: flex; diff --git a/frontend/packages/swarm-ui/src/pages/review-settings/ClassifierSettings.tsx b/frontend/packages/swarm-ui/src/pages/review-settings/ClassifierSettings.tsx index cc26bb8f..3ce8bd6a 100644 --- a/frontend/packages/swarm-ui/src/pages/review-settings/ClassifierSettings.tsx +++ b/frontend/packages/swarm-ui/src/pages/review-settings/ClassifierSettings.tsx @@ -11,6 +11,7 @@ import { ApiErrorPanel } from "@hive/shared/api-error-panel.js"; import { readApiError, type ProblemDetails } from "@hive/shared/api-error.js"; import { ActionRow } from "../../ui/action-row/ActionRow.js"; import { Button } from "../../ui/button/Button.js"; +import { FieldGrid, FieldGridFull } from "../../ui/field-grid/FieldGrid.js"; import { Hint } from "../../ui/hint/Hint.js"; import { Disclosure } from "../../ui/disclosure/Disclosure.js"; import { SelectField } from "../../ui/select-field/SelectField.js"; @@ -143,7 +144,7 @@ export function ClassifierSettings() { ) : null} {draft ? (
void save(e)}> -
+ edit({ ...draft, max })} /> -
+ {draft.runtime === "acp" ? (
provider -
-
+ + edit({ ...draft, acpUrl })} /> -
-
+ + edit({ ...draft, acpModel })} /> -
+ -
+

Prices are in USD per million tokens.

diff --git a/frontend/packages/swarm-ui/src/pages/review-tryout/ClassificationEditor.tsx b/frontend/packages/swarm-ui/src/pages/review-tryout/ClassificationEditor.tsx index 63a4d63d..f28b6fd8 100644 --- a/frontend/packages/swarm-ui/src/pages/review-tryout/ClassificationEditor.tsx +++ b/frontend/packages/swarm-ui/src/pages/review-tryout/ClassificationEditor.tsx @@ -2,6 +2,7 @@ // description (the prompt the model answers), which answer passes, and how // certain the model has to be for its answer to count. import { Button } from "../../ui/button/Button.js"; +import { FieldGrid } from "../../ui/field-grid/FieldGrid.js"; import { SelectField } from "../../ui/select-field/SelectField.js"; import { TextAreaField } from "../../ui/text-area-field/TextAreaField.js"; import { TextField } from "../../ui/text-field/TextField.js"; @@ -41,7 +42,7 @@ export function ClassificationEditor({ placeholder="what to look for in the PR, e.g. does it add a naive datetime?" onInput={(description) => onChange({ ...draft, description })} /> -
+ onChange({ ...draft, threshold })} /> {onRemove ? : null} -
+ ); } diff --git a/frontend/packages/swarm-ui/src/pages/review-tryout/ReviewTryOut.css b/frontend/packages/swarm-ui/src/pages/review-tryout/ReviewTryOut.css index 33c11710..87917308 100644 --- a/frontend/packages/swarm-ui/src/pages/review-tryout/ReviewTryOut.css +++ b/frontend/packages/swarm-ui/src/pages/review-tryout/ReviewTryOut.css @@ -12,17 +12,10 @@ gap: 1em; margin-top: 1em; } -.ui-tryout-target { - display: flex; - flex-wrap: wrap; - gap: 0.75em; -} -.ui-tryout-target > * { - flex: 1 1 14em; -} +/* The button sits at the foot of its cell, beside the inputs. */ .ui-tryout-target > button { - flex: none; - align-self: flex-end; + align-self: end; + justify-self: start; } .ui-tryout-loaded { margin: 0; @@ -37,16 +30,10 @@ border-radius: 0.5em; } .ui-tryout-classification-row { - display: flex; - flex-wrap: wrap; - align-items: flex-end; - gap: 0.75em; -} -.ui-tryout-classification-row > * { - flex: 1 1 12em; + align-items: end; } .ui-tryout-classification-row > button { - flex: none; + justify-self: start; } .ui-tryout-hint { margin: 0; diff --git a/frontend/packages/swarm-ui/src/pages/review-tryout/ReviewTryOut.tsx b/frontend/packages/swarm-ui/src/pages/review-tryout/ReviewTryOut.tsx index e7093a56..1178cf19 100644 --- a/frontend/packages/swarm-ui/src/pages/review-tryout/ReviewTryOut.tsx +++ b/frontend/packages/swarm-ui/src/pages/review-tryout/ReviewTryOut.tsx @@ -27,6 +27,7 @@ import { ApiErrorPanel } from "@hive/shared/api-error-panel.js"; import { readApiError, type ProblemDetails } from "@hive/shared/api-error.js"; import { ActionRow } from "../../ui/action-row/ActionRow.js"; import { Button } from "../../ui/button/Button.js"; +import { FieldGrid } from "../../ui/field-grid/FieldGrid.js"; import { ConfirmDialog } from "../../ui/confirm-dialog/ConfirmDialog.js"; import { Disclosure } from "../../ui/disclosure/Disclosure.js"; import { ExternalLink } from "../../ui/external-link/ExternalLink.js"; @@ -332,7 +333,7 @@ export function ReviewTryOut() { the repo's rules.

void run(e)}> -
+ {loadingRules ? "loading…" : "load the repo's rules"} -
+ {repoChoicesError ? ( .ui-form-field { - width: auto; - flex: 1 1 9em; -} .ui-schedule-form-hint { font-size: 0.85em; } diff --git a/frontend/packages/swarm-ui/src/pages/schedules/ScheduleForm.tsx b/frontend/packages/swarm-ui/src/pages/schedules/ScheduleForm.tsx index 15f1ff12..67275e97 100644 --- a/frontend/packages/swarm-ui/src/pages/schedules/ScheduleForm.tsx +++ b/frontend/packages/swarm-ui/src/pages/schedules/ScheduleForm.tsx @@ -13,6 +13,7 @@ import { ApiErrorPanel } from "@hive/shared/api-error-panel.js"; import { readApiError, type ProblemDetails } from "@hive/shared/api-error.js"; import { ActionRow } from "../../ui/action-row/ActionRow.js"; import { Button } from "../../ui/button/Button.js"; +import { FieldGrid } from "../../ui/field-grid/FieldGrid.js"; import { Card } from "../../ui/card/Card.js"; import { Hint } from "../../ui/hint/Hint.js"; import { @@ -212,7 +213,7 @@ export function ScheduleForm({ required onInput={setBody} /> -
+ -
+ {fires.length > 0 ? ( {repeat ? "next fires: " : "fires: "} diff --git a/frontend/packages/swarm-ui/src/ui/field-grid/FieldGrid.css b/frontend/packages/swarm-ui/src/ui/field-grid/FieldGrid.css new file mode 100644 index 00000000..5573feab --- /dev/null +++ b/frontend/packages/swarm-ui/src/ui/field-grid/FieldGrid.css @@ -0,0 +1,8 @@ +.ui-field-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(var(--ui-field-min), 1fr)); + gap: 0.75em; +} +.ui-field-grid-full { + grid-column: 1 / -1; +} diff --git a/frontend/packages/swarm-ui/src/ui/field-grid/FieldGrid.tsx b/frontend/packages/swarm-ui/src/ui/field-grid/FieldGrid.tsx new file mode 100644 index 00000000..3dbeb816 --- /dev/null +++ b/frontend/packages/swarm-ui/src/ui/field-grid/FieldGrid.tsx @@ -0,0 +1,30 @@ +// — a row or block of form fields on one grid: every field is the +// same width and the columns have the same edges in every row, so a field's +// width depends on the container and not on the siblings it wraps with. The +// columns are as many as fit `min` wide; a lone last field keeps its column +// width instead of stretching across the form. One gap, the same in every form. +// A field that needs a whole row (a URL, a model name) goes in `FieldGridFull`. +import type { ComponentChildren } from "preact"; +import "./FieldGrid.css"; + +export function FieldGrid({ + min = "14em", + class: extraClass, + children, +}: { + /** The narrowest a column gets, any CSS length. */ + min?: string; + class?: string; + children: ComponentChildren; +}) { + const classes = ["ui-field-grid", extraClass].filter(Boolean).join(" "); + return ( +
+ {children} +
+ ); +} + +export function FieldGridFull({ children }: { children: ComponentChildren }) { + return
{children}
; +}