From 31a7559b86c421fb4d8d7c168aa1915807829a1c Mon Sep 17 00:00:00 2001 From: Meier Lukas Date: Sat, 7 Dec 2024 22:21:40 +0100 Subject: [PATCH] fix: two issues with board rename and iframes (#2215) --- package.json | 2 +- src/server/api/routers/board.ts | 64 ++++++++++++++++++------------- src/validations/boards.ts | 11 +++++- src/widgets/iframe/IFrameTile.tsx | 1 + 4 files changed, 48 insertions(+), 30 deletions(-) diff --git a/package.json b/package.json index bab2389e3fb..cf60568f2ef 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homarr", - "version": "0.15.7", + "version": "0.15.8", "description": "Homarr - A homepage for your server.", "license": "MIT", "repository": { diff --git a/src/server/api/routers/board.ts b/src/server/api/routers/board.ts index 7426e763dd6..7971531c230 100644 --- a/src/server/api/routers/board.ts +++ b/src/server/api/routers/board.ts @@ -1,29 +1,33 @@ import { TRPCError } from '@trpc/server'; +import Consola from 'consola'; import fs from 'fs'; import { z } from 'zod'; -import Consola from 'consola'; import { getDefaultBoardAsync } from '~/server/db/queries/userSettings'; import { configExists } from '~/tools/config/configExists'; import { getConfig } from '~/tools/config/getConfig'; import { getFrontendConfig } from '~/tools/config/getFrontendConfig'; +import { writeConfig } from '~/tools/config/writeConfig'; import { generateDefaultApp } from '~/tools/shared/app'; +import { configNameSchema } from '~/validations/boards'; import { adminProcedure, createTRPCRouter, protectedProcedure } from '../trpc'; -import { writeConfig } from '~/tools/config/writeConfig'; -import { configNameSchema } from '~/validations/boards'; export const boardRouter = createTRPCRouter({ all: protectedProcedure .meta({ openapi: { method: 'GET', path: '/boards/all', tags: ['board'] } }) .input(z.void()) - .output(z.array(z.object({ - name: z.string(), - allowGuests: z.boolean(), - countApps: z.number().min(0), - countWidgets: z.number().min(0), - countCategories: z.number().min(0), - isDefaultForUser: z.boolean(), - }))) + .output( + z.array( + z.object({ + name: z.string(), + allowGuests: z.boolean(), + countApps: z.number().min(0), + countWidgets: z.number().min(0), + countCategories: z.number().min(0), + isDefaultForUser: z.boolean(), + }) + ) + ) .query(async ({ ctx }) => { const files = fs.readdirSync('./data/configs').filter((file) => file.endsWith('.json')); @@ -44,7 +48,7 @@ export const boardRouter = createTRPCRouter({ countCategories: config.categories.length, isDefaultForUser: name === defaultBoard, }; - }), + }) ); }), addAppsForContainers: adminProcedure @@ -58,9 +62,9 @@ export const boardRouter = createTRPCRouter({ name: z.string(), icon: z.string().optional(), port: z.number().optional(), - }), + }) ), - }), + }) ) .mutation(async ({ input }) => { if (!configExists(input.boardName)) { @@ -101,12 +105,14 @@ export const boardRouter = createTRPCRouter({ const targetPath = `data/configs/${input.boardName}.json`; fs.writeFileSync(targetPath, JSON.stringify(newConfig, null, 2), 'utf8'); }), - renameBoard: protectedProcedure + renameBoard: adminProcedure .meta({ openapi: { method: 'PUT', path: '/boards/rename', tags: ['board'] } }) - .input(z.object({ - oldName: z.string(), - newName: z.string().min(1), - })) + .input( + z.object({ + oldName: configNameSchema, + newName: configNameSchema, + }) + ) .output(z.void()) .mutation(async ({ input }) => { if (input.oldName === 'default') { @@ -141,15 +147,19 @@ export const boardRouter = createTRPCRouter({ fs.unlinkSync(targetPath); Consola.info(`Deleted ${input.oldName} from file system`); }), - duplicateBoard: protectedProcedure + duplicateBoard: adminProcedure .meta({ openapi: { method: 'POST', path: '/boards/duplicate', tags: ['board'] } }) - .input(z.object({ - boardName: z.string(), - })) + .input( + z.object({ + boardName: z.string(), + }) + ) .output(z.void()) .mutation(async ({ input }) => { if (!configExists(input.boardName)) { - Consola.error(`Tried to duplicate ${input.boardName} but this configuration does not exist.`); + Consola.error( + `Tried to duplicate ${input.boardName} but this configuration does not exist.` + ); throw new TRPCError({ code: 'NOT_FOUND', message: 'Board not found', @@ -164,7 +174,7 @@ export const boardRouter = createTRPCRouter({ config.configProperties.name = targetName; writeConfig(config); - Consola.info(`Wrote config to name '${targetName}'`) + Consola.info(`Wrote config to name '${targetName}'`); }), }); @@ -185,7 +195,7 @@ const attemptGenerateDuplicateName = (baseName: string, maxAttempts: number) => code: 'CONFLICT', message: 'Board conflicts with an existing board', }); -} +}; const generateDuplicateName = (baseName: string, increment: number) => { const result = duplicationName.exec(baseName); @@ -197,4 +207,4 @@ const generateDuplicateName = (baseName: string, increment: number) => { } return `${baseName} (2)`; -} +}; diff --git a/src/validations/boards.ts b/src/validations/boards.ts index be3347cc1a1..b66f2eb7ddc 100644 --- a/src/validations/boards.ts +++ b/src/validations/boards.ts @@ -1,8 +1,15 @@ import { DEFAULT_THEME, MANTINE_COLORS, MantineColor } from '@mantine/core'; import { z } from 'zod'; -import { BackgroundImageAttachment, BackgroundImageRepeat, BackgroundImageSize } from '~/types/settings'; +import { + BackgroundImageAttachment, + BackgroundImageRepeat, + BackgroundImageSize, +} from '~/types/settings'; -export const configNameSchema = z.string().regex(/^[a-zA-Z0-9-_\s()]+$/); +export const configNameSchema = z + .string() + .regex(/^[a-zA-Z0-9-_\s()]+$/) + .min(1); export const createBoardSchemaValidation = z.object({ name: configNameSchema, diff --git a/src/widgets/iframe/IFrameTile.tsx b/src/widgets/iframe/IFrameTile.tsx index 86b32c89c1b..ab3f1790d71 100644 --- a/src/widgets/iframe/IFrameTile.tsx +++ b/src/widgets/iframe/IFrameTile.tsx @@ -116,6 +116,7 @@ function IFrameTile({ widget }: IFrameTileProps) { return (