Merge remote-tracking branch 'origin/release/v2' into feat/pr-6691-hardening

# Conflicts:
#	apps/nextjs/src/app/[locale]/layout.tsx
#	packages/api/src/router/widgets/anchor-notes.ts
#	packages/api/src/router/widgets/archive-team-warrior.ts
#	packages/api/src/router/widgets/audio-stats.ts
#	packages/api/src/router/widgets/bazarr.ts
#	packages/api/src/router/widgets/coolify.ts
#	packages/api/src/router/widgets/firewall.ts
#	packages/api/src/router/widgets/immich.ts
#	packages/api/src/router/widgets/paperless-ngx.ts
#	packages/api/src/router/widgets/patchmon.ts
#	packages/api/src/router/widgets/speedtest-tracker.ts
#	packages/api/src/router/widgets/tracearr.ts
#	packages/api/src/router/widgets/traefik.ts
#	packages/api/src/router/widgets/umami.ts
#	packages/api/src/router/widgets/uptime-kuma.ts
#	packages/api/src/router/widgets/vpn.ts
#	packages/api/src/router/widgets/wud.ts
#	packages/definitions/src/widget-integration-map.ts
#	packages/widgets/src/anchor-note/index.ts
#	packages/widgets/src/archive-team-warrior/index.ts
#	packages/widgets/src/audio-stats/index.ts
#	packages/widgets/src/bazarr/index.ts
#	packages/widgets/src/coolify/index.ts
#	packages/widgets/src/firewall/index.ts
#	packages/widgets/src/immich/album-carousel/index.ts
#	packages/widgets/src/immich/server-stats/index.ts
#	packages/widgets/src/paperless-ngx/index.ts
#	packages/widgets/src/patchmon/index.ts
#	packages/widgets/src/speedtest-tracker/index.ts
#	packages/widgets/src/system-disks/index.ts
#	packages/widgets/src/system-resources/index.ts
#	packages/widgets/src/tracearr/index.ts
#	packages/widgets/src/traefik/index.ts
#	packages/widgets/src/umami/index.ts
#	packages/widgets/src/uptime-kuma/index.ts
#	packages/widgets/src/vpn/index.ts
#	packages/widgets/src/wud/index.ts
This commit is contained in:
ajnart committed 2026-08-26 15:12:49 +02:00
commit ac7e3f2ef4
201 files changed
+13795 -981

No files matched your search

