Revert "fix: harden automatic mobile boards"

This reverts commit d0b9348b86.
This commit is contained in:
ajnart committed 2026-07-29 20:06:32 +02:00
1 parent 92a2be2b65
commit dba9a250ff
37 files changed
+137 -637

No files matched your search

+21 -5
View File
@@ -5,10 +5,10 @@ import { and, eq, inArray } from "@homarr/db";
import {
getServerSettingByKeyAsync,
getServerSettingsAsync,
mergeServerSettingByKeyAsync,
insertServerSettingByKeyAsync,
updateServerSettingByKeyAsync,
} from "@homarr/db/queries";
import { boards } from "@homarr/db/schema";
import { boards, serverSettings } from "@homarr/db/schema";
import type { ServerSettings } from "@homarr/server-settings";
import { defaultServerSettingsKeys } from "@homarr/server-settings";
import { settingsInitSchema } from "@homarr/validation/settings";
@@ -82,9 +82,17 @@ export const serverSettingsRouter = createTRPCRouter({
const current = await getServerSettingByKeyAsync(ctx.db, "board");
const next = { ...current, ...input };
await mergeServerSettingByKeyAsync(ctx.db, "board", next, input);
const existing = await ctx.db.query.serverSettings.findFirst({
where: eq(serverSettings.settingKey, "board"),
});
return await getServerSettingByKeyAsync(ctx.db, "board");
if (existing) {
await updateServerSettingByKeyAsync(ctx.db, "board", next);
} else {
await insertServerSettingByKeyAsync(ctx.db, "board", next);
}
return next;
}),
saveSettings: permissionRequiredProcedure
.requiresPermission("admin")
@@ -100,7 +108,15 @@ export const serverSettingsRouter = createTRPCRouter({
...current,
...input.value,
} as ServerSettings[keyof ServerSettings];
await mergeServerSettingByKeyAsync(ctx.db, input.settingsKey, next, input.value);
const existing = await ctx.db.query.serverSettings.findFirst({
where: eq(serverSettings.settingKey, input.settingsKey),
});
if (existing) {
await updateServerSettingByKeyAsync(ctx.db, input.settingsKey, next);
} else {
await insertServerSettingByKeyAsync(ctx.db, input.settingsKey, next);
}
}),
initSettings: onboardingProcedure
.requiresStep("settings")
@@ -3,7 +3,7 @@ import { describe, expect, test, vi } from "vitest";
import type { Session } from "@homarr/auth";
import { createId } from "@homarr/common";
import { boards, layouts, serverSettings } from "@homarr/db/schema";
import { boards, serverSettings } from "@homarr/db/schema";
import { createDb } from "@homarr/db/test";
import { defaultServerSettings, defaultServerSettingsKeys } from "@homarr/server-settings";
@@ -116,33 +116,6 @@ describe("saveSettings", () => {
},
]);
});
test("saveSettings should preserve concurrent partial updates", async () => {
const db = createDb();
const caller = serverSettingsRouter.createCaller({
db,
deviceType: undefined,
session: defaultSession,
});
await Promise.all([
caller.saveSettings({
settingsKey: "analytics",
value: { enableGeneral: false },
}),
caller.saveSettings({
settingsKey: "analytics",
value: { instanceId: "concurrent-instance" },
}),
]);
await expect(caller.getAll()).resolves.toMatchObject({
analytics: {
enableGeneral: false,
instanceId: "concurrent-instance",
},
});
});
});
describe("board settings API", () => {
@@ -164,12 +137,6 @@ describe("board settings API", () => {
deviceType: undefined,
session: defaultSession,
});
const boardId = createId();
await db.insert(boards).values({ id: boardId, name: "legacy", isPublic: false });
await db.insert(layouts).values([
{ id: createId(), boardId, name: "Base", columnCount: 12, breakpoint: 0 },
{ id: createId(), boardId, name: "Mobile", columnCount: 4, breakpoint: 480 },
]);
const legacyBoardSettings = {
homeBoardId: defaultServerSettings.board.homeBoardId,
mobileHomeBoardId: defaultServerSettings.board.mobileHomeBoardId,
@@ -181,10 +148,7 @@ describe("board settings API", () => {
value: stringify(legacyBoardSettings),
});
await expect(caller.getBoardSettings()).resolves.toStrictEqual({
...defaultServerSettings.board,
enableAutomaticMobileLayout: false,
});
await expect(caller.getBoardSettings()).resolves.toStrictEqual(defaultServerSettings.board);
});
test("updateBoardSettings should insert settings when defaults are not persisted", async () => {
@@ -249,25 +213,6 @@ describe("board settings API", () => {
]);
});
test("updateBoardSettings should preserve concurrent partial updates", async () => {
const db = createDb();
const caller = serverSettingsRouter.createCaller({
db,
deviceType: undefined,
session: defaultSession,
});
await Promise.all([
caller.updateBoardSettings({ forceDisableStatus: true }),
caller.updateBoardSettings({ enableStatusByDefault: false }),
]);
await expect(caller.getBoardSettings()).resolves.toMatchObject({
forceDisableStatus: true,
enableStatusByDefault: false,
});
});
test("updateBoardSettings should reject private home boards", async () => {
const db = createDb();
const caller = serverSettingsRouter.createCaller({
@@ -2,7 +2,7 @@ import { getIntegrationKindsByCategory } from "@homarr/definitions";
import { mediaReleaseRequestHandler } from "@homarr/request-handler/media-release";
import { createManyIntegrationMiddleware } from "../../middlewares/integration";
import { settleIntegrationQueriesWithProvenance } from "../../settle-integrations";
import { getIntegrationQueryProvenance, settleIntegrationQueries } from "../../settle-integrations";
import { createTRPCRouter, publicProcedure } from "../../trpc";
const mediaReleasesProcedure = publicProcedure.concat(
@@ -12,7 +12,7 @@ const mediaReleasesProcedure = publicProcedure.concat(
type MediaReleaseIntegration = Parameters<typeof mediaReleaseRequestHandler.handler>[0];
const getMediaReleasesWithProvenanceAsync = async (integrations: MediaReleaseIntegration[]) => {
const { results, ...provenance } = await settleIntegrationQueriesWithProvenance(
const results = await settleIntegrationQueries(
integrations,
async (integration) => {
const innerHandler = mediaReleaseRequestHandler.handler(integration, {});
@@ -40,7 +40,7 @@ const getMediaReleasesWithProvenanceAsync = async (integrations: MediaReleaseInt
return {
items,
...provenance,
...getIntegrationQueryProvenance(integrations.length, results),
};
};
@@ -11,7 +11,7 @@ import {
import { mediaRequestStatsRequestHandler } from "@homarr/request-handler/media-request-stats";
import { createManyIntegrationMiddleware, createOneIntegrationMiddleware } from "../../middlewares/integration";
import { settleIntegrationQueriesWithProvenance } from "../../settle-integrations";
import { getIntegrationQueryProvenance, settleIntegrationQueries } from "../../settle-integrations";
import { createTRPCRouter, protectedProcedure, publicProcedure } from "../../trpc";
const latestRequestsProcedure = publicProcedure
@@ -28,7 +28,7 @@ const getLatestRequestsWithProvenanceAsync = async (
integrations: MediaRequestIntegration[],
input: MediaRequestListInput,
) => {
const { results, ...provenance } = await settleIntegrationQueriesWithProvenance(
const results = await settleIntegrationQueries(
integrations,
async (integration) => {
const { data, isStale } = await mediaRequestListRequestHandler
@@ -61,12 +61,12 @@ const getLatestRequestsWithProvenanceAsync = async (
return {
items,
...provenance,
...getIntegrationQueryProvenance(integrations.length, results),
};
};
const getRequestStatsWithProvenanceAsync = async (integrations: MediaRequestStatsIntegration[]) => {
const { results, ...provenance } = await settleIntegrationQueriesWithProvenance(
const results = await settleIntegrationQueries(
integrations,
async (integration) => {
const { data, isStale } = await mediaRequestStatsRequestHandler
@@ -92,7 +92,7 @@ const getRequestStatsWithProvenanceAsync = async (integrations: MediaRequestStat
)
.toSorted(({ requestCount: countA }, { requestCount: countB }) => countB - countA),
integrations: results.map((result) => result.integration),
...provenance,
...getIntegrationQueryProvenance(integrations.length, results),
};
};