From 2b4a18385d574b754892bc907a619f76dbcd4b22 Mon Sep 17 00:00:00 2001 From: ajnart <49837342+ajnart@users.noreply.github.com> Date: Tue, 9 Jun 2026 16:10:56 +0000 Subject: [PATCH] style: auto-fix lint and format --- .../board/items/actions/create-item.ts | 2 +- .../audiobookshelf-integration.ts | 5 +- .../src/navidrome/navidrome-integration.ts | 11 +- .../test/navidrome-integration.spec.ts | 183 +++++++++--------- .../src/paperless-ngx/paperless-ngx-types.ts | 5 +- .../test/uptime-kuma-integration.spec.ts | 49 +++-- .../src/audio-stats/audio-stats-content.tsx | 16 +- .../audio-stats/audio-stats-shared.spec.ts | 20 +- .../widgets/src/paperless-ngx/component.tsx | 21 +- .../widgets/src/uptime-kuma/component.tsx | 4 +- 10 files changed, 152 insertions(+), 164 deletions(-) diff --git a/apps/nextjs/src/components/board/items/actions/create-item.ts b/apps/nextjs/src/components/board/items/actions/create-item.ts index 3e1b0ee4d..d4b2cb24d 100644 --- a/apps/nextjs/src/components/board/items/actions/create-item.ts +++ b/apps/nextjs/src/components/board/items/actions/create-item.ts @@ -20,7 +20,7 @@ export const createItemCallback = (previous: Board): Board => { const firstSection = previous.sections .filter((section): section is EmptySection => section.kind === "empty") - .sort((sectionA, sectionB) => sectionA.yOffset - sectionB.yOffset) + .toSorted((sectionA, sectionB) => sectionA.yOffset - sectionB.yOffset) .at(0); if (!firstSection) return previous; diff --git a/packages/integrations/src/audiobookshelf/audiobookshelf-integration.ts b/packages/integrations/src/audiobookshelf/audiobookshelf-integration.ts index aebe478bf..441d7fe3a 100644 --- a/packages/integrations/src/audiobookshelf/audiobookshelf-integration.ts +++ b/packages/integrations/src/audiobookshelf/audiobookshelf-integration.ts @@ -20,7 +20,10 @@ import type { const mediaTypeCountField = { book: "totalAudiobooks", podcast: "totalPodcasts", -} as const satisfies Record>; +} as const satisfies Record< + AudiobookshelfLibrary["mediaType"], + keyof Pick +>; export class AudiobookshelfIntegration extends Integration { protected async testingAsync(input: IntegrationTestingInput): Promise { diff --git a/packages/integrations/src/navidrome/navidrome-integration.ts b/packages/integrations/src/navidrome/navidrome-integration.ts index c84edba02..706419a9d 100644 --- a/packages/integrations/src/navidrome/navidrome-integration.ts +++ b/packages/integrations/src/navidrome/navidrome-integration.ts @@ -1,4 +1,3 @@ - import { ParseError, ResponseError } from "@homarr/common/server"; import { createLogger } from "@homarr/core/infrastructure/logs"; import { fetchWithTrustedCertificatesAsync } from "@homarr/core/infrastructure/http"; @@ -7,11 +6,7 @@ import type { IntegrationTestingInput } from "../base/integration"; import { Integration } from "../base/integration"; import { TestConnectionError } from "../base/test-connection/test-connection-error"; import type { TestingResult } from "../base/test-connection/test-connection-service"; -import type { - NavidromeDashboardData, - NavidromeNowPlayingEntry, - SubsonicResponseBody, -} from "./navidrome-types"; +import type { NavidromeDashboardData, NavidromeNowPlayingEntry, SubsonicResponseBody } from "./navidrome-types"; import { subsonicResponseSchema } from "./navidrome-types"; const logger = createLogger({ module: "navidromeIntegration" }); @@ -60,9 +55,7 @@ export class NavidromeIntegration extends Integration { return TestConnectionError.UnauthorizedResult(401); } - return TestConnectionError.UnknownResult( - new Error(subsonicResponse.error?.message ?? "Subsonic request failed"), - ); + return TestConnectionError.UnknownResult(new Error(subsonicResponse.error?.message ?? "Subsonic request failed")); } return { success: true }; diff --git a/packages/integrations/src/navidrome/test/navidrome-integration.spec.ts b/packages/integrations/src/navidrome/test/navidrome-integration.spec.ts index 34f5bc5dd..921169b1a 100644 --- a/packages/integrations/src/navidrome/test/navidrome-integration.spec.ts +++ b/packages/integrations/src/navidrome/test/navidrome-integration.spec.ts @@ -52,48 +52,48 @@ describe("NavidromeIntegration.getDashboardDataAsync", () => { songCount, })); - mockFetch.mockImplementation( - (url) => { - const urlStr = toUrlString(url); - - if (urlStr.includes("getArtists")) { - return Promise.resolve( - new Response(subsonicOk({ artists: { index: [{ name: "A", artist: [{ id: "1", name: "Artist" }] }] } }), { status: 200 }), - ) as unknown as ReturnType; - } - - if (urlStr.includes("getAlbumList2")) { - const offsetMatch = urlStr.match(/offset=(\d+)/); - const offset = Number(offsetMatch?.[1] ?? 0); - - if (offset === 0) { - return Promise.resolve( - new Response(subsonicOk({ albumList2: { album: makeAlbums(500, 10) } }), { status: 200 }), - ) as unknown as ReturnType; - } - - if (offset === 500) { - return Promise.resolve( - new Response(subsonicOk({ albumList2: { album: makeAlbums(200, 5) } }), { status: 200 }), - ) as unknown as ReturnType; - } - - return Promise.resolve( - new Response(subsonicOk({ albumList2: {} }), { status: 200 }), - ) as unknown as ReturnType; - } - - if (urlStr.includes("getNowPlaying")) { - return Promise.resolve( - new Response(subsonicOk({ nowPlaying: {} }), { status: 200 }), - ) as unknown as ReturnType; - } + mockFetch.mockImplementation((url) => { + const urlStr = toUrlString(url); + if (urlStr.includes("getArtists")) { return Promise.resolve( - new Response(subsonicOk({}), { status: 200 }), + new Response(subsonicOk({ artists: { index: [{ name: "A", artist: [{ id: "1", name: "Artist" }] }] } }), { + status: 200, + }), ) as unknown as ReturnType; - }, - ); + } + + if (urlStr.includes("getAlbumList2")) { + const offsetMatch = urlStr.match(/offset=(\d+)/); + const offset = Number(offsetMatch?.[1] ?? 0); + + if (offset === 0) { + return Promise.resolve( + new Response(subsonicOk({ albumList2: { album: makeAlbums(500, 10) } }), { status: 200 }), + ) as unknown as ReturnType; + } + + if (offset === 500) { + return Promise.resolve( + new Response(subsonicOk({ albumList2: { album: makeAlbums(200, 5) } }), { status: 200 }), + ) as unknown as ReturnType; + } + + return Promise.resolve(new Response(subsonicOk({ albumList2: {} }), { status: 200 })) as unknown as ReturnType< + typeof fetchWithTrustedCertificatesAsync + >; + } + + if (urlStr.includes("getNowPlaying")) { + return Promise.resolve(new Response(subsonicOk({ nowPlaying: {} }), { status: 200 })) as unknown as ReturnType< + typeof fetchWithTrustedCertificatesAsync + >; + } + + return Promise.resolve(new Response(subsonicOk({}), { status: 200 })) as unknown as ReturnType< + typeof fetchWithTrustedCertificatesAsync + >; + }); const integration = createIntegration(); const result = await integration.getDashboardDataAsync(); @@ -105,33 +105,31 @@ describe("NavidromeIntegration.getDashboardDataAsync", () => { }); test("handles empty library gracefully", async () => { - mockFetch.mockImplementation( - (url) => { - const urlStr = toUrlString(url); - - if (urlStr.includes("getArtists")) { - return Promise.resolve( - new Response(subsonicFailed("Library not found or empty"), { status: 200 }), - ) as unknown as ReturnType; - } - - if (urlStr.includes("getAlbumList2")) { - return Promise.resolve( - new Response(subsonicFailed("Library not found or empty"), { status: 200 }), - ) as unknown as ReturnType; - } - - if (urlStr.includes("getNowPlaying")) { - return Promise.resolve( - new Response(subsonicFailed("Library not found or empty"), { status: 200 }), - ) as unknown as ReturnType; - } + mockFetch.mockImplementation((url) => { + const urlStr = toUrlString(url); + if (urlStr.includes("getArtists")) { return Promise.resolve( - new Response(subsonicOk({}), { status: 200 }), + new Response(subsonicFailed("Library not found or empty"), { status: 200 }), ) as unknown as ReturnType; - }, - ); + } + + if (urlStr.includes("getAlbumList2")) { + return Promise.resolve( + new Response(subsonicFailed("Library not found or empty"), { status: 200 }), + ) as unknown as ReturnType; + } + + if (urlStr.includes("getNowPlaying")) { + return Promise.resolve( + new Response(subsonicFailed("Library not found or empty"), { status: 200 }), + ) as unknown as ReturnType; + } + + return Promise.resolve(new Response(subsonicOk({}), { status: 200 })) as unknown as ReturnType< + typeof fetchWithTrustedCertificatesAsync + >; + }); const integration = createIntegration(); const result = await integration.getDashboardDataAsync(); @@ -145,9 +143,9 @@ describe("NavidromeIntegration.getDashboardDataAsync", () => { test("throws on non-empty-library subsonic error", async () => { mockFetch.mockImplementation( () => - Promise.resolve( - new Response(subsonicFailed("Permission denied"), { status: 200 }), - ) as unknown as ReturnType, + Promise.resolve(new Response(subsonicFailed("Permission denied"), { status: 200 })) as unknown as ReturnType< + typeof fetchWithTrustedCertificatesAsync + >, ); const integration = createIntegration(); @@ -155,37 +153,38 @@ describe("NavidromeIntegration.getDashboardDataAsync", () => { }); test("now playing maps entries correctly", async () => { - mockFetch.mockImplementation( - (url) => { - const urlStr = toUrlString(url); + mockFetch.mockImplementation((url) => { + const urlStr = toUrlString(url); - if (urlStr.includes("getNowPlaying")) { - return Promise.resolve( - new Response(subsonicOk({ + if (urlStr.includes("getNowPlaying")) { + return Promise.resolve( + new Response( + subsonicOk({ nowPlaying: { entry: { title: "Song", artist: "Band", album: "LP", username: "user1", playerName: "Chrome" }, }, - }), { status: 200 }), - ) as unknown as ReturnType; - } - - if (urlStr.includes("getArtists")) { - return Promise.resolve( - new Response(subsonicOk({ artists: {} }), { status: 200 }), - ) as unknown as ReturnType; - } - - if (urlStr.includes("getAlbumList2")) { - return Promise.resolve( - new Response(subsonicOk({ albumList2: {} }), { status: 200 }), - ) as unknown as ReturnType; - } - - return Promise.resolve( - new Response(subsonicOk({}), { status: 200 }), + }), + { status: 200 }, + ), ) as unknown as ReturnType; - }, - ); + } + + if (urlStr.includes("getArtists")) { + return Promise.resolve(new Response(subsonicOk({ artists: {} }), { status: 200 })) as unknown as ReturnType< + typeof fetchWithTrustedCertificatesAsync + >; + } + + if (urlStr.includes("getAlbumList2")) { + return Promise.resolve(new Response(subsonicOk({ albumList2: {} }), { status: 200 })) as unknown as ReturnType< + typeof fetchWithTrustedCertificatesAsync + >; + } + + return Promise.resolve(new Response(subsonicOk({}), { status: 200 })) as unknown as ReturnType< + typeof fetchWithTrustedCertificatesAsync + >; + }); const integration = createIntegration(); const result = await integration.getDashboardDataAsync(); diff --git a/packages/integrations/src/paperless-ngx/paperless-ngx-types.ts b/packages/integrations/src/paperless-ngx/paperless-ngx-types.ts index 00d34f8c2..8a47ffcdb 100644 --- a/packages/integrations/src/paperless-ngx/paperless-ngx-types.ts +++ b/packages/integrations/src/paperless-ngx/paperless-ngx-types.ts @@ -2,7 +2,10 @@ import { z } from "zod/v4"; export const paperlessNgxStatisticsSchema = z.object({ documents_total: z.number(), - documents_inbox: z.number().nullable().transform((value) => value ?? 0), + documents_inbox: z + .number() + .nullable() + .transform((value) => value ?? 0), }); export const paperlessNgxPaginatedCountSchema = z.object({ diff --git a/packages/integrations/src/uptime-kuma/test/uptime-kuma-integration.spec.ts b/packages/integrations/src/uptime-kuma/test/uptime-kuma-integration.spec.ts index b0e8d3ad7..f21c522b6 100644 --- a/packages/integrations/src/uptime-kuma/test/uptime-kuma-integration.spec.ts +++ b/packages/integrations/src/uptime-kuma/test/uptime-kuma-integration.spec.ts @@ -80,21 +80,19 @@ describe("UptimeKumaIntegration.getDashboardDataAsync", () => { }; const mockResponses = () => { - mockFetch.mockImplementation( - (url) => { - const urlStr = toUrlString(url); - - if (urlStr.includes("/heartbeat/")) { - return Promise.resolve( - new Response(JSON.stringify(heartbeatResponse), { status: 200 }), - ) as unknown as ReturnType; - } + mockFetch.mockImplementation((url) => { + const urlStr = toUrlString(url); + if (urlStr.includes("/heartbeat/")) { return Promise.resolve( - new Response(JSON.stringify(statusPageResponse), { status: 200 }), + new Response(JSON.stringify(heartbeatResponse), { status: 200 }), ) as unknown as ReturnType; - }, - ); + } + + return Promise.resolve( + new Response(JSON.stringify(statusPageResponse), { status: 200 }), + ) as unknown as ReturnType; + }); }; test("aggregates monitor counts correctly", async () => { @@ -123,21 +121,22 @@ describe("UptimeKumaIntegration.getDashboardDataAsync", () => { uptimeList: { "10_24": 1 }, }; - mockFetch.mockImplementation( - (url) => { - const urlStr = toUrlString(url); - if (urlStr.includes("/heartbeat/")) { - return Promise.resolve( - new Response(JSON.stringify(unknownHeartbeat), { status: 200 }), - ) as unknown as ReturnType; - } + mockFetch.mockImplementation((url) => { + const urlStr = toUrlString(url); + if (urlStr.includes("/heartbeat/")) { return Promise.resolve( - new Response(JSON.stringify({ - publicGroupList: [{ id: 1, name: "G", monitorList: [{ id: 10, name: "Svc" }] }], - }), { status: 200 }), + new Response(JSON.stringify(unknownHeartbeat), { status: 200 }), ) as unknown as ReturnType; - }, - ); + } + return Promise.resolve( + new Response( + JSON.stringify({ + publicGroupList: [{ id: 1, name: "G", monitorList: [{ id: 10, name: "Svc" }] }], + }), + { status: 200 }, + ), + ) as unknown as ReturnType; + }); const integration = createIntegration([{ kind: "slug", value: "default" }]); const result = await integration.getDashboardDataAsync(); diff --git a/packages/widgets/src/audio-stats/audio-stats-content.tsx b/packages/widgets/src/audio-stats/audio-stats-content.tsx index 65347cd0f..31aa7e8ac 100644 --- a/packages/widgets/src/audio-stats/audio-stats-content.tsx +++ b/packages/widgets/src/audio-stats/audio-stats-content.tsx @@ -63,7 +63,9 @@ export function AudioStatsContent({ const nowPlayingTracks = navidromeStats?.nowPlaying.slice( 0, - nowPlayingLimitByListVisibility[String(options.showNowPlayingList) as keyof typeof nowPlayingLimitByListVisibility], + nowPlayingLimitByListVisibility[ + String(options.showNowPlayingList) as keyof typeof nowPlayingLimitByListVisibility + ], ) ?? []; const hasContent = visibleStats.length > 0 || showNowPlayingSection; @@ -76,10 +78,7 @@ export function AudioStatsContent({ style={{ "--stat-cols": gridCols } as CSSProperties} > {visibleStats.map(({ optionKey, statKey, value, Icon }) => ( -
+
{value} {t(statKey as never)} @@ -95,10 +94,9 @@ export function AudioStatsContent({ {t("nowPlaying" as never)} {!options.showNowPlayingList && ( - {(t as unknown as (key: string, params?: { count: number }) => string)( - "nowPlayingCount", - { count: navidromeStats.nowPlaying.length }, - )} + {(t as unknown as (key: string, params?: { count: number }) => string)("nowPlayingCount", { + count: navidromeStats.nowPlaying.length, + })} )}
diff --git a/packages/widgets/src/audio-stats/audio-stats-shared.spec.ts b/packages/widgets/src/audio-stats/audio-stats-shared.spec.ts index e3379f0ec..3aab75060 100644 --- a/packages/widgets/src/audio-stats/audio-stats-shared.spec.ts +++ b/packages/widgets/src/audio-stats/audio-stats-shared.spec.ts @@ -54,7 +54,11 @@ describe("getVisibleStats", () => { }; test("returns only enabled navidrome stats", () => { - const result = getVisibleStats("navidrome", { showArtists: true, showAlbums: false, showSongs: true }, navidromeStats); + const result = getVisibleStats( + "navidrome", + { showArtists: true, showAlbums: false, showSongs: true }, + navidromeStats, + ); expect(result).toHaveLength(2); expect(result.map((s) => s.statKey)).toEqual(["artists", "songs"]); expect(result[0]?.value).toBe(100); @@ -64,7 +68,13 @@ describe("getVisibleStats", () => { test("returns only enabled audiobookshelf stats", () => { const result = getVisibleStats( "audiobookshelf", - { showLibraryCount: true, showAudiobooks: true, showPodcasts: false, showListeningTime: false, showActiveSessions: true }, + { + showLibraryCount: true, + showAudiobooks: true, + showPodcasts: false, + showListeningTime: false, + showActiveSessions: true, + }, audiobookshelfStats, ); expect(result).toHaveLength(3); @@ -77,11 +87,7 @@ describe("getVisibleStats", () => { }); test("formats listening time as duration string", () => { - const result = getVisibleStats( - "audiobookshelf", - { showListeningTime: true }, - audiobookshelfStats, - ); + const result = getVisibleStats("audiobookshelf", { showListeningTime: true }, audiobookshelfStats); expect(result).toHaveLength(1); expect(typeof result[0]?.value).toBe("string"); }); diff --git a/packages/widgets/src/paperless-ngx/component.tsx b/packages/widgets/src/paperless-ngx/component.tsx index 60cb91ffc..406c50605 100644 --- a/packages/widgets/src/paperless-ngx/component.tsx +++ b/packages/widgets/src/paperless-ngx/component.tsx @@ -1,14 +1,9 @@ "use client"; -import { Fragment, type CSSProperties } from "react"; +import { Fragment } from "react"; +import type { CSSProperties } from "react"; import { RingProgress, Text } from "@mantine/core"; -import { - IconFileDescription, - IconFileText, - IconInbox, - IconTag, - IconUsers, -} from "@tabler/icons-react"; +import { IconFileDescription, IconFileText, IconInbox, IconTag, IconUsers } from "@tabler/icons-react"; import { clientApi } from "@homarr/api/client"; import { useScopedI18n } from "@homarr/translation/client"; @@ -74,11 +69,7 @@ const heroPartVisibility = { ring: "showInboxRing", } as const; -export default function PaperlessNgxWidget({ - integrationIds, - options, - width, -}: WidgetComponentProps<"paperlessNgx">) { +export default function PaperlessNgxWidget({ integrationIds, options, width }: WidgetComponentProps<"paperlessNgx">) { const t = useScopedI18n("widget.paperlessNgx"); const [stats] = clientApi.widget.paperlessNgx.getStats.useSuspenseQuery({ integrationId: integrationIds[0] ?? "", @@ -150,9 +141,7 @@ export default function PaperlessNgxWidget({ {showHero && (
{visibleHeroParts.map(([partKey]) => ( - - {heroPartRenderers[partKey as keyof typeof heroPartRenderers]} - + {heroPartRenderers[partKey as keyof typeof heroPartRenderers]} ))}
)} diff --git a/packages/widgets/src/uptime-kuma/component.tsx b/packages/widgets/src/uptime-kuma/component.tsx index 984cfe12d..4d484138a 100644 --- a/packages/widgets/src/uptime-kuma/component.tsx +++ b/packages/widgets/src/uptime-kuma/component.tsx @@ -94,9 +94,7 @@ export default function UptimeKumaWidget({ throw new NoIntegrationDataError(); } - return ( - - ); + return ; } interface UptimeKumaContentProps {