mirror of
				https://github.com/ajnart/homarr.git
				synced 2025-11-03 12:05:57 +01:00 
			
		
		
		
	fix: two issues with board rename and iframes (#2215)
This commit is contained in:
		@@ -1,6 +1,6 @@
 | 
			
		||||
{
 | 
			
		||||
  "name": "homarr",
 | 
			
		||||
  "version": "0.15.7",
 | 
			
		||||
  "version": "0.15.8",
 | 
			
		||||
  "description": "Homarr - A homepage for your server.",
 | 
			
		||||
  "license": "MIT",
 | 
			
		||||
  "repository": {
 | 
			
		||||
 
 | 
			
		||||
@@ -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({
 | 
			
		||||
    .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({
 | 
			
		||||
    .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)`;
 | 
			
		||||
}
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
@@ -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,
 | 
			
		||||
 
 | 
			
		||||
@@ -116,6 +116,7 @@ function IFrameTile({ widget }: IFrameTileProps) {
 | 
			
		||||
  return (
 | 
			
		||||
    <Container h="100%" w="100%" maw="initial" mah="initial" p={0}>
 | 
			
		||||
      <iframe
 | 
			
		||||
        sandbox="" // Disables js execution see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe#sandbox
 | 
			
		||||
        className={classes.iframe}
 | 
			
		||||
        src={widget.properties.embedUrl}
 | 
			
		||||
        title="widget iframe"
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user