fix(lint): clear remaining biome errors (unused code, optional chains, non-null assertions, effect deps)

This commit is contained in:
SnapOtter
2026-06-21 01:49:48 +08:00
parent 7561f2a8c3
commit 19dc6ba554
20 changed files with 17 additions and 26 deletions
+1 -1
View File
@@ -326,7 +326,7 @@ export async function authRoutes(app: FastifyInstance): Promise<void> {
const audit = auditFromRequest(request); const audit = auditFromRequest(request);
if (!user || !user.passwordHash) { if (!user?.passwordHash) {
authAttempts.inc({ method: "password", result: "failure" }); authAttempts.inc({ method: "password", result: "failure" });
await audit("LOGIN_FAILED", { await audit("LOGIN_FAILED", {
username: sanitizeAuditInput(body.username), username: sanitizeAuditInput(body.username),
+1 -1
View File
@@ -108,7 +108,7 @@ export async function registerSaml(app: FastifyInstance): Promise<void> {
return redirectToLogin(reply, "saml_auth_failed"); return redirectToLogin(reply, "saml_auth_failed");
} }
if (!profile || !profile.nameID) { if (!profile?.nameID) {
request.log.warn("SAML callback: no profile or nameID in assertion"); request.log.warn("SAML callback: no profile or nameID in assertion");
authAttempts.inc({ method: "saml", result: "failure" }); authAttempts.inc({ method: "saml", result: "failure" });
await audit("SAML_LOGIN_FAILED", { reason: "missing_profile" }); await audit("SAML_LOGIN_FAILED", { reason: "missing_profile" });
+2 -1
View File
@@ -456,7 +456,8 @@ export async function registerBatchRoutes(app: FastifyInstance): Promise<void> {
// Append results from object storage in original upload order // Append results from object storage in original upload order
try { try {
for (const entry of successEntries) { for (const entry of successEntries) {
const stream = await getObjectStream(entry.outputRef!); if (!entry.outputRef) continue;
const stream = await getObjectStream(entry.outputRef);
archive.append(stream, { name: entry.filename }); archive.append(stream, { name: entry.filename });
} }
+1 -1
View File
@@ -4,7 +4,7 @@ import { z } from "zod";
import { env } from "../../config.js"; import { env } from "../../config.js";
import { db, schema } from "../../db/index.js"; import { db, schema } from "../../db/index.js";
import { auditFromRequest } from "../../lib/audit.js"; import { auditFromRequest } from "../../lib/audit.js";
import { encrypt, isEncrypted } from "../../lib/encryption.js"; import { encrypt } from "../../lib/encryption.js";
import { requirePermission } from "../../permissions.js"; import { requirePermission } from "../../permissions.js";
const configSchema = z.object({ const configSchema = z.object({
+2 -1
View File
@@ -1161,7 +1161,8 @@ export async function registerPipelineRoutes(app: FastifyInstance): Promise<void
// Append results from object storage in original upload order // Append results from object storage in original upload order
try { try {
for (const entry of successEntries) { for (const entry of successEntries) {
const stream = await getObjectStream(entry.outputRef!); if (!entry.outputRef) continue;
const stream = await getObjectStream(entry.outputRef);
archive.append(stream, { name: entry.filename }); archive.append(stream, { name: entry.filename });
} }
+1 -1
View File
@@ -387,7 +387,7 @@ export async function registerProgressRoutes(app: FastifyInstance): Promise<void
if (!sseListeners.has(jobId)) { if (!sseListeners.has(jobId)) {
sseListeners.set(jobId, new Set()); sseListeners.set(jobId, new Set());
} }
sseListeners.get(jobId)!.add(callback); sseListeners.get(jobId)?.add(callback);
// Clean up on client disconnect // Clean up on client disconnect
request.raw.on("close", () => { request.raw.on("close", () => {
+2 -1
View File
@@ -88,9 +88,10 @@ export function registerHtmlToImage(app: FastifyInstance) {
isMobile: preset.isMobile, isMobile: preset.isMobile,
}; };
// Zod refine guarantees either url or html is present
const buffer = settings.html const buffer = settings.html
? await captureHtml(settings.html, captureOpts) ? await captureHtml(settings.html, captureOpts)
: await capturePage(settings.url!, captureOpts); : await capturePage(settings.url ?? "", captureOpts);
const jobId = randomUUID(); const jobId = randomUUID();
const ext = settings.format; const ext = settings.format;
@@ -45,7 +45,7 @@ export function BottomSheet({
}, [onClose]); }, [onClose]);
const bind = useDrag( const bind = useDrag(
({ movement: [, my], last, cancel }) => { ({ movement: [, my], last }) => {
// Only allow downward dragging // Only allow downward dragging
if (my < 0) { if (my < 0) {
setTranslateY(0); setTranslateY(0);
+1 -1
View File
@@ -151,7 +151,7 @@ export function Dropzone({
setUrlError(t.dropzone.urlFetchFailed); setUrlError(t.dropzone.urlFetchFailed);
} }
setUrlLoading(false); setUrlLoading(false);
}, [urlInput, importSingleUrl, onUrlImport, checkFile, acceptDescription]); }, [urlInput, importSingleUrl, onUrlImport, checkFile, acceptDescription, t]);
const handleDrag = useCallback((e: DragEvent) => { const handleDrag = useCallback((e: DragEvent) => {
e.preventDefault(); e.preventDefault();
@@ -109,7 +109,7 @@ export function NonNativePreview({
} finally { } finally {
stopMessageRotation(); stopMessageRotation();
} }
}, [file, filename, previewUrl, startMessageRotation, stopMessageRotation]); }, [file, src, filename, previewUrl, startMessageRotation, stopMessageRotation]);
const ext = filename.split(".").pop()?.toUpperCase() ?? ""; const ext = filename.split(".").pop()?.toUpperCase() ?? "";
const IconComponent = modality === "audio" ? Volume2 : Video; const IconComponent = modality === "audio" ? Volume2 : Video;
@@ -6,6 +6,7 @@ export function RouteAnnouncer() {
const isFirstRender = useRef(true); const isFirstRender = useRef(true);
const announcerRef = useRef<HTMLDivElement>(null); const announcerRef = useRef<HTMLDivElement>(null);
// biome-ignore lint/correctness/useExhaustiveDependencies: pathname is the intentional trigger for re-announcing on route change
useEffect(() => { useEffect(() => {
if (isFirstRender.current) { if (isFirstRender.current) {
isFirstRender.current = false; isFirstRender.current = false;
@@ -23,7 +23,7 @@ export function CropOptions() {
if (!cropState) return; if (!cropState) return;
const preset = ASPECT_RATIOS.find((p) => p.label === label); const preset = ASPECT_RATIOS.find((p) => p.label === label);
if (!preset || !preset.value) { if (!preset?.value) {
setCropState({ ...cropState, aspectRatio: null }); setCropState({ ...cropState, aspectRatio: null });
return; return;
} }
@@ -71,7 +71,7 @@ export function useCropTool(): CropToolApi {
(label: string) => { (label: string) => {
setAspectRatioState(label); setAspectRatioState(label);
const preset = ASPECT_RATIOS.find((p) => p.label === label); const preset = ASPECT_RATIOS.find((p) => p.label === label);
if (!preset || !preset.value || !cropState) return; if (!preset?.value || !cropState) return;
const ratio = preset.value; const ratio = preset.value;
let w = cropState.width; let w = cropState.width;
@@ -1,6 +1,5 @@
import { Download, Search, Trash2 } from "lucide-react"; import { Download, Search, Trash2 } from "lucide-react";
import { useCallback, useEffect, useRef, useState } from "react"; import { useCallback, useEffect, useRef, useState } from "react";
import { useNavigate } from "react-router-dom";
import { useTranslation } from "@/contexts/i18n-context"; import { useTranslation } from "@/contexts/i18n-context";
import { getFileDownloadUrl } from "@/lib/api"; import { getFileDownloadUrl } from "@/lib/api";
import { format } from "@/lib/format"; import { format } from "@/lib/format";
@@ -22,7 +21,6 @@ export function FileList({ filterMimePrefix }: { filterMimePrefix?: string }) {
setSearchQuery, setSearchQuery,
} = useFilesPageStore(); } = useFilesPageStore();
const navigate = useNavigate();
const [inputValue, setInputValue] = useState(""); const [inputValue, setInputValue] = useState("");
const debounceRef = useRef<ReturnType<typeof setTimeout> | null>(null); const debounceRef = useRef<ReturnType<typeof setTimeout> | null>(null);
const listRef = useRef<HTMLDivElement>(null); const listRef = useRef<HTMLDivElement>(null);
@@ -1,9 +1,7 @@
import { Check, Copy, Download, Search } from "lucide-react"; import { Check, Copy, Download, Search } from "lucide-react";
import { useRef, useState } from "react"; import { useRef, useState } from "react";
import { ProgressCard } from "@/components/common/progress-card"; import { ProgressCard } from "@/components/common/progress-card";
import { useTranslation } from "@/contexts/i18n-context";
import { formatHeaders } from "@/lib/api"; import { formatHeaders } from "@/lib/api";
import { format } from "@/lib/format";
import { copyToClipboard } from "@/lib/utils"; import { copyToClipboard } from "@/lib/utils";
import { useFileStore } from "@/stores/file-store"; import { useFileStore } from "@/stores/file-store";
@@ -108,7 +106,6 @@ function scanOneFile(
} }
export function BarcodeReadSettings() { export function BarcodeReadSettings() {
const { t } = useTranslation();
const { files, processing, error, setProcessing, setError } = useFileStore(); const { files, processing, error, setProcessing, setError } = useFileStore();
const [tryHarder, setTryHarder] = useState(false); const [tryHarder, setTryHarder] = useState(false);
@@ -2,9 +2,7 @@ import { Download } from "lucide-react";
import type React from "react"; import type React from "react";
import { useCallback, useEffect, useRef, useState } from "react"; import { useCallback, useEffect, useRef, useState } from "react";
import { ProgressCard } from "@/components/common/progress-card"; import { ProgressCard } from "@/components/common/progress-card";
import { useTranslation } from "@/contexts/i18n-context";
import { useToolProcessor } from "@/hooks/use-tool-processor"; import { useToolProcessor } from "@/hooks/use-tool-processor";
import { format } from "@/lib/format";
import { useFileStore } from "@/stores/file-store"; import { useFileStore } from "@/stores/file-store";
// ── Presets ────────────────────────────────────────────────────────── // ── Presets ──────────────────────────────────────────────────────────
@@ -227,7 +225,6 @@ export function BorderControls({
onChange, onChange,
onImageStyle, onImageStyle,
}: BorderControlsProps) { }: BorderControlsProps) {
const { t } = useTranslation();
const [selectedPreset, setSelectedPreset] = useState<string | null>(null); const [selectedPreset, setSelectedPreset] = useState<string | null>(null);
const [borderWidth, setBorderWidth] = useState(10); const [borderWidth, setBorderWidth] = useState(10);
const [borderColor, setBorderColor] = useState("#000000"); const [borderColor, setBorderColor] = useState("#000000");
@@ -51,7 +51,6 @@ function displayUrl(img: CollageImage): string {
} }
export function CollagePreview() { export function CollagePreview() {
const { t } = useTranslation();
const images = useCollageStore((s) => s.images); const images = useCollageStore((s) => s.images);
const templateId = useCollageStore((s) => s.templateId); const templateId = useCollageStore((s) => s.templateId);
const phase = useCollageStore((s) => s.phase); const phase = useCollageStore((s) => s.phase);
@@ -1,7 +1,6 @@
import { Download, Loader2 } from "lucide-react"; import { Download, Loader2 } from "lucide-react";
import { useCallback } from "react"; import { useCallback } from "react";
import { CollapsibleSection } from "@/components/common/collapsible-section"; import { CollapsibleSection } from "@/components/common/collapsible-section";
import { useTranslation } from "@/contexts/i18n-context";
import { formatHeaders } from "@/lib/api"; import { formatHeaders } from "@/lib/api";
import { import {
COLLAGE_TEMPLATES, COLLAGE_TEMPLATES,
@@ -38,7 +37,6 @@ const BG_PRESETS = [
]; ];
export function CollageSettings() { export function CollageSettings() {
const { t } = useTranslation();
const store = useCollageStore(); const store = useCollageStore();
const { const {
images, images,
@@ -1,10 +1,8 @@
import { Download, Loader2, Upload } from "lucide-react"; import { Download, Loader2, Upload } from "lucide-react";
import { useRef, useState } from "react"; import { useRef, useState } from "react";
import { useTranslation } from "@/contexts/i18n-context";
import { formatHeaders } from "@/lib/api"; import { formatHeaders } from "@/lib/api";
import { useFileStore } from "@/stores/file-store"; import { useFileStore } from "@/stores/file-store";
export function CompareSettings() { export function CompareSettings() {
const { t } = useTranslation();
const { files, processing, error, setProcessing, setError, setProcessedUrl } = useFileStore(); const { files, processing, error, setProcessing, setError, setProcessedUrl } = useFileStore();
const [secondFile, setSecondFile] = useState<File | null>(null); const [secondFile, setSecondFile] = useState<File | null>(null);
const [similarity, setSimilarity] = useState<number | null>(null); const [similarity, setSimilarity] = useState<number | null>(null);
+1 -1
View File
@@ -54,7 +54,7 @@ export const useFeaturesStore = create<FeaturesState>((set, get) => {
try { try {
await refreshBundles(); await refreshBundles();
const updated = get().bundles.find((b) => b.id === bundleId); const updated = get().bundles.find((b) => b.id === bundleId);
if (!updated || updated.status !== "installing") { if (updated?.status !== "installing") {
clearInterval(pollRefs[bundleId]); clearInterval(pollRefs[bundleId]);
delete pollRefs[bundleId]; delete pollRefs[bundleId];