refactor: remove deprecated navidrome/audiobookshelf widgets
Consolidate into the unified Audio Stats widget which adapts its UI based on the linked integration kind — Navidrome shows artists/albums/ songs/now-playing, Audiobookshelf shows libraries/audiobooks/podcasts/ listening-time/sessions. Removes: widget definitions, components, API routers, and the deprecatedWidgetKinds mechanism (no longer needed).
This commit is contained in:
13 files changed
+4
-220
No files matched your search
@@ -9,7 +9,7 @@ import { useScopedI18n } from "@homarr/translation/client";
|
||||
|
||||
import classes from "./component.module.css";
|
||||
import type { AudioStatsBackend, AudioStatsDisplayOptions } from "./shared";
|
||||
import { getGridCols, getIconSize, getVisibleStats, translationScopeByBackend } from "./shared";
|
||||
import { AUDIO_STATS_TRANSLATION_SCOPE, getGridCols, getIconSize, getVisibleStats } from "./shared";
|
||||
|
||||
const rootClassByCompact = {
|
||||
true: classes.rootCompact,
|
||||
@@ -31,7 +31,6 @@ interface AudioStatsContentProps {
|
||||
stats: NavidromeDashboardData | AudiobookshelfDashboardData;
|
||||
options: AudioStatsDisplayOptions;
|
||||
width: number;
|
||||
translationScope?: keyof typeof translationScopeByBackend;
|
||||
}
|
||||
|
||||
export function AudioStatsContent({
|
||||
@@ -39,9 +38,8 @@ export function AudioStatsContent({
|
||||
stats,
|
||||
options,
|
||||
width,
|
||||
translationScope = "audioStats",
|
||||
}: AudioStatsContentProps) {
|
||||
const t = useScopedI18n(translationScopeByBackend[translationScope]);
|
||||
const t = useScopedI18n(AUDIO_STATS_TRANSLATION_SCOPE);
|
||||
const visibleStats = getVisibleStats(backend, options, stats);
|
||||
const compactKey = String(options.compactMode ?? false) as keyof typeof rootClassByCompact;
|
||||
const gridCols = getGridCols(width, visibleStats.length, options.compactMode ?? false);
|
||||
|
||||
@@ -34,7 +34,6 @@ export default function AudioStatsWidget({ integrationIds, options, width }: Wid
|
||||
stats={response.data}
|
||||
options={displayOptions}
|
||||
width={width}
|
||||
translationScope="audioStats"
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -166,8 +166,4 @@ export const getIconSize = (width: number, compact: boolean): number => {
|
||||
return match?.size ?? fallbackIconSize[String(compact) as keyof typeof fallbackIconSize];
|
||||
};
|
||||
|
||||
export const translationScopeByBackend = {
|
||||
navidrome: "widget.navidrome",
|
||||
audiobookshelf: "widget.audiobookshelf",
|
||||
audioStats: "widget.audioStats",
|
||||
} as const;
|
||||
export const AUDIO_STATS_TRANSLATION_SCOPE = "widget.audioStats" as const;
|
||||
@@ -1,38 +0,0 @@
|
||||
"use client";
|
||||
|
||||
import { clientApi } from "@homarr/api/client";
|
||||
|
||||
import type { WidgetComponentProps } from "../definition";
|
||||
import { AudioStatsContent } from "../audio-stats/audio-stats-content";
|
||||
import type { AudiobookshelfDisplayOptions } from "../audio-stats/shared";
|
||||
|
||||
const defaultAudiobookshelfOptions: AudiobookshelfDisplayOptions = {
|
||||
showLibraryCount: true,
|
||||
showAudiobooks: true,
|
||||
showPodcasts: true,
|
||||
showListeningTime: true,
|
||||
showActiveSessions: true,
|
||||
compactMode: false,
|
||||
};
|
||||
|
||||
export default function AudiobookshelfWidget({
|
||||
integrationIds,
|
||||
options,
|
||||
width,
|
||||
}: WidgetComponentProps<"audiobookshelf">) {
|
||||
const [stats] = clientApi.widget.audiobookshelf.getStats.useSuspenseQuery({
|
||||
integrationId: integrationIds[0] ?? "",
|
||||
});
|
||||
|
||||
const displayOptions = { ...defaultAudiobookshelfOptions, ...options };
|
||||
|
||||
return (
|
||||
<AudioStatsContent
|
||||
backend="audiobookshelf"
|
||||
stats={stats}
|
||||
options={displayOptions}
|
||||
width={width}
|
||||
translationScope="audiobookshelf"
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
import { IconHeadphones, IconServerOff } from "@tabler/icons-react";
|
||||
|
||||
import { createWidgetDefinition } from "../definition";
|
||||
import { optionsBuilder } from "../options";
|
||||
|
||||
export const { definition, componentLoader } = createWidgetDefinition("audiobookshelf", {
|
||||
icon: IconHeadphones,
|
||||
supportedIntegrations: ["audiobookshelf"],
|
||||
integrationsRequired: true,
|
||||
createOptions() {
|
||||
return optionsBuilder.from((factory) => ({
|
||||
showLibraryCount: factory.switch({
|
||||
defaultValue: true,
|
||||
withDescription: true,
|
||||
}),
|
||||
showAudiobooks: factory.switch({
|
||||
defaultValue: true,
|
||||
withDescription: true,
|
||||
}),
|
||||
showPodcasts: factory.switch({
|
||||
defaultValue: true,
|
||||
withDescription: true,
|
||||
}),
|
||||
showListeningTime: factory.switch({
|
||||
defaultValue: true,
|
||||
withDescription: true,
|
||||
}),
|
||||
showActiveSessions: factory.switch({
|
||||
defaultValue: true,
|
||||
withDescription: true,
|
||||
}),
|
||||
compactMode: factory.switch({
|
||||
defaultValue: false,
|
||||
withDescription: true,
|
||||
}),
|
||||
}));
|
||||
},
|
||||
errors: {
|
||||
INTERNAL_SERVER_ERROR: {
|
||||
icon: IconServerOff,
|
||||
message: (t) => t("widget.audiobookshelf.error.internalServerError"),
|
||||
},
|
||||
},
|
||||
}).withDynamicImport(() => import("./component"));
|
||||
@@ -9,8 +9,6 @@ import type { SettingsContextProps } from "@homarr/settings/creator";
|
||||
|
||||
import * as anchorNote from "./anchor-note";
|
||||
import * as audioStats from "./audio-stats";
|
||||
import * as audiobookshelf from "./audiobookshelf";
|
||||
import * as navidrome from "./navidrome";
|
||||
import * as app from "./app";
|
||||
import * as bookmarks from "./bookmarks";
|
||||
import * as calendar from "./calendar";
|
||||
@@ -101,8 +99,6 @@ export const widgetImports = {
|
||||
speedtestTracker,
|
||||
uptimeKuma,
|
||||
audioStats,
|
||||
audiobookshelf,
|
||||
navidrome,
|
||||
umami,
|
||||
ups,
|
||||
} satisfies WidgetImportRecord;
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
"use client";
|
||||
|
||||
import { clientApi } from "@homarr/api/client";
|
||||
|
||||
import type { WidgetComponentProps } from "../definition";
|
||||
import { AudioStatsContent } from "../audio-stats/audio-stats-content";
|
||||
import type { NavidromeDisplayOptions } from "../audio-stats/shared";
|
||||
|
||||
const defaultNavidromeOptions: NavidromeDisplayOptions = {
|
||||
showArtists: true,
|
||||
showAlbums: true,
|
||||
showSongs: true,
|
||||
showNowPlaying: true,
|
||||
showNowPlayingList: true,
|
||||
maxNowPlayingItems: 3,
|
||||
};
|
||||
|
||||
export default function NavidromeWidget({ integrationIds, options, width }: WidgetComponentProps<"navidrome">) {
|
||||
const [stats] = clientApi.widget.navidrome.getStats.useSuspenseQuery({
|
||||
integrationId: integrationIds[0] ?? "",
|
||||
});
|
||||
|
||||
const displayOptions = { ...defaultNavidromeOptions, ...options };
|
||||
|
||||
return (
|
||||
<AudioStatsContent
|
||||
backend="navidrome"
|
||||
stats={stats}
|
||||
options={displayOptions}
|
||||
width={width}
|
||||
translationScope="navidrome"
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
import { IconMusic, IconServerOff } from "@tabler/icons-react";
|
||||
import { z } from "zod/v4";
|
||||
|
||||
import { createWidgetDefinition } from "../definition";
|
||||
import { optionsBuilder } from "../options";
|
||||
|
||||
export const { definition, componentLoader } = createWidgetDefinition("navidrome", {
|
||||
icon: IconMusic,
|
||||
supportedIntegrations: ["navidrome"],
|
||||
integrationsRequired: true,
|
||||
createOptions() {
|
||||
return optionsBuilder.from((factory) => ({
|
||||
showArtists: factory.switch({
|
||||
defaultValue: true,
|
||||
withDescription: true,
|
||||
}),
|
||||
showAlbums: factory.switch({
|
||||
defaultValue: true,
|
||||
withDescription: true,
|
||||
}),
|
||||
showSongs: factory.switch({
|
||||
defaultValue: true,
|
||||
withDescription: true,
|
||||
}),
|
||||
showNowPlaying: factory.switch({
|
||||
defaultValue: true,
|
||||
withDescription: true,
|
||||
}),
|
||||
showNowPlayingList: factory.switch({
|
||||
defaultValue: true,
|
||||
withDescription: true,
|
||||
}),
|
||||
maxNowPlayingItems: factory.number({
|
||||
defaultValue: 3,
|
||||
validate: z.number().min(1).max(5),
|
||||
step: 1,
|
||||
withDescription: true,
|
||||
}),
|
||||
}));
|
||||
},
|
||||
errors: {
|
||||
INTERNAL_SERVER_ERROR: {
|
||||
icon: IconServerOff,
|
||||
message: (t) => t("widget.navidrome.error.internalServerError"),
|
||||
},
|
||||
},
|
||||
}).withDynamicImport(() => import("./component"));
|
||||
Reference in new issue
Block a user