chore: add more linting rules and fix warnings (#325)

This commit is contained in:
Nico 2026-01-08 18:53:02 +01:00 committed by GitHub
parent 76741d6fb8
commit 87403c9407
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 28 additions and 19 deletions

View file

@ -1,6 +1,6 @@
{
"$schema": "./node_modules/oxlint/configuration_schema.json",
"plugins": ["unicorn", "typescript", "oxc"],
"plugins": ["eslint", "unicorn", "typescript", "oxc", "import", "react", "react-perf", "node", "jsx-a11y"],
"categories": {},
"rules": {
"constructor-super": "warn",
@ -112,7 +112,8 @@
"unicorn/no-useless-length-check": "warn",
"unicorn/no-useless-spread": "warn",
"unicorn/prefer-set-size": "warn",
"unicorn/prefer-string-starts-ends-with": "warn"
"unicorn/prefer-string-starts-ends-with": "warn",
"import/no-cycle": "error"
},
"settings": {
"jsx-a11y": {

View file

@ -489,18 +489,27 @@ interface ButtonProps {
const NodeButton = memo(({ depth, icon, onClick, onMouseEnter, className, children }: ButtonProps) => {
const paddingLeft = useMemo(() => `${8 + depth * NODE_PADDING_LEFT}px`, [depth]);
const handleKeyDown = useCallback(
(e: React.KeyboardEvent) => {
if (e.key === "Enter" || e.key === " ") {
e.preventDefault();
onClick?.();
}
},
[onClick],
);
return (
// biome-ignore lint/a11y/noStaticElementInteractions: we handle click and hover manually
// biome-ignore lint/a11y/useKeyWithClickEvents: we handle click and hover manually
<div
<button
className={cn("flex items-center gap-2 w-full pr-2 text-sm py-1.5 text-left", className)}
style={{ paddingLeft }}
onClick={onClick}
onMouseEnter={onMouseEnter}
onKeyDown={handleKeyDown}
>
{icon}
<div className="truncate w-full flex items-center gap-2">{children}</div>
</div>
</button>
);
});

View file

@ -158,7 +158,7 @@ export const SnapshotsTable = ({ snapshots, repositoryId, backups }: Props) => {
}
setSelectedIds(newSelected);
}}
aria-label={`Select snapshot ${snapshot.short_id}`}
aria-label={`Select snapshot ${snapshot.short_id}` as string}
/>
</TableCell>
<TableCell className="font-mono text-sm">

View file

@ -27,9 +27,9 @@ const Alert = React.forwardRef<
));
Alert.displayName = "Alert";
const AlertTitle = React.forwardRef<HTMLParagraphElement, React.HTMLAttributes<HTMLHeadingElement>>(
const AlertTitle = React.forwardRef<HTMLHeadingElement, React.HTMLAttributes<HTMLHeadingElement>>(
({ className, ...props }, ref) => (
<h5 ref={ref} className={cn("mb-1 font-medium leading-none tracking-tight", className)} {...props} />
<h5 ref={ref} className={cn("mb-1 font-medium leading-none tracking-tight", className)} {...props}>{props.children}</h5>
),
);
AlertTitle.displayName = "AlertTitle";

View file

@ -43,16 +43,17 @@ function BreadcrumbLink({
);
}
function BreadcrumbPage({ className, ...props }: React.ComponentProps<"span">) {
function BreadcrumbPage({ className, children, ...props }: React.ComponentProps<"a">) {
return (
<span
<a
data-slot="breadcrumb-page"
role="link"
aria-disabled="true"
aria-current="page"
className={cn("text-foreground font-normal truncate", className)}
{...props}
/>
>
{children}
</a>
);
}

View file

@ -88,7 +88,6 @@ export default function DownloadRecoveryKeyPage() {
onChange={(e) => setPassword(e.target.value)}
placeholder="Enter your password"
required
autoFocus
disabled={downloadResticPassword.isPending}
/>
<p className="text-xs text-muted-foreground">Enter your account password to download the recovery key</p>

View file

@ -84,7 +84,7 @@ export default function LoginPage() {
<FormItem>
<FormLabel>Username</FormLabel>
<FormControl>
<Input {...field} type="text" placeholder="admin" disabled={isLoggingIn} autoFocus />
<Input {...field} type="text" placeholder="admin" disabled={isLoggingIn} />
</FormControl>
<FormMessage />
</FormItem>

View file

@ -115,7 +115,7 @@ export default function OnboardingPage() {
<FormItem>
<FormLabel>Username</FormLabel>
<FormControl>
<Input {...field} type="text" placeholder="admin" disabled={submitting} autoFocus />
<Input {...field} type="text" placeholder="admin" disabled={submitting} />
</FormControl>
<FormDescription>Choose a username for the admin account</FormDescription>
<FormMessage />

View file

@ -393,7 +393,7 @@ export const CreateScheduleForm = ({ initialValues, formId, onSubmit, volume }:
type="button"
onClick={() => handleRemovePath(path)}
className="ml-1 hover:bg-destructive/20 rounded p-0.5 transition-colors"
aria-label={`Remove ${path}`}
aria-label={`Remove ${path}` as string}
>
<X className="h-3 w-3" />
</button>

View file

@ -65,7 +65,7 @@ export const ScheduleSummary = (props: Props) => {
repositoryLabel: schedule.repositoryId || "No repository selected",
retentionLabel: retentionParts.length > 0 ? retentionParts.join(" • ") : "No retention policy",
};
}, [schedule, schedule.volume.name]);
}, [schedule]);
const handleConfirmDelete = () => {
setShowDeleteConfirm(false);

View file

@ -244,7 +244,6 @@ export default function Settings({ loaderData }: Route.ComponentProps) {
onChange={(e) => setDownloadPassword(e.target.value)}
placeholder="Enter your password"
required
autoFocus
/>
</div>
</div>