From 87403c94078af7e84eee984f93504db8bc60af63 Mon Sep 17 00:00:00 2001 From: Nico <47644445+nicotsx@users.noreply.github.com> Date: Thu, 8 Jan 2026 18:53:02 +0100 Subject: [PATCH] chore: add more linting rules and fix warnings (#325) --- .oxlintrc.json | 5 +++-- app/client/components/file-tree.tsx | 17 +++++++++++++---- app/client/components/snapshots-table.tsx | 2 +- app/client/components/ui/alert.tsx | 4 ++-- app/client/components/ui/breadcrumb.tsx | 9 +++++---- .../auth/routes/download-recovery-key.tsx | 1 - app/client/modules/auth/routes/login.tsx | 2 +- app/client/modules/auth/routes/onboarding.tsx | 2 +- .../backups/components/create-schedule-form.tsx | 2 +- .../backups/components/schedule-summary.tsx | 2 +- app/client/modules/settings/routes/settings.tsx | 1 - 11 files changed, 28 insertions(+), 19 deletions(-) diff --git a/.oxlintrc.json b/.oxlintrc.json index 634c4b7c..0caeb87a 100644 --- a/.oxlintrc.json +++ b/.oxlintrc.json @@ -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": { diff --git a/app/client/components/file-tree.tsx b/app/client/components/file-tree.tsx index fa9559c2..22d0a5c4 100644 --- a/app/client/components/file-tree.tsx +++ b/app/client/components/file-tree.tsx @@ -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 -
{icon}
{children}
-
+ ); }); diff --git a/app/client/components/snapshots-table.tsx b/app/client/components/snapshots-table.tsx index 2e3b7f79..9ff31b8f 100644 --- a/app/client/components/snapshots-table.tsx +++ b/app/client/components/snapshots-table.tsx @@ -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} /> diff --git a/app/client/components/ui/alert.tsx b/app/client/components/ui/alert.tsx index 1014ae72..229491a7 100644 --- a/app/client/components/ui/alert.tsx +++ b/app/client/components/ui/alert.tsx @@ -27,9 +27,9 @@ const Alert = React.forwardRef< )); Alert.displayName = "Alert"; -const AlertTitle = React.forwardRef>( +const AlertTitle = React.forwardRef>( ({ className, ...props }, ref) => ( -
+
{props.children}
), ); AlertTitle.displayName = "AlertTitle"; diff --git a/app/client/components/ui/breadcrumb.tsx b/app/client/components/ui/breadcrumb.tsx index e1fb0843..f838da10 100644 --- a/app/client/components/ui/breadcrumb.tsx +++ b/app/client/components/ui/breadcrumb.tsx @@ -43,16 +43,17 @@ function BreadcrumbLink({ ); } -function BreadcrumbPage({ className, ...props }: React.ComponentProps<"span">) { +function BreadcrumbPage({ className, children, ...props }: React.ComponentProps<"a">) { return ( - + > + {children} + ); } diff --git a/app/client/modules/auth/routes/download-recovery-key.tsx b/app/client/modules/auth/routes/download-recovery-key.tsx index af29dd05..da20ce32 100644 --- a/app/client/modules/auth/routes/download-recovery-key.tsx +++ b/app/client/modules/auth/routes/download-recovery-key.tsx @@ -88,7 +88,6 @@ export default function DownloadRecoveryKeyPage() { onChange={(e) => setPassword(e.target.value)} placeholder="Enter your password" required - autoFocus disabled={downloadResticPassword.isPending} />

Enter your account password to download the recovery key

diff --git a/app/client/modules/auth/routes/login.tsx b/app/client/modules/auth/routes/login.tsx index f342ccd5..fb089eb6 100644 --- a/app/client/modules/auth/routes/login.tsx +++ b/app/client/modules/auth/routes/login.tsx @@ -84,7 +84,7 @@ export default function LoginPage() { Username - + diff --git a/app/client/modules/auth/routes/onboarding.tsx b/app/client/modules/auth/routes/onboarding.tsx index f9e3f490..6290b598 100644 --- a/app/client/modules/auth/routes/onboarding.tsx +++ b/app/client/modules/auth/routes/onboarding.tsx @@ -115,7 +115,7 @@ export default function OnboardingPage() { Username - + Choose a username for the admin account diff --git a/app/client/modules/backups/components/create-schedule-form.tsx b/app/client/modules/backups/components/create-schedule-form.tsx index 8e2a088b..577fb064 100644 --- a/app/client/modules/backups/components/create-schedule-form.tsx +++ b/app/client/modules/backups/components/create-schedule-form.tsx @@ -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} > diff --git a/app/client/modules/backups/components/schedule-summary.tsx b/app/client/modules/backups/components/schedule-summary.tsx index 2036ccfa..16f1df03 100644 --- a/app/client/modules/backups/components/schedule-summary.tsx +++ b/app/client/modules/backups/components/schedule-summary.tsx @@ -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); diff --git a/app/client/modules/settings/routes/settings.tsx b/app/client/modules/settings/routes/settings.tsx index a1a75225..70a2fe8a 100644 --- a/app/client/modules/settings/routes/settings.tsx +++ b/app/client/modules/settings/routes/settings.tsx @@ -244,7 +244,6 @@ export default function Settings({ loaderData }: Route.ComponentProps) { onChange={(e) => setDownloadPassword(e.target.value)} placeholder="Enter your password" required - autoFocus />