Skip to content

Commit f74d479

Browse files
committed
fix(webapp): enforce associated form labels
1 parent ccd9727 commit f74d479

5 files changed

Lines changed: 56 additions & 19 deletions

File tree

.oxlintrc.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@
7878
"jsx-a11y/aria-role": "error",
7979
"jsx-a11y/click-events-have-key-events": "off",
8080
"jsx-a11y/control-has-associated-label": "off",
81-
"jsx-a11y/label-has-associated-control": "off",
81+
"jsx-a11y/label-has-associated-control": "error",
8282
"jsx-a11y/no-autofocus": "off",
8383
"jsx-a11y/no-noninteractive-element-interactions": "off",
8484
"jsx-a11y/no-static-element-interactions": "off",

apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.playground.$agentParam/route.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1034,9 +1034,9 @@ function PlaygroundSidebar({
10341034
{runFriendlyId && <SessionField label="Run ID" value={runFriendlyId} />}
10351035
<SessionField label="Messages" value={String(messageCount)} />
10361036
<div>
1037-
<label className="mb-0.5 block text-[10px] font-medium uppercase tracking-wider text-text-dimmed">
1037+
<span className="mb-0.5 block text-[10px] font-medium uppercase tracking-wider text-text-dimmed">
10381038
Status
1039-
</label>
1039+
</span>
10401040
<span className="flex items-center gap-1.5 text-xs">
10411041
<span
10421042
className={cn(
@@ -1353,9 +1353,9 @@ function safeParseJson(json: string): Record<string, unknown> {
13531353
function SessionField({ label, value }: { label: string; value: string }) {
13541354
return (
13551355
<div>
1356-
<label className="mb-0.5 block text-[10px] font-medium uppercase tracking-wider text-text-dimmed">
1356+
<span className="mb-0.5 block text-[10px] font-medium uppercase tracking-wider text-text-dimmed">
13571357
{label}
1358-
</label>
1358+
</span>
13591359
<code className="block truncate text-xs text-text-bright">{value}</code>
13601360
</div>
13611361
);

apps/webapp/app/routes/admin.data-stores.tsx

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useState } from "react";
1+
import { useId, useState } from "react";
22
import { useFetcher } from "@remix-run/react";
33
import type { ActionFunctionArgs, LoaderFunctionArgs } from "@remix-run/server-runtime";
44
import { redirect } from "@remix-run/server-runtime";
@@ -313,6 +313,7 @@ function DeleteButton({ name }: { name: string }) {
313313

314314
function EditButton({ name, organizationIds }: { name: string; organizationIds: string[] }) {
315315
const [open, setOpen] = useState(false);
316+
const fieldId = useId();
316317
const fetcher = useFetcher<{ success?: boolean; error?: string }>();
317318
const isSubmitting = fetcher.state !== "idle";
318319

@@ -336,8 +337,11 @@ function EditButton({ name, organizationIds }: { name: string; organizationIds:
336337
<input type="hidden" name="key" value={name} />
337338

338339
<div className="space-y-1.5">
339-
<label className="text-xs font-medium text-text-dimmed">Key</label>
340+
<label htmlFor={`${fieldId}-key`} className="text-xs font-medium text-text-dimmed">
341+
Key
342+
</label>
340343
<Input
344+
id={`${fieldId}-key`}
341345
name="_key_display"
342346
value={name}
343347
readOnly
@@ -347,10 +351,14 @@ function EditButton({ name, organizationIds }: { name: string; organizationIds:
347351
</div>
348352

349353
<div className="space-y-1.5">
350-
<label className="text-xs font-medium text-text-dimmed">
354+
<label
355+
htmlFor={`${fieldId}-organizationIds`}
356+
className="text-xs font-medium text-text-dimmed"
357+
>
351358
Organization IDs <span className="text-rose-400">*</span>
352359
</label>
353360
<Input
361+
id={`${fieldId}-organizationIds`}
354362
name="organizationIds"
355363
defaultValue={organizationIds.join(", ")}
356364
placeholder="clxxxxx, clyyyyy, clzzzzz"
@@ -394,6 +402,7 @@ function AddDataStoreDialog({
394402
onOpenChange: (open: boolean) => void;
395403
}) {
396404
const fetcher = useFetcher<{ success?: boolean; error?: string }>();
405+
const fieldId = useId();
397406
const isSubmitting = fetcher.state !== "idle";
398407

399408
// Close dialog on success
@@ -412,10 +421,11 @@ function AddDataStoreDialog({
412421
<input type="hidden" name="_action" value="add" />
413422

414423
<div className="space-y-1.5">
415-
<label className="text-xs font-medium text-text-dimmed">
424+
<label htmlFor={`${fieldId}-key`} className="text-xs font-medium text-text-dimmed">
416425
Key <span className="text-rose-400">*</span>
417426
</label>
418427
<Input
428+
id={`${fieldId}-key`}
419429
name="key"
420430
placeholder="e.g. hipaa-clickhouse-us-east"
421431
variant="medium"
@@ -428,10 +438,11 @@ function AddDataStoreDialog({
428438
</div>
429439

430440
<div className="space-y-1.5">
431-
<label className="text-xs font-medium text-text-dimmed">
441+
<label htmlFor={`${fieldId}-kind`} className="text-xs font-medium text-text-dimmed">
432442
Kind <span className="text-rose-400">*</span>
433443
</label>
434444
<Input
445+
id={`${fieldId}-kind`}
435446
name="kind"
436447
value="CLICKHOUSE"
437448
readOnly
@@ -441,10 +452,14 @@ function AddDataStoreDialog({
441452
</div>
442453

443454
<div className="space-y-1.5">
444-
<label className="text-xs font-medium text-text-dimmed">
455+
<label
456+
htmlFor={`${fieldId}-organizationIds`}
457+
className="text-xs font-medium text-text-dimmed"
458+
>
445459
Organization IDs <span className="text-rose-400">*</span>
446460
</label>
447461
<Input
462+
id={`${fieldId}-organizationIds`}
448463
name="organizationIds"
449464
placeholder="clxxxxx, clyyyyy, clzzzzz"
450465
variant="medium"
@@ -454,10 +469,14 @@ function AddDataStoreDialog({
454469
</div>
455470

456471
<div className="space-y-1.5">
457-
<label className="text-xs font-medium text-text-dimmed">
472+
<label
473+
htmlFor={`${fieldId}-connectionUrl`}
474+
className="text-xs font-medium text-text-dimmed"
475+
>
458476
ClickHouse connection URL <span className="text-rose-400">*</span>
459477
</label>
460478
<Input
479+
id={`${fieldId}-connectionUrl`}
461480
name="connectionUrl"
462481
type="password"
463482
placeholder="https://user:password@host:8443"

apps/webapp/app/routes/admin.notifications.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -434,8 +434,11 @@ export default function AdminNotificationsRoute() {
434434
<Paragraph className="text-text-dimmed">
435435
{total} notifications (page {page} of {pageCount || 1})
436436
</Paragraph>
437-
<label className="flex items-center gap-2 text-xs text-text-dimmed">
438-
<Checkbox checked={hideInactive} onChange={toggleHideInactive} />
437+
<label
438+
htmlFor="hideInactive"
439+
className="flex items-center gap-2 text-xs text-text-dimmed"
440+
>
441+
<Checkbox id="hideInactive" checked={hideInactive} onChange={toggleHideInactive} />
439442
Hide inactive
440443
</label>
441444
</div>

apps/webapp/app/routes/storybook.stepper/route.tsx

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,23 @@ export default function Story() {
1616
<Header2>InputNumberStepper</Header2>
1717
<Header3>Size: base (default)</Header3>
1818
<div className="flex flex-col gap-2">
19-
<label className="text-sm text-text-dimmed">Step: 75</label>
19+
<label htmlFor="stepper-1" className="text-sm text-text-dimmed">
20+
Step: 75
21+
</label>
2022
<InputNumberStepper
23+
id="stepper-1"
2124
value={value1}
2225
onChange={(e) => setValue1(e.target.value === "" ? "" : Number(e.target.value))}
2326
step={75}
2427
/>
2528
</div>
2629

2730
<div className="flex flex-col gap-2">
28-
<label className="text-sm text-text-dimmed">Step: 50, Min: 0, Max: 1000</label>
31+
<label htmlFor="stepper-2" className="text-sm text-text-dimmed">
32+
Step: 50, Min: 0, Max: 1000
33+
</label>
2934
<InputNumberStepper
35+
id="stepper-2"
3036
value={value2}
3137
onChange={(e) => setValue2(e.target.value === "" ? "" : Number(e.target.value))}
3238
step={50}
@@ -36,8 +42,11 @@ export default function Story() {
3642
</div>
3743

3844
<div className="flex flex-col gap-2">
39-
<label className="text-sm text-text-dimmed">Disabled state</label>
45+
<label htmlFor="stepper-3" className="text-sm text-text-dimmed">
46+
Disabled state
47+
</label>
4048
<InputNumberStepper
49+
id="stepper-3"
4150
value={value3}
4251
onChange={(e) => setValue3(e.target.value === "" ? "" : Number(e.target.value))}
4352
step={50}
@@ -49,8 +58,11 @@ export default function Story() {
4958
<div className="flex flex-col gap-2">
5059
<Header3>Size: large</Header3>
5160
<div className="flex flex-col gap-2">
52-
<label className="text-sm text-text-dimmed">Step: 50</label>
61+
<label htmlFor="stepper-4" className="text-sm text-text-dimmed">
62+
Step: 50
63+
</label>
5364
<InputNumberStepper
65+
id="stepper-4"
5466
value={value4}
5567
onChange={(e) => setValue4(e.target.value === "" ? "" : Number(e.target.value))}
5668
step={50}
@@ -59,8 +71,11 @@ export default function Story() {
5971
</div>
6072

6173
<div className="flex flex-col gap-2">
62-
<label className="text-sm text-text-dimmed">Step: 50, Disabled</label>
74+
<label htmlFor="stepper-5" className="text-sm text-text-dimmed">
75+
Step: 50, Disabled
76+
</label>
6377
<InputNumberStepper
78+
id="stepper-5"
6479
value={value5}
6580
onChange={(e) => setValue5(e.target.value === "" ? "" : Number(e.target.value))}
6681
step={50}

0 commit comments

Comments
 (0)