feat(widgets): consolidate integration metadata + shared response caching (#6691)

This commit is contained in:
Thomas authored and GitHub committed 2026-08-30 18:38:07 +02:00
1 parent 7d1d9062ed
commit 8d8dec5749
206 files changed
+3893 -1946

No files matched your search

+16 -7
View File
@@ -41,6 +41,14 @@ const defaultSession = {
expires: new Date().toISOString(),
} satisfies Session;
const integrationUseSession = {
...defaultSession,
user: {
...defaultSession.user,
permissions: ["integration-use-all"],
},
} satisfies Session;
// Mock the auth module to return an empty session
vi.mock("@homarr/auth", () => ({ auth: () => ({}) as Session }));
@@ -698,7 +706,8 @@ describe("duplicateBoard should preserve protected layout invariants", () => {
},
};
const caller = boardRouter.createCaller({ db, deviceType: undefined, session });
const { boardId } = await createFullBoardAsync(db, "source");
const { boardId, integrationId } = await createFullBoardAsync(db, "source");
await db.delete(integrationItems).where(eq(integrationItems.integrationId, integrationId));
const result = await caller.duplicateBoard({ id: boardId, name: "copy" });
@@ -1195,7 +1204,7 @@ describe("saveBoard should save full board", () => {
it("should remove integration reference when not present in input", async () => {
const spy = vi.spyOn(boardAccess, "throwIfActionForbiddenAsync");
const db = createDb();
const caller = boardRouter.createCaller({ db, deviceType: undefined, session: defaultSession });
const caller = boardRouter.createCaller({ db, deviceType: undefined, session: integrationUseSession });
const anotherIntegration = {
id: createId(),
kind: "adGuardHome",
@@ -1219,8 +1228,8 @@ describe("saveBoard should save full board", () => {
items: [
{
id: itemId,
kind: "clock",
options: { is24HourFormat: true },
kind: "dnsHoleSummary",
options: { usePiHoleColors: true, layout: "grid" },
integrationIds: [anotherIntegration.id],
layouts: [
{
@@ -1526,7 +1535,7 @@ describe("saveBoard should save full board", () => {
it("should add integration reference when present in input", async () => {
const spy = vi.spyOn(boardAccess, "throwIfActionForbiddenAsync");
const db = createDb();
const caller = boardRouter.createCaller({ db, deviceType: undefined, session: defaultSession });
const caller = boardRouter.createCaller({ db, deviceType: undefined, session: integrationUseSession });
const integration = {
id: createId(),
kind: "plex",
@@ -1550,8 +1559,8 @@ describe("saveBoard should save full board", () => {
items: [
{
id: itemId,
kind: "clock",
options: { is24HourFormat: true },
kind: "mediaServer",
options: { showOnlyPlaying: true, showBitrate: true, showLocation: true },
integrationIds: [integration.id],
layouts: [
{
@@ -1,7 +1,8 @@
import { describe, expect, test, vi } from "vitest";
import * as homarrDefinitions from "@homarr/definitions";
import * as homarrIntegrations from "@homarr/integrations";
import type * as homarrIntegrations from "@homarr/integrations";
import * as homarrIntegrationFactory from "@homarr/integrations/factory";
import { testConnectionAsync } from "../../integration/integration-test-connection";
@@ -18,7 +19,7 @@ vi.mock("@homarr/common/server", async (importActual) => {
describe("testConnectionAsync should run test connection of integration", () => {
test("with input of only form secrets matching api key kind it should use form apiKey", async () => {
// Arrange
const factorySpy = vi.spyOn(homarrIntegrations, "createIntegrationAsync");
const factorySpy = vi.spyOn(homarrIntegrationFactory, "createIntegrationAsync");
const optionsSpy = vi.spyOn(homarrDefinitions, "getAllSecretKindOptions");
factorySpy.mockReturnValue(
Promise.resolve({
@@ -61,7 +62,7 @@ describe("testConnectionAsync should run test connection of integration", () =>
test("with input of only null form secrets and the required db secrets matching api key kind it should use db apiKey", async () => {
// Arrange
const factorySpy = vi.spyOn(homarrIntegrations, "createIntegrationAsync");
const factorySpy = vi.spyOn(homarrIntegrationFactory, "createIntegrationAsync");
const optionsSpy = vi.spyOn(homarrDefinitions, "getAllSecretKindOptions");
factorySpy.mockReturnValue(
Promise.resolve({
@@ -111,7 +112,7 @@ describe("testConnectionAsync should run test connection of integration", () =>
test("with input of form and db secrets matching api key kind it should use form apiKey", async () => {
// Arrange
const factorySpy = vi.spyOn(homarrIntegrations, "createIntegrationAsync");
const factorySpy = vi.spyOn(homarrIntegrationFactory, "createIntegrationAsync");
const optionsSpy = vi.spyOn(homarrDefinitions, "getAllSecretKindOptions");
factorySpy.mockReturnValue(
Promise.resolve({
@@ -161,7 +162,7 @@ describe("testConnectionAsync should run test connection of integration", () =>
test("with input of form apiKey and db secrets for username and password it should use form apiKey when both is allowed", async () => {
// Arrange
const factorySpy = vi.spyOn(homarrIntegrations, "createIntegrationAsync");
const factorySpy = vi.spyOn(homarrIntegrationFactory, "createIntegrationAsync");
const optionsSpy = vi.spyOn(homarrDefinitions, "getAllSecretKindOptions");
factorySpy.mockReturnValue(
Promise.resolve({
@@ -215,7 +216,7 @@ describe("testConnectionAsync should run test connection of integration", () =>
test("with input of null form apiKey and db secrets for username and password it should use db username and password when both is allowed", async () => {
// Arrange
const factorySpy = vi.spyOn(homarrIntegrations, "createIntegrationAsync");
const factorySpy = vi.spyOn(homarrIntegrationFactory, "createIntegrationAsync");
const optionsSpy = vi.spyOn(homarrDefinitions, "getAllSecretKindOptions");
factorySpy.mockReturnValue(
Promise.resolve({