Merge remote-tracking branch 'origin/release/v2' into feat/v2-release-readiness
This commit is contained in:
commit
8bf8c5e0ea
47 files changed
+2176
-145
No files matched your search
@@ -454,7 +454,7 @@ export const userRouter = createTRPCRouter({
|
||||
}
|
||||
|
||||
const user = await ctx.db.query.users.findFirst({
|
||||
columns: { email: true, provider: true },
|
||||
columns: { name: true, email: true, provider: true },
|
||||
where: eq(users.id, input.id),
|
||||
});
|
||||
|
||||
@@ -472,6 +472,13 @@ export const userRouter = createTRPCRouter({
|
||||
});
|
||||
}
|
||||
|
||||
if (isDemoMode && input.name !== user.name) {
|
||||
throw new TRPCError({
|
||||
code: "FORBIDDEN",
|
||||
message: "Username changes are disabled in demo mode",
|
||||
});
|
||||
}
|
||||
|
||||
await checkUsernameAlreadyTakenAndThrowAsync(ctx.db, "credentials", input.name, input.id);
|
||||
|
||||
const emailDirty = input.email && user.email !== input.email;
|
||||
@@ -497,6 +504,13 @@ export const userRouter = createTRPCRouter({
|
||||
mcp: { enabled: true, description: "Delete a user by ID. REQUIRED: userId (string)" },
|
||||
})
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
if (isDemoMode) {
|
||||
throw new TRPCError({
|
||||
code: "FORBIDDEN",
|
||||
message: "User deletion is disabled in demo mode",
|
||||
});
|
||||
}
|
||||
|
||||
// Only admins and user itself can delete a user
|
||||
if (ctx.session.user.id !== input.userId && !ctx.session.user.permissions.includes("admin")) {
|
||||
throw new TRPCError({
|
||||
@@ -519,6 +533,13 @@ export const userRouter = createTRPCRouter({
|
||||
},
|
||||
})
|
||||
.mutation(async ({ ctx, input }) => {
|
||||
if (isDemoMode) {
|
||||
throw new TRPCError({
|
||||
code: "FORBIDDEN",
|
||||
message: "Password changes are disabled in demo mode",
|
||||
});
|
||||
}
|
||||
|
||||
const user = ctx.session.user;
|
||||
// Only admins can change other users' passwords
|
||||
if (!user.permissions.includes("admin") && user.id !== input.userId) {
|
||||
|
||||
@@ -46,4 +46,5 @@ export const widgetRouter = createTRPCRouter({
|
||||
customApi: lazy(() => import("./custom-api").then((mod) => mod.customApiRouter)),
|
||||
secrets: lazy(() => import("./widget-secrets").then((mod) => mod.widgetSecretsRouter)),
|
||||
wud: lazy(() => import("./wud").then((mod) => mod.wudRouter)),
|
||||
llamacpp: lazy(() => import("./llamacpp").then((mod) => mod.llamacppRouter)),
|
||||
});
|
||||
@@ -0,0 +1,29 @@
|
||||
import { llamacppStatsRequestHandler } from "@homarr/request-handler/llamacpp";
|
||||
import { mockWidgetData } from "@homarr/integrations";
|
||||
|
||||
import { createOneWidgetIntegrationMiddleware } from "../../middlewares/integration";
|
||||
import { createTRPCRouter, publicProcedure } from "../../trpc";
|
||||
|
||||
export const llamacppRouter = createTRPCRouter({
|
||||
getStats: publicProcedure
|
||||
.meta({
|
||||
mcp: {
|
||||
enabled: true,
|
||||
description:
|
||||
"Returns health, loaded model and Prometheus metrics (generation speed, token counts, request queue) from a llama.cpp (llama-server) integration. REQUIRED: integrationId from integration_all. The caller needs query permission for that integration.",
|
||||
},
|
||||
})
|
||||
.concat(createOneWidgetIntegrationMiddleware("query", "llamacpp"))
|
||||
.query(async ({ ctx }) => {
|
||||
if (ctx.integration.kind === "mock") {
|
||||
return { stats: mockWidgetData.llamacpp, updatedAt: new Date(mockWidgetData.timestamp) };
|
||||
}
|
||||
const handler = llamacppStatsRequestHandler.handler({ ...ctx.integration, kind: "llamacpp" }, {});
|
||||
const { data, timestamp } = await handler.getDataAsync();
|
||||
|
||||
return {
|
||||
stats: data,
|
||||
updatedAt: timestamp,
|
||||
};
|
||||
}),
|
||||
});
|
||||
Reference in new issue
Block a user