Fix: re-enable global lint, fix un-caught warnings / errors (#6990)

This commit is contained in:
shamoon
2026-08-15 11:01:29 -07:00
committed by GitHub
parent 342afa2215
commit f711d290a7
22 changed files with 32 additions and 41 deletions
+2
View File
@@ -17,6 +17,8 @@ const compat = new FlatCompat({
export default defineConfig([ export default defineConfig([
{ {
files: ["**/*.{js,mjs,cjs,jsx}"],
extends: fixupConfigRules(compat.extends("next/core-web-vitals", "prettier", "plugin:react-hooks/recommended")), extends: fixupConfigRules(compat.extends("next/core-web-vitals", "prettier", "plugin:react-hooks/recommended")),
plugins: { plugins: {
-1
View File
@@ -15,7 +15,6 @@ export default class ErrorBoundary extends React.Component {
// You can also log error messages to an error reporting service here // You can also log error messages to an error reporting service here
if (error || errorInfo) { if (error || errorInfo) {
// eslint-disable-next-line no-console
console.error("component error: %s, info: %s", error, errorInfo); console.error("component error: %s, info: %s", error, errorInfo);
} }
} }
+1 -2
View File
@@ -147,7 +147,7 @@ export default function QuickLaunch({ servicesAndBookmarks, searchString, setSea
let descriptionMatch; let descriptionMatch;
if (searchDescriptions) { if (searchDescriptions) {
descriptionMatch = r.description?.toLowerCase().includes(searchString); descriptionMatch = r.description?.toLowerCase().includes(searchString);
r.priority = nameMatch ? 2 * +nameMatch : +descriptionMatch; // eslint-disable-line no-param-reassign r.priority = nameMatch ? 2 * +nameMatch : +descriptionMatch;
} }
return nameMatch || descriptionMatch; return nameMatch || descriptionMatch;
}); });
@@ -244,7 +244,6 @@ export default function QuickLaunch({ servicesAndBookmarks, searchString, setSea
<span> <span>
{parts.map((part, i) => {parts.map((part, i) =>
part.toLowerCase() === searchString.toLowerCase() ? ( part.toLowerCase() === searchString.toLowerCase() ? (
// eslint-disable-next-line react/no-array-index-key
<span key={`${searchString}_${i}`} className="bg-theme-300/10"> <span key={`${searchString}_${i}`} className="bg-theme-300/10">
{part} {part}
</span> </span>
+3 -3
View File
@@ -13,13 +13,13 @@ export default function Error({ error }) {
const { t } = useTranslation(); const { t } = useTranslation();
if (typeof error === "string") { if (typeof error === "string") {
error = { message: error }; // eslint-disable-line no-param-reassign error = { message: error };
} else if (typeof error === "number") { } else if (typeof error === "number") {
error = { message: `Error ${error}` }; // eslint-disable-line no-param-reassign error = { message: `Error ${error}` };
} }
if (error?.data?.error) { if (error?.data?.error) {
error = error.data.error; // eslint-disable-line no-param-reassign error = error.data.error;
} }
return ( return (
@@ -7,7 +7,6 @@ import Resource from "../widget/resource";
export default function Network({ options, refresh = 1500 }) { export default function Network({ options, refresh = 1500 }) {
const { t } = useTranslation(); const { t } = useTranslation();
// eslint-disable-next-line no-param-reassign
if (options.network === true) options.network = "default"; if (options.network === true) options.network = "default";
const { data, error } = useSWR(`/api/widgets/resources?type=network&interfaceName=${options.network}`, { const { data, error } = useSWR(`/api/widgets/resources?type=network&interfaceName=${options.network}`, {
+8 -8
View File
@@ -11,7 +11,7 @@ import {
} from "@headlessui/react"; } from "@headlessui/react";
import classNames from "classnames"; import classNames from "classnames";
import { useTranslation } from "next-i18next/pages"; import { useTranslation } from "next-i18next/pages";
import { Fragment, useEffect, useState } from "react"; import { Fragment, useEffect, useMemo, useState } from "react";
import { BiLogoBing } from "react-icons/bi"; import { BiLogoBing } from "react-icons/bi";
import { FiSearch } from "react-icons/fi"; import { FiSearch } from "react-icons/fi";
import { SiBaidu, SiBrave, SiDuckduckgo, SiGoogle } from "react-icons/si"; import { SiBaidu, SiBrave, SiDuckduckgo, SiGoogle } from "react-icons/si";
@@ -57,12 +57,12 @@ export const searchProviders = {
}, },
}; };
function getAvailableProviderIds(options) { function getAvailableProviderIds(provider) {
if (options.provider && Array.isArray(options.provider)) { if (provider && Array.isArray(provider)) {
return options.provider.filter((value) => searchProviders.hasOwnProperty(value)); return provider.filter((value) => searchProviders.hasOwnProperty(value));
} }
if (options.provider && searchProviders[options.provider]) { if (provider && searchProviders[provider]) {
return [options.provider]; return [provider];
} }
return null; return null;
} }
@@ -82,7 +82,8 @@ export function getStoredProvider() {
export default function Search({ options }) { export default function Search({ options }) {
const { t } = useTranslation(); const { t } = useTranslation();
const availableProviderIds = getAvailableProviderIds(options) ?? []; // options is a fresh object each render, so memo on provider itself
const availableProviderIds = useMemo(() => getAvailableProviderIds(options.provider) ?? [], [options.provider]);
const [query, setQuery] = useState(""); const [query, setQuery] = useState("");
const [selectedProvider, setSelectedProvider] = useState(searchProviders[availableProviderIds[0] ?? "google"]); const [selectedProvider, setSelectedProvider] = useState(searchProviders[availableProviderIds[0] ?? "google"]);
@@ -184,7 +185,6 @@ export default function Search({ options }) {
autoCapitalize="off" autoCapitalize="off"
autoCorrect="off" autoCorrect="off"
autoComplete="off" autoComplete="off"
// eslint-disable-next-line jsx-a11y/no-autofocus
autoFocus={options.focus} autoFocus={options.focus}
onBlur={(e) => e.preventDefault()} onBlur={(e) => e.preventDefault()}
onKeyDown={handleSearchKeyDown} onKeyDown={handleSearchKeyDown}
@@ -14,7 +14,6 @@ import useWidgetAPI from "utils/proxy/use-widget-api";
export default function Widget({ options }) { export default function Widget({ options }) {
const { t } = useTranslation(); const { t } = useTranslation();
// eslint-disable-next-line no-param-reassign, no-multi-assign
options.service_group = options.service_name = "unifi_console"; options.service_group = options.service_name = "unifi_console";
const { data: statsData, error: statsError } = useWidgetAPI(options, "stat/sites", { index: options.index }); const { data: statsData, error: statsError } = useWidgetAPI(options, "stat/sites", { index: options.index });
@@ -39,8 +38,8 @@ export default function Widget({ options }) {
const lan = defaultSite.health.find((h) => h.subsystem === "lan"); const lan = defaultSite.health.find((h) => h.subsystem === "lan");
const wlan = defaultSite.health.find((h) => h.subsystem === "wlan"); const wlan = defaultSite.health.find((h) => h.subsystem === "wlan");
[wan, lan, wlan].forEach((s) => { [wan, lan, wlan].forEach((s) => {
s.up = s.status === "ok"; // eslint-disable-line no-param-reassign s.up = s.status === "ok";
s.show = s.status !== "unknown"; // eslint-disable-line no-param-reassign s.show = s.status !== "unknown";
}); });
const name = wan.gw_name ?? defaultSite.desc; const name = wan.gw_name ?? defaultSite.desc;
const uptime = wan["gw_system-stats"] ? wan["gw_system-stats"].uptime : null; const uptime = wan["gw_system-stats"] ? wan["gw_system-stats"].uptime : null;
@@ -10,7 +10,6 @@ import WidgetIcon from "./widget_icon";
export function getAllClasses(options, additionalClassNames = "") { export function getAllClasses(options, additionalClassNames = "") {
if (options?.style?.header === "boxedWidgets") { if (options?.style?.header === "boxedWidgets") {
if (options?.style?.cardBlur !== undefined) { if (options?.style?.cardBlur !== undefined) {
// eslint-disable-next-line no-param-reassign
additionalClassNames = [ additionalClassNames = [
additionalClassNames, additionalClassNames,
`backdrop-blur${options.style.cardBlur.length ? "-" : ""}${options.style.cardBlur}`, `backdrop-blur${options.style.cardBlur.length ? "-" : ""}${options.style.cardBlur}`,
-2
View File
@@ -1,4 +1,3 @@
/* eslint-disable react/jsx-props-no-spreading */
import { SessionProvider } from "next-auth/react"; import { SessionProvider } from "next-auth/react";
import { appWithTranslation } from "next-i18next/pages"; import { appWithTranslation } from "next-i18next/pages";
import Head from "next/head"; import Head from "next/head";
@@ -13,7 +12,6 @@ import { ThemeProvider } from "utils/contexts/theme";
import nextI18nextConfig from "../../next-i18next.config"; import nextI18nextConfig from "../../next-i18next.config";
// eslint-disable-next-line no-unused-vars
const tailwindSafelist = [ const tailwindSafelist = [
// TODO: remove pending https://github.com/tailwindlabs/tailwindcss/pull/17147 // TODO: remove pending https://github.com/tailwindlabs/tailwindcss/pull/17147
"backdrop-blur", "backdrop-blur",
+1 -2
View File
@@ -1,4 +1,3 @@
/* eslint-disable react/no-array-index-key */
import classNames from "classnames"; import classNames from "classnames";
import BookmarksGroup from "components/bookmarks/group"; import BookmarksGroup from "components/bookmarks/group";
import ErrorBoundary from "components/errorboundry"; import ErrorBoundary from "components/errorboundry";
@@ -175,7 +174,7 @@ function Index({ initialSettings, fallback }) {
</div> </div>
<div className="p-2 text-theme-100 dark:text-theme-200"> <div className="p-2 text-theme-100 dark:text-theme-200">
<pre className="opacity-50 font-bold pb-2"> <pre className="opacity-50 font-bold pb-2">
Reason: "{error.reason}" at line {error.mark?.line} Reason: &quot;{error.reason}&quot; at line {error.mark?.line}
</pre> </pre>
<pre className="font-italic">Check logs for details.</pre> <pre className="font-italic">Check logs for details.</pre>
</div> </div>
-1
View File
@@ -1,5 +1,4 @@
import { render } from "@testing-library/react"; import { render } from "@testing-library/react";
import { SettingsContext } from "utils/contexts/settings"; import { SettingsContext } from "utils/contexts/settings";
export function renderWithProviders(ui, { settings = {} } = {}) { export function renderWithProviders(ui, { settings = {} } = {}) {
-1
View File
@@ -32,7 +32,6 @@ export function ColorProvider({ initialTheme, children }) {
useEffect(() => { useEffect(() => {
if (initialTheme !== undefined) setColor(initialTheme ?? getInitialColor()); if (initialTheme !== undefined) setColor(initialTheme ?? getInitialColor());
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [initialTheme]); }, [initialTheme]);
useEffect(() => { useEffect(() => {
-1
View File
@@ -33,7 +33,6 @@ export function ThemeProvider({ initialTheme, children }) {
useEffect(() => { useEffect(() => {
if (initialTheme !== undefined) setTheme(initialTheme ?? getInitialTheme()); if (initialTheme !== undefined) setTheme(initialTheme ?? getInitialTheme());
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [initialTheme]); }, [initialTheme]);
useEffect(() => { useEffect(() => {
+7 -5
View File
@@ -16,14 +16,16 @@ export default function Component({ service }) {
widget.fields = widget.fields.slice(0, MAX_FIELDS); widget.fields = widget.fields.slice(0, MAX_FIELDS);
} }
if (widget?.env == null || widget.env === "") { const envNotSet = widget.env == null || widget.env === "";
const { data: containers, error: containersError } = useWidgetAPI(widget, envNotSet ? "" : "containers");
const { data: images, error: imagesError } = useWidgetAPI(widget, envNotSet ? "" : "images");
const { data: updates, error: updatesError } = useWidgetAPI(widget, envNotSet ? "" : "updates");
if (envNotSet) {
return <Container service={service} error={t("arcane.environment_required")} />; return <Container service={service} error={t("arcane.environment_required")} />;
} }
const { data: containers, error: containersError } = useWidgetAPI(widget, "containers");
const { data: images, error: imagesError } = useWidgetAPI(widget, "images");
const { data: updates, error: updatesError } = useWidgetAPI(widget, "updates");
const error = const error =
containersError ?? imagesError ?? updatesError ?? containers?.detail ?? images?.detail ?? updates?.detail; containersError ?? imagesError ?? updatesError ?? containers?.detail ?? images?.detail ?? updates?.detail;
if (error) { if (error) {
+5 -1
View File
@@ -20,11 +20,15 @@ describe("widgets/arcane/component", () => {
}); });
it("shows an environment required error when env is missing", () => { it("shows an environment required error when env is missing", () => {
useWidgetAPI.mockImplementation(() => ({ data: undefined, error: undefined }));
renderWithProviders(<Component service={{ widget: { type: "arcane" } }} />, { renderWithProviders(<Component service={{ widget: { type: "arcane" } }} />, {
settings: { hideErrors: false }, settings: { hideErrors: false },
}); });
expect(useWidgetAPI).not.toHaveBeenCalled(); // hooks always run; the empty endpoint is what skips the request
expect(useWidgetAPI).toHaveBeenCalledTimes(3);
useWidgetAPI.mock.calls.forEach((call) => expect(call[1]).toBe(""));
expect(screen.getByText("arcane.environment_required")).toBeInTheDocument(); expect(screen.getByText("arcane.environment_required")).toBeInTheDocument();
}); });
-1
View File
@@ -27,7 +27,6 @@ export default function Component({ service }) {
} }
// uptime info // uptime info
// eslint-disable-next-line no-unused-vars
const [hour, minutes, seconds] = infoData.data.up_time.split(":"); const [hour, minutes, seconds] = infoData.data.up_time.split(":");
const days = Math.floor(hour / 24); const days = Math.floor(hour / 24);
const uptime = `${t("common.number", { value: days })} ${t("diskstation.days")}`; const uptime = `${t("common.number", { value: days })} ${t("diskstation.days")}`;
-2
View File
@@ -28,7 +28,6 @@ export default function Component({ service }) {
useEffect(() => { useEffect(() => {
if (data && !data.error) { if (data && !data.error) {
// eslint-disable-next-line eqeqeq
const gpuData = data.find((item) => item[item.key] == gpuName); const gpuData = data.find((item) => item[item.key] == gpuName);
if (gpuData) { if (gpuData) {
@@ -56,7 +55,6 @@ export default function Component({ service }) {
); );
} }
// eslint-disable-next-line eqeqeq
const gpuData = data.find((item) => item[item.key] == gpuName); const gpuData = data.find((item) => item[item.key] == gpuName);
if (!gpuData) { if (!gpuData) {
+1
View File
@@ -1,6 +1,7 @@
import Block from "components/services/widget/block"; import Block from "components/services/widget/block";
import Container from "components/services/widget/container"; import Container from "components/services/widget/container";
import { useTranslation } from "next-i18next/pages"; import { useTranslation } from "next-i18next/pages";
import useWidgetAPI from "utils/proxy/use-widget-api"; import useWidgetAPI from "utils/proxy/use-widget-api";
export default function Component({ service }) { export default function Component({ service }) {
-2
View File
@@ -8,7 +8,6 @@ export default function Component({ service }) {
const { t } = useTranslation(); const { t } = useTranslation();
const { widget } = service; const { widget } = service;
// eslint-disable-next-line prefer-const
let { data: spoolData, error: spoolError } = useWidgetAPI(widget, "spools"); let { data: spoolData, error: spoolError } = useWidgetAPI(widget, "spools");
if (spoolError) { if (spoolError) {
@@ -20,7 +19,6 @@ export default function Component({ service }) {
return ( return (
<Container service={service}> <Container service={service}>
{[...Array(nBlocksGuess)].map((_, i) => ( {[...Array(nBlocksGuess)].map((_, i) => (
// eslint-disable-next-line react/no-array-index-key
<Block key={i} label="spoolman.loading" /> <Block key={i} label="spoolman.loading" />
))} ))}
</Container> </Container>
-1
View File
@@ -1,4 +1,3 @@
/* eslint-disable camelcase */
import Container from "components/services/widget/container"; import Container from "components/services/widget/container";
import { useTranslation } from "next-i18next/pages"; import { useTranslation } from "next-i18next/pages";
import { BsCpu, BsFillCpuFill, BsFillPlayFill, BsPauseFill } from "react-icons/bs"; import { BsCpu, BsFillCpuFill, BsFillPlayFill, BsPauseFill } from "react-icons/bs";
-1
View File
@@ -1,4 +1,3 @@
/* eslint-disable camelcase */
import Block from "components/services/widget/block"; import Block from "components/services/widget/block";
import Container from "components/services/widget/container"; import Container from "components/services/widget/container";
import { useTranslation } from "next-i18next/pages"; import { useTranslation } from "next-i18next/pages";
+2 -2
View File
@@ -38,8 +38,8 @@ export default function Component({ service }) {
const lan = defaultSite.health.find((h) => h.subsystem === "lan"); const lan = defaultSite.health.find((h) => h.subsystem === "lan");
const wlan = defaultSite.health.find((h) => h.subsystem === "wlan"); const wlan = defaultSite.health.find((h) => h.subsystem === "wlan");
[wan, lan, wlan].forEach((s) => { [wan, lan, wlan].forEach((s) => {
s.up = s.status === "ok"; // eslint-disable-line no-param-reassign s.up = s.status === "ok";
s.show = s.status !== "unknown"; // eslint-disable-line no-param-reassign s.show = s.status !== "unknown";
}); });
const uptime = wan["gw_system-stats"] const uptime = wan["gw_system-stats"]