Merge branch 'dev' into fix/beszel-widget-transparency-and-errors

This commit is contained in:
Thomas authored and GitHub committed 2026-06-19 21:53:31 +02:00
commit 10cc29c3a5
70 files changed
+1930 -1254

No files matched your search

+1
View File
@@ -24,6 +24,7 @@
"typecheck": "tsc --noEmit"
},
"dependencies": {
"@homarr/analytics": "workspace:^0.1.0",
"@homarr/auth": "workspace:^0.1.0",
"@homarr/common": "workspace:^0.1.0",
"@homarr/core": "workspace:^0.1.0",
+1
View File
@@ -28,6 +28,7 @@ export const appRouter = createTRPCRouter({
updateChecker: lazy(() => import("./router/update-checker").then((mod) => mod.updateCheckerRouter)),
certificates: lazy(() => import("./router/certificates/certificate-router").then((mod) => mod.certificateRouter)),
bangs: lazy(() => import("./router/bangs/bangs-router").then((mod) => mod.bangsRouter)),
analytics: lazy(() => import("./router/analytics").then((mod) => mod.analyticsRouter)),
info: lazy(() => import("./router/info").then((mod) => mod.infoRouter)),
customWidget: lazy(() => import("./router/custom-widget/custom-widget-router").then((mod) => mod.customWidgetRouter)),
});
+51
View File
@@ -0,0 +1,51 @@
import { TRPCError } from "@trpc/server";
import z from "zod/v4";
import { sendServerAnalyticsAsync, trackEvent } from "@homarr/analytics";
import { env } from "@homarr/common/env";
import { db } from "@homarr/db";
import { getServerSettingByKeyAsync } from "@homarr/db/queries";
import { createTRPCRouter, permissionRequiredProcedure, protectedProcedure } from "../trpc";
const getInstanceId = async (): Promise<string | null> => {
if (env.NO_EXTERNAL_CONNECTION) return null;
const settings = await getServerSettingByKeyAsync(db, "analytics");
if (!settings.enableGeneral) return null;
return settings.instanceId;
};
export const analyticsRouter = createTRPCRouter({
sendAnalytics: permissionRequiredProcedure.requiresPermission("admin").mutation(async () => {
if (env.NO_EXTERNAL_CONNECTION) {
throw new TRPCError({ code: "PRECONDITION_FAILED", message: "External connections are disabled" });
}
return { status: await sendServerAnalyticsAsync() };
}),
trackFeature: protectedProcedure
.input(
z.object({
feature: z.string().max(128),
properties: z.record(z.string(), z.unknown()).optional(),
}),
)
.mutation(async ({ input, ctx }) => {
const instanceId = await getInstanceId();
if (!instanceId) return;
trackEvent(instanceId, `feature:${input.feature}`, {
...input.properties,
userId: ctx.session.user.id,
});
}),
heartbeat: protectedProcedure.mutation(async ({ ctx }) => {
const instanceId = await getInstanceId();
if (!instanceId) return;
trackEvent(instanceId, "user-active", {
userId: ctx.session.user.id,
});
}),
});
+7 -6
View File
@@ -24,17 +24,18 @@ export const serverSettingsRouter = createTRPCRouter({
}),
)
.mutation(async ({ ctx, input }) => {
await updateServerSettingByKeyAsync(
ctx.db,
input.settingsKey,
input.value as ServerSettings[keyof ServerSettings],
);
const current = await getServerSettingByKeyAsync(ctx.db, input.settingsKey);
await updateServerSettingByKeyAsync(ctx.db, input.settingsKey, {
...current,
...input.value,
} as ServerSettings[keyof ServerSettings]);
}),
initSettings: onboardingProcedure
.requiresStep("settings")
.input(settingsInitSchema)
.mutation(async ({ ctx, input }) => {
await updateServerSettingByKeyAsync(ctx.db, "analytics", input.analytics);
const currentAnalytics = await getServerSettingByKeyAsync(ctx.db, "analytics");
await updateServerSettingByKeyAsync(ctx.db, "analytics", { ...currentAnalytics, ...input.analytics });
await updateServerSettingByKeyAsync(ctx.db, "crawlingAndIndexing", input.crawlingAndIndexing);
await nextOnboardingStepAsync(ctx.db, undefined);
}),
@@ -75,9 +75,6 @@ describe("saveSettings", () => {
settingsKey: "analytics",
value: {
enableGeneral: true,
enableWidgetData: true,
enableIntegrationData: true,
enableUserData: true,
},
});
@@ -87,9 +84,7 @@ describe("saveSettings", () => {
settingKey: "analytics",
value: SuperJSON.stringify({
enableGeneral: true,
enableWidgetData: true,
enableIntegrationData: true,
enableUserData: true,
instanceId: null,
}),
},
]);