@@ -26,6 +26,12 @@ describe("widget integration config", () => {
}
});
test("supports the mock integration for every integration-backed widget", () => {
for (const config of Object.values(widgetIntegrationConfigs)) {
expect(config.supportedIntegrations).toContain("mock");
}
});
test("derives optional connections and server selection limits", () => {
expect(widgetKindsWithOptionalIntegrations).toEqual(new Set(["calendar"]));
expect(widgetIntegrationLimits).toEqual({
@@ -59,34 +59,34 @@ export const widgetIntegrationConfigs = {
healthMonitoring: {
supportedIntegrations: [...healthMonitoringGeneralIntegrationKinds, ...healthMonitoringClusterIntegrationKinds],
},
firewall: { supportedIntegrations: getIntegrationKindsByCategory("firewall") },
firewall: { supportedIntegrations: [...getIntegrationKindsByCategory("firewall"), "mock"] },
notifications: { supportedIntegrations: getIntegrationKindsByCategory("notifications") },
mediaReleases: { supportedIntegrations: ["mock", "emby", "jellyfin", "plex"] },
systemResources: {
supportedIntegrations: [...healthMonitoringGeneralIntegrationKinds],
supportedIntegrations: [...healthMonitoringSystemIntegrationKinds],
},
systemDisks: { supportedIntegrations: ["dashDot", "openmediavault", "truenas", "unraid", "synology"] },
systemDisks: { supportedIntegrations: ["dashDot", "openmediavault", "truenas", "unraid", "synology", "mock"] },
beszelAlerts: { supportedIntegrations: ["beszel", "mock"] },
beszelSystemGrid: { supportedIntegrations: ["beszel", "mock"] },
beszelSystemStats: { supportedIntegrations: ["beszel", "mock"] },
beszelSystemTable: { supportedIntegrations: ["beszel", "mock"] },
coolify: { supportedIntegrations: ["coolify"] },
"immich-serverStats": { supportedIntegrations: ["immich"], maxIntegrations: 1 },
"immich-albumCarousel": { supportedIntegrations: ["immich"], maxIntegrations: 1 },
paperlessNgx: { supportedIntegrations: ["paperlessNgx"], maxIntegrations: 1 },
patchmon: { supportedIntegrations: ["patchmon"], maxIntegrations: 1 },
bazarr: { supportedIntegrations: ["bazarr"], maxIntegrations: 1 },
tracearr: { supportedIntegrations: ["tracearr"] },
speedtestTracker: { supportedIntegrations: ["speedtestTracker"] },
uptimeKuma: { supportedIntegrations: ["uptimeKuma"] },
audioStats: { supportedIntegrations: ["navidrome", "audiobookshelf"], maxIntegrations: 1 },
umami: { supportedIntegrations: ["umami"], maxIntegrations: 1 },
vpn: { supportedIntegrations: getIntegrationKindsByCategory("vpn") },
coolify: { supportedIntegrations: ["coolify", "mock"] },
"immich-serverStats": { supportedIntegrations: ["immich", "mock"], maxIntegrations: 1 },
"immich-albumCarousel": { supportedIntegrations: ["immich", "mock"], maxIntegrations: 1 },
paperlessNgx: { supportedIntegrations: ["paperlessNgx", "mock"], maxIntegrations: 1 },
patchmon: { supportedIntegrations: ["patchmon", "mock"], maxIntegrations: 1 },
bazarr: { supportedIntegrations: ["bazarr", "mock"], maxIntegrations: 1 },
tracearr: { supportedIntegrations: ["tracearr", "mock"] },
speedtestTracker: { supportedIntegrations: ["speedtestTracker", "mock"] },
uptimeKuma: { supportedIntegrations: ["uptimeKuma", "mock"] },
audioStats: { supportedIntegrations: ["navidrome", "audiobookshelf", "mock"], maxIntegrations: 1 },
umami: { supportedIntegrations: ["umami", "mock"], maxIntegrations: 1 },
vpn: { supportedIntegrations: [...getIntegrationKindsByCategory("vpn"), "mock"] },
ups: { supportedIntegrations: getIntegrationKindsByCategory("ups") },
archiveTeamWarrior: { supportedIntegrations: ["archiveTeamWarrior"], maxIntegrations: 1 },
anchorNote: { supportedIntegrations: ["anchor"], maxIntegrations: 1 },
traefik: { supportedIntegrations: ["traefik"] },
wud: { supportedIntegrations: ["wud"], maxIntegrations: 1 },
archiveTeamWarrior: { supportedIntegrations: ["archiveTeamWarrior", "mock"], maxIntegrations: 1 },
anchorNote: { supportedIntegrations: ["anchor", "mock"], maxIntegrations: 1 },
traefik: { supportedIntegrations: ["traefik", "mock"] },
wud: { supportedIntegrations: ["wud", "mock"], maxIntegrations: 1 },
} satisfies Partial<Record<WidgetKind, WidgetIntegrationConfig>>;
export type WidgetKindWithIntegration = keyof typeof widgetIntegrationConfigs;
@@ -206,6 +206,18 @@ export const generalWidgets: WidgetKind[] = defaultWidgetConfigs
.filter((config) => !config.skip)
.map((config) => config.kind);
export const featuredIntegrations: readonly IntegrationKind[] = [
"sonarr",
"radarr",
"prowlarr",
"sabNzbd",
"qBittorrent",
"seerr",
"jellyfin",
];
export const hiddenFromOnboarding = new Set<IntegrationKind>(["mock"]);
export const defaultBookmarkApps = [
{
name: "Homarr Docs",