fix(webapp): associate model administration labels (#4694)
## Summary Associate internal model administration labels with their form controls. The model editor, creator, and tester now use explicit `htmlFor` and `id` pairs. Section titles that do not label controls now use headings instead of label elements. Base: [#4693](https://github.com/triggerdotdev/trigger.dev/pull/4693)
This commit is contained in:
@@ -230,8 +230,11 @@ export default function AdminLlmModelDetailRoute() {
|
||||
<div className="space-y-4">
|
||||
{/* Model fields */}
|
||||
<div className="space-y-2">
|
||||
<label className="text-xs font-medium text-text-dimmed">Model Name</label>
|
||||
<label htmlFor="modelName" className="text-xs font-medium text-text-dimmed">
|
||||
Model Name
|
||||
</label>
|
||||
<Input
|
||||
id="modelName"
|
||||
name="modelName"
|
||||
value={modelName}
|
||||
onChange={(e) => setModelName(e.target.value)}
|
||||
@@ -241,8 +244,11 @@ export default function AdminLlmModelDetailRoute() {
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<label className="text-xs font-medium text-text-dimmed">Match Pattern (regex)</label>
|
||||
<label htmlFor="matchPattern" className="text-xs font-medium text-text-dimmed">
|
||||
Match Pattern (regex)
|
||||
</label>
|
||||
<Input
|
||||
id="matchPattern"
|
||||
name="matchPattern"
|
||||
value={matchPattern}
|
||||
onChange={(e) => setMatchPattern(e.target.value)}
|
||||
@@ -254,9 +260,12 @@ export default function AdminLlmModelDetailRoute() {
|
||||
|
||||
{/* Test pattern */}
|
||||
<div className="space-y-2">
|
||||
<label className="text-xs font-medium text-text-dimmed">Test pattern match</label>
|
||||
<label htmlFor="testPattern" className="text-xs font-medium text-text-dimmed">
|
||||
Test pattern match
|
||||
</label>
|
||||
<div className="flex items-center gap-2">
|
||||
<Input
|
||||
id="testPattern"
|
||||
value={testInput}
|
||||
onChange={(e) => setTestInput(e.target.value)}
|
||||
placeholder="Type a model name to test..."
|
||||
@@ -277,12 +286,15 @@ export default function AdminLlmModelDetailRoute() {
|
||||
|
||||
{/* Catalog metadata */}
|
||||
<div className="space-y-2 border-t border-grid-dimmed pt-4">
|
||||
<label className="text-sm font-medium text-text-bright">Catalog Metadata</label>
|
||||
<h3 className="text-sm font-medium text-text-bright">Catalog Metadata</h3>
|
||||
|
||||
<div className="grid grid-cols-2 gap-3">
|
||||
<div className="space-y-1">
|
||||
<label className="text-xs font-medium text-text-dimmed">Provider</label>
|
||||
<label htmlFor="provider" className="text-xs font-medium text-text-dimmed">
|
||||
Provider
|
||||
</label>
|
||||
<Input
|
||||
id="provider"
|
||||
name="provider"
|
||||
value={provider}
|
||||
onChange={(e) => setProvider(e.target.value)}
|
||||
@@ -292,8 +304,11 @@ export default function AdminLlmModelDetailRoute() {
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
<label className="text-xs font-medium text-text-dimmed">Context Window</label>
|
||||
<label htmlFor="contextWindow" className="text-xs font-medium text-text-dimmed">
|
||||
Context Window
|
||||
</label>
|
||||
<Input
|
||||
id="contextWindow"
|
||||
name="contextWindow"
|
||||
value={contextWindow}
|
||||
onChange={(e) => setContextWindow(e.target.value)}
|
||||
@@ -305,8 +320,11 @@ export default function AdminLlmModelDetailRoute() {
|
||||
</div>
|
||||
|
||||
<div className="space-y-1">
|
||||
<label className="text-xs font-medium text-text-dimmed">Description</label>
|
||||
<label htmlFor="description" className="text-xs font-medium text-text-dimmed">
|
||||
Description
|
||||
</label>
|
||||
<Input
|
||||
id="description"
|
||||
name="description"
|
||||
value={description}
|
||||
onChange={(e) => setDescription(e.target.value)}
|
||||
@@ -318,8 +336,11 @@ export default function AdminLlmModelDetailRoute() {
|
||||
|
||||
<div className="grid grid-cols-2 gap-3">
|
||||
<div className="space-y-1">
|
||||
<label className="text-xs font-medium text-text-dimmed">Max Output Tokens</label>
|
||||
<label htmlFor="maxOutputTokens" className="text-xs font-medium text-text-dimmed">
|
||||
Max Output Tokens
|
||||
</label>
|
||||
<Input
|
||||
id="maxOutputTokens"
|
||||
name="maxOutputTokens"
|
||||
value={maxOutputTokens}
|
||||
onChange={(e) => setMaxOutputTokens(e.target.value)}
|
||||
@@ -329,10 +350,11 @@ export default function AdminLlmModelDetailRoute() {
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
<label className="text-xs font-medium text-text-dimmed">
|
||||
<label htmlFor="capabilities" className="text-xs font-medium text-text-dimmed">
|
||||
Features (comma-separated)
|
||||
</label>
|
||||
<Input
|
||||
id="capabilities"
|
||||
name="capabilities"
|
||||
value={capabilities}
|
||||
onChange={(e) => setCapabilities(e.target.value)}
|
||||
@@ -344,8 +366,11 @@ export default function AdminLlmModelDetailRoute() {
|
||||
</div>
|
||||
|
||||
<div className="space-y-1">
|
||||
<label className="text-xs font-medium text-text-dimmed">Pricing Unit</label>
|
||||
<label htmlFor="pricingUnit" className="text-xs font-medium text-text-dimmed">
|
||||
Pricing Unit
|
||||
</label>
|
||||
<select
|
||||
id="pricingUnit"
|
||||
name="pricingUnit"
|
||||
value={pricingUnit}
|
||||
onChange={(e) => setPricingUnit(e.target.value)}
|
||||
@@ -374,7 +399,7 @@ export default function AdminLlmModelDetailRoute() {
|
||||
{/* Pricing tiers */}
|
||||
<div className="space-y-3">
|
||||
<div className="flex items-center justify-between">
|
||||
<label className="text-sm font-medium text-text-bright">Pricing Tiers</label>
|
||||
<h3 className="text-sm font-medium text-text-bright">Pricing Tiers</h3>
|
||||
<Button
|
||||
type="button"
|
||||
variant="tertiary/small"
|
||||
|
||||
@@ -223,12 +223,13 @@ export default function AdminLlmModelsRoute() {
|
||||
|
||||
{/* Model tester */}
|
||||
<div className="rounded-md border border-grid-dimmed bg-background-bright p-3 space-y-2">
|
||||
<label className="text-xs font-medium text-text-dimmed">
|
||||
<label htmlFor="modelString" className="text-xs font-medium text-text-dimmed">
|
||||
Test model string — paste a model name to see which pricing model matches
|
||||
</label>
|
||||
<testFetcher.Form method="post" className="flex items-center gap-2">
|
||||
<input type="hidden" name="_action" value="test" />
|
||||
<Input
|
||||
id="modelString"
|
||||
name="modelString"
|
||||
placeholder="e.g. anthropic/claude-haiku-4-5-20251001, gpt-4o-mini, mistral/mistral-large-3"
|
||||
variant="medium"
|
||||
|
||||
@@ -178,8 +178,11 @@ export default function AdminLlmModelNewRoute() {
|
||||
|
||||
<div className="space-y-4">
|
||||
<div className="space-y-2">
|
||||
<label className="text-xs font-medium text-text-dimmed">Model Name</label>
|
||||
<label htmlFor="modelName" className="text-xs font-medium text-text-dimmed">
|
||||
Model Name
|
||||
</label>
|
||||
<Input
|
||||
id="modelName"
|
||||
name="modelName"
|
||||
value={modelName}
|
||||
onChange={(e) => setModelName(e.target.value)}
|
||||
@@ -191,7 +194,7 @@ export default function AdminLlmModelNewRoute() {
|
||||
|
||||
<div className="space-y-2">
|
||||
<div className="flex items-center justify-between">
|
||||
<label className="text-xs font-medium text-text-dimmed">
|
||||
<label htmlFor="matchPattern" className="text-xs font-medium text-text-dimmed">
|
||||
Match Pattern (regex)
|
||||
</label>
|
||||
<button
|
||||
@@ -203,6 +206,7 @@ export default function AdminLlmModelNewRoute() {
|
||||
</button>
|
||||
</div>
|
||||
<Input
|
||||
id="matchPattern"
|
||||
name="matchPattern"
|
||||
value={matchPattern}
|
||||
onChange={(e) => setMatchPattern(e.target.value)}
|
||||
@@ -214,9 +218,12 @@ export default function AdminLlmModelNewRoute() {
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<label className="text-xs font-medium text-text-dimmed">Test pattern match</label>
|
||||
<label htmlFor="testPattern" className="text-xs font-medium text-text-dimmed">
|
||||
Test pattern match
|
||||
</label>
|
||||
<div className="flex items-center gap-2">
|
||||
<Input
|
||||
id="testPattern"
|
||||
value={testInput}
|
||||
onChange={(e) => setTestInput(e.target.value)}
|
||||
placeholder="Type a model name to test..."
|
||||
@@ -237,12 +244,15 @@ export default function AdminLlmModelNewRoute() {
|
||||
|
||||
{/* Catalog metadata */}
|
||||
<div className="space-y-2 border-t border-grid-dimmed pt-4">
|
||||
<label className="text-sm font-medium text-text-bright">Catalog Metadata</label>
|
||||
<h3 className="text-sm font-medium text-text-bright">Catalog Metadata</h3>
|
||||
|
||||
<div className="grid grid-cols-2 gap-3">
|
||||
<div className="space-y-1">
|
||||
<label className="text-xs font-medium text-text-dimmed">Provider</label>
|
||||
<label htmlFor="provider" className="text-xs font-medium text-text-dimmed">
|
||||
Provider
|
||||
</label>
|
||||
<Input
|
||||
id="provider"
|
||||
name="provider"
|
||||
value={provider}
|
||||
onChange={(e) => setProvider(e.target.value)}
|
||||
@@ -252,8 +262,11 @@ export default function AdminLlmModelNewRoute() {
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
<label className="text-xs font-medium text-text-dimmed">Context Window</label>
|
||||
<label htmlFor="contextWindow" className="text-xs font-medium text-text-dimmed">
|
||||
Context Window
|
||||
</label>
|
||||
<Input
|
||||
id="contextWindow"
|
||||
name="contextWindow"
|
||||
value={contextWindow}
|
||||
onChange={(e) => setContextWindow(e.target.value)}
|
||||
@@ -265,8 +278,11 @@ export default function AdminLlmModelNewRoute() {
|
||||
</div>
|
||||
|
||||
<div className="space-y-1">
|
||||
<label className="text-xs font-medium text-text-dimmed">Description</label>
|
||||
<label htmlFor="description" className="text-xs font-medium text-text-dimmed">
|
||||
Description
|
||||
</label>
|
||||
<Input
|
||||
id="description"
|
||||
name="description"
|
||||
value={description}
|
||||
onChange={(e) => setDescription(e.target.value)}
|
||||
@@ -278,8 +294,11 @@ export default function AdminLlmModelNewRoute() {
|
||||
|
||||
<div className="grid grid-cols-2 gap-3">
|
||||
<div className="space-y-1">
|
||||
<label className="text-xs font-medium text-text-dimmed">Max Output Tokens</label>
|
||||
<label htmlFor="maxOutputTokens" className="text-xs font-medium text-text-dimmed">
|
||||
Max Output Tokens
|
||||
</label>
|
||||
<Input
|
||||
id="maxOutputTokens"
|
||||
name="maxOutputTokens"
|
||||
value={maxOutputTokens}
|
||||
onChange={(e) => setMaxOutputTokens(e.target.value)}
|
||||
@@ -289,10 +308,11 @@ export default function AdminLlmModelNewRoute() {
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
<label className="text-xs font-medium text-text-dimmed">
|
||||
<label htmlFor="capabilities" className="text-xs font-medium text-text-dimmed">
|
||||
Features (comma-separated)
|
||||
</label>
|
||||
<Input
|
||||
id="capabilities"
|
||||
name="capabilities"
|
||||
value={capabilities}
|
||||
onChange={(e) => setCapabilities(e.target.value)}
|
||||
@@ -304,8 +324,11 @@ export default function AdminLlmModelNewRoute() {
|
||||
</div>
|
||||
|
||||
<div className="space-y-1">
|
||||
<label className="text-xs font-medium text-text-dimmed">Pricing Unit</label>
|
||||
<label htmlFor="pricingUnit" className="text-xs font-medium text-text-dimmed">
|
||||
Pricing Unit
|
||||
</label>
|
||||
<select
|
||||
id="pricingUnit"
|
||||
name="pricingUnit"
|
||||
value={pricingUnit}
|
||||
onChange={(e) => setPricingUnit(e.target.value)}
|
||||
@@ -334,7 +357,7 @@ export default function AdminLlmModelNewRoute() {
|
||||
{/* Pricing tiers */}
|
||||
<div className="space-y-3">
|
||||
<div className="flex items-center justify-between">
|
||||
<label className="text-sm font-medium text-text-bright">Pricing Tiers</label>
|
||||
<h3 className="text-sm font-medium text-text-bright">Pricing Tiers</h3>
|
||||
<Button
|
||||
type="button"
|
||||
variant="tertiary/small"
|
||||
|
||||
Reference in New Issue
Block a user