Merge branch 'dev' into feat/add-integration-from-dashboard

This commit is contained in:
Thomas authored and GitHub committed 2026-05-16 11:38:11 +02:00
commit dd3cb3956d
91 files changed
+16964 -7653

No files matched your search

+19 -16
View File
@@ -2,33 +2,36 @@ import { observable } from "@trpc/server/observable";
import z from "zod/v4";
import { createLogger } from "@homarr/core/infrastructure/logs";
import { jobGroupKeys, jobNameSchema } from "@homarr/cron-job-api";
import { cronJobApi } from "@homarr/cron-job-api/client";
import type { TaskStatus } from "@homarr/cron-job-status";
import { createCronJobStatusChannel } from "@homarr/cron-job-status";
import { jobGroup } from "@homarr/cron-jobs";
import { JobManager } from "@homarr/cron-jobs/job-manager";
import { createTRPCRouter, permissionRequiredProcedure } from "../trpc";
const jobGroupKeys = jobGroup.getKeys();
const jobNameSchema = z.enum(jobGroup.getKeys());
const logger = createLogger({ module: "cronJobsRouter" });
export const cronJobsRouter = createTRPCRouter({
triggerJob: permissionRequiredProcedure
.requiresPermission("admin")
.input(jobNameSchema)
.mutation(async ({ input }) => {
await cronJobApi.trigger.mutate(input);
.mutation(async ({ input, ctx }) => {
await new JobManager(ctx.db, jobGroup).triggerAsync(input);
}),
startJob: permissionRequiredProcedure
.requiresPermission("admin")
.input(jobNameSchema)
.mutation(async ({ input }) => {
await cronJobApi.start.mutate(input);
.mutation(async ({ input, ctx }) => {
await new JobManager(ctx.db, jobGroup).startAsync(input);
}),
stopJob: permissionRequiredProcedure
.requiresPermission("admin")
.input(jobNameSchema)
.mutation(async ({ input }) => {
await cronJobApi.stop.mutate(input);
.mutation(({ input, ctx }) => {
new JobManager(ctx.db, jobGroup).stop(input);
}),
updateJobInterval: permissionRequiredProcedure
.requiresPermission("admin")
@@ -38,23 +41,23 @@ export const cronJobsRouter = createTRPCRouter({
cron: z.string(),
}),
)
.mutation(async ({ input }) => {
await cronJobApi.updateInterval.mutate(input);
.mutation(async ({ input, ctx }) => {
await new JobManager(ctx.db, jobGroup).updateIntervalAsync(input.name, input.cron);
}),
disableJob: permissionRequiredProcedure
.requiresPermission("admin")
.input(jobNameSchema)
.mutation(async ({ input }) => {
await cronJobApi.disable.mutate(input);
.mutation(async ({ input, ctx }) => {
await new JobManager(ctx.db, jobGroup).disableAsync(input);
}),
enableJob: permissionRequiredProcedure
.requiresPermission("admin")
.input(jobNameSchema)
.mutation(async ({ input }) => {
await cronJobApi.enable.mutate(input);
.mutation(async ({ input, ctx }) => {
await new JobManager(ctx.db, jobGroup).enableAsync(input);
}),
getJobs: permissionRequiredProcedure.requiresPermission("admin").query(async () => {
return await cronJobApi.getAll.query();
getJobs: permissionRequiredProcedure.requiresPermission("admin").query(async ({ ctx }) => {
return await new JobManager(ctx.db, jobGroup).getAllAsync();
}),
subscribeToStatusUpdates: permissionRequiredProcedure.requiresPermission("admin").subscription(() => {
return observable<TaskStatus>((emit) => {
@@ -138,6 +138,7 @@ const getContainerOrThrowAsync = async (id: string) => {
interface DockerContainer {
name: string;
id: string;
host: string;
state: ContainerState;
image: string;
ports: Port[] | undefined;
+23 -1
View File
@@ -2,6 +2,8 @@ import { observable } from "@trpc/server/observable";
import { z } from "zod/v4";
import type { Modify } from "@homarr/common/types";
import { createLogger } from "@homarr/core/infrastructure/logs";
import { ErrorWithMetadata } from "@homarr/core/infrastructure/logs/error";
import type { Integration } from "@homarr/db/schema";
import type { IntegrationKindByCategory } from "@homarr/definitions";
import { getIntegrationKindsByCategory } from "@homarr/definitions";
@@ -12,6 +14,8 @@ import { calendarMonthRequestHandler } from "@homarr/request-handler/calendar";
import { createManyIntegrationMiddleware } from "../../middlewares/integration";
import { createTRPCRouter, publicProcedure } from "../../trpc";
const logger = createLogger({ module: "calendarRouter" });
export const calendarRouter = createTRPCRouter({
findAllEvents: publicProcedure
.input(
@@ -24,7 +28,7 @@ export const calendarRouter = createTRPCRouter({
)
.concat(createManyIntegrationMiddleware("query", ...getIntegrationKindsByCategory("calendar")))
.query(async ({ ctx, input }) => {
return await Promise.all(
const settled = await Promise.allSettled(
ctx.integrations.map(async (integration) => {
const { integrationIds: _integrationIds, ...handlerInput } = input;
const innerHandler = calendarMonthRequestHandler.handler(integration, handlerInput);
@@ -40,6 +44,24 @@ export const calendarRouter = createTRPCRouter({
};
}),
);
return settled.flatMap((result, index) => {
if (result.status === "fulfilled") {
return [result.value];
}
const integration = ctx.integrations[index];
logger.warn(
new ErrorWithMetadata(
"Calendar integration request failed; skipping events for this integration",
{
integrationId: integration?.id,
integrationKind: integration?.kind,
},
{ cause: result.reason },
),
);
return [];
});
}),
subscribeToEvents: publicProcedure
.input(