chore(release): automatic release v1.43.3

This commit is contained in:
homarr-releases[bot]
2025-11-14 19:15:12 +00:00
committed by GitHub
52 changed files with 1282 additions and 759 deletions

View File

@@ -25,8 +25,9 @@ const nextConfig: NextConfig = {
typescript: { ignoreBuildErrors: true }, typescript: { ignoreBuildErrors: true },
/** /**
* dockerode is required in the external server packages because of https://github.com/homarr-labs/homarr/issues/612 * dockerode is required in the external server packages because of https://github.com/homarr-labs/homarr/issues/612
* isomorphic-dompurify and jsdom are required, see https://github.com/kkomelin/isomorphic-dompurify/issues/356
*/ */
serverExternalPackages: ["dockerode"], serverExternalPackages: ["dockerode", "isomorphic-dompurify", "jsdom"],
experimental: { experimental: {
optimizePackageImports: ["@mantine/core", "@mantine/hooks", "@tabler/icons-react"], optimizePackageImports: ["@mantine/core", "@mantine/hooks", "@tabler/icons-react"],
turbopackFileSystemCacheForDev: true, turbopackFileSystemCacheForDev: true,

View File

@@ -50,15 +50,15 @@
"@homarr/ui": "workspace:^0.1.0", "@homarr/ui": "workspace:^0.1.0",
"@homarr/validation": "workspace:^0.1.0", "@homarr/validation": "workspace:^0.1.0",
"@homarr/widgets": "workspace:^0.1.0", "@homarr/widgets": "workspace:^0.1.0",
"@mantine/colors-generator": "^8.3.6", "@mantine/colors-generator": "^8.3.7",
"@mantine/core": "^8.3.6", "@mantine/core": "^8.3.7",
"@mantine/dropzone": "^8.3.6", "@mantine/dropzone": "^8.3.7",
"@mantine/hooks": "^8.3.6", "@mantine/hooks": "^8.3.7",
"@mantine/modals": "^8.3.6", "@mantine/modals": "^8.3.7",
"@mantine/tiptap": "^8.3.6", "@mantine/tiptap": "^8.3.7",
"@million/lint": "1.0.14", "@million/lint": "1.0.14",
"@tabler/icons-react": "^3.35.0", "@tabler/icons-react": "^3.35.0",
"@tanstack/react-query": "^5.90.6", "@tanstack/react-query": "^5.90.7",
"@tanstack/react-query-devtools": "^5.90.2", "@tanstack/react-query-devtools": "^5.90.2",
"@tanstack/react-query-next-experimental": "^5.90.2", "@tanstack/react-query-next-experimental": "^5.90.2",
"@trpc/client": "^11.7.1", "@trpc/client": "^11.7.1",
@@ -75,6 +75,7 @@
"dotenv": "^17.2.3", "dotenv": "^17.2.3",
"flag-icons": "^7.5.0", "flag-icons": "^7.5.0",
"glob": "^11.0.3", "glob": "^11.0.3",
"isomorphic-dompurify": "^2.32.0",
"jotai": "^2.15.1", "jotai": "^2.15.1",
"mantine-react-table": "2.0.0-beta.9", "mantine-react-table": "2.0.0-beta.9",
"next": "16.0.1", "next": "16.0.1",
@@ -86,7 +87,7 @@
"react-simple-code-editor": "^0.14.1", "react-simple-code-editor": "^0.14.1",
"sass": "^1.93.3", "sass": "^1.93.3",
"superjson": "2.2.5", "superjson": "2.2.5",
"swagger-ui-react": "^5.30.1", "swagger-ui-react": "^5.30.2",
"use-deep-compare-effect": "^1.8.1", "use-deep-compare-effect": "^1.8.1",
"zod": "^4.1.12" "zod": "^4.1.12"
}, },
@@ -95,13 +96,13 @@
"@homarr/prettier-config": "workspace:^0.1.0", "@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0",
"@types/chroma-js": "3.1.2", "@types/chroma-js": "3.1.2",
"@types/node": "^24.9.2", "@types/node": "^24.10.0",
"@types/prismjs": "^1.26.5", "@types/prismjs": "^1.26.5",
"@types/react": "19.2.2", "@types/react": "19.2.2",
"@types/react-dom": "19.2.2", "@types/react-dom": "19.2.2",
"@types/swagger-ui-react": "^5.18.0", "@types/swagger-ui-react": "^5.18.0",
"concurrently": "^9.2.1", "concurrently": "^9.2.1",
"eslint": "^9.39.0", "eslint": "^9.39.1",
"node-loader": "^2.1.0", "node-loader": "^2.1.0",
"prettier": "^3.6.2", "prettier": "^3.6.2",
"typescript": "^5.9.3" "typescript": "^5.9.3"

View File

@@ -1,6 +1,6 @@
"use client"; "use client";
import { startTransition, useCallback, useMemo, useState } from "react"; import { startTransition, useCallback, useState } from "react";
import { import {
Badge, Badge,
Button, Button,
@@ -20,8 +20,9 @@ import { IconPlus, IconUserCheck } from "@tabler/icons-react";
import { z } from "zod/v4"; import { z } from "zod/v4";
import { clientApi } from "@homarr/api/client"; import { clientApi } from "@homarr/api/client";
import { everyoneGroup, groupPermissions } from "@homarr/definitions";
import type { GroupPermissionKey } from "@homarr/definitions"; import type { GroupPermissionKey } from "@homarr/definitions";
import { everyoneGroup, groupPermissions } from "@homarr/definitions";
import type { IsValid } from "@homarr/form";
import { useZodForm } from "@homarr/form"; import { useZodForm } from "@homarr/form";
import { useModalAction } from "@homarr/modals"; import { useModalAction } from "@homarr/modals";
import { showErrorNotification } from "@homarr/notifications"; import { showErrorNotification } from "@homarr/notifications";
@@ -113,11 +114,9 @@ export const UserCreateStepperComponent = ({ initialGroups }: UserCreateStepperC
}, },
); );
const allForms = useMemo(() => [generalForm, securityForm, groupsForm], [generalForm, securityForm, groupsForm]); const allForms = [generalForm, securityForm, groupsForm];
const isValidCallback: IsValid<unknown> | undefined = allForms[active]?.isValid;
const activeForm = allForms[active]; const currentFormValid = isValidCallback?.() ?? true;
const isCurrentFormValid = activeForm ? activeForm.isValid : () => true;
const canNavigateToNextStep = isCurrentFormValid();
const controlledGoToNextStep = useCallback(async () => { const controlledGoToNextStep = useCallback(async () => {
if (active + 1 === stepperMax) { if (active + 1 === stepperMax) {
@@ -218,7 +217,7 @@ export const UserCreateStepperComponent = ({ initialGroups }: UserCreateStepperC
</Stepper.Completed> </Stepper.Completed>
</Stepper> </Stepper>
<StepperNavigationComponent <StepperNavigationComponent
hasNext={hasNext && canNavigateToNextStep} hasNext={hasNext && currentFormValid}
hasPrevious={hasPrevious} hasPrevious={hasPrevious}
isComplete={active === stepperMax} isComplete={active === stepperMax}
isLoadingNextStep={isPending} isLoadingNextStep={isPending}

View File

@@ -1,6 +1,7 @@
import { notFound } from "next/navigation"; import { notFound } from "next/navigation";
import { NextResponse } from "next/server"; import { NextResponse } from "next/server";
import type { NextRequest } from "next/server"; import type { NextRequest } from "next/server";
import DOMPurify from "isomorphic-dompurify";
import { db, eq } from "@homarr/db"; import { db, eq } from "@homarr/db";
import { medias } from "@homarr/db/schema"; import { medias } from "@homarr/db/schema";
@@ -19,11 +20,24 @@ export async function GET(_req: NextRequest, props: { params: Promise<{ id: stri
notFound(); notFound();
} }
let content = new Uint8Array(image.content);
// Sanitize SVG content to prevent XSS attacks
if (image.contentType === "image/svg+xml" || image.contentType === "image/svg") {
const svgText = new TextDecoder().decode(content);
const sanitized = DOMPurify.sanitize(svgText, {
USE_PROFILES: { svg: true, svgFilters: true },
});
content = new TextEncoder().encode(sanitized);
}
const headers = new Headers(); const headers = new Headers();
headers.set("Content-Type", image.contentType); headers.set("Content-Type", image.contentType);
headers.set("Content-Length", image.content.length.toString()); headers.set("Content-Length", content.length.toString());
headers.set("Content-Security-Policy", "default-src 'none'; style-src 'unsafe-inline'; sandbox");
headers.set("X-Content-Type-Options", "nosniff");
return new NextResponse(new Uint8Array(image.content), { return new NextResponse(content, {
status: 200, status: 200,
headers, headers,
}); });

View File

@@ -39,7 +39,7 @@
"@homarr/widgets": "workspace:^0.1.0", "@homarr/widgets": "workspace:^0.1.0",
"dayjs": "^1.11.19", "dayjs": "^1.11.19",
"dotenv": "^17.2.3", "dotenv": "^17.2.3",
"fastify": "^5.6.1", "fastify": "^5.6.2",
"superjson": "2.2.5", "superjson": "2.2.5",
"undici": "7.16.0" "undici": "7.16.0"
}, },
@@ -47,10 +47,10 @@
"@homarr/eslint-config": "workspace:^0.2.0", "@homarr/eslint-config": "workspace:^0.2.0",
"@homarr/prettier-config": "workspace:^0.1.0", "@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0",
"@types/node": "^24.9.2", "@types/node": "^24.10.0",
"dotenv-cli": "^11.0.0", "dotenv-cli": "^11.0.0",
"esbuild": "^0.25.12", "esbuild": "^0.26.0",
"eslint": "^9.39.0", "eslint": "^9.39.1",
"prettier": "^3.6.2", "prettier": "^3.6.2",
"tsx": "4.20.4", "tsx": "4.20.4",
"typescript": "^5.9.3" "typescript": "^5.9.3"

View File

@@ -34,8 +34,8 @@
"@homarr/prettier-config": "workspace:^0.1.0", "@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0",
"@types/ws": "^8.18.1", "@types/ws": "^8.18.1",
"esbuild": "^0.25.12", "esbuild": "^0.26.0",
"eslint": "^9.39.0", "eslint": "^9.39.1",
"prettier": "^3.6.2", "prettier": "^3.6.2",
"typescript": "^5.9.3" "typescript": "^5.9.3"
} }

View File

@@ -39,24 +39,24 @@
"@semantic-release/changelog": "^6.0.3", "@semantic-release/changelog": "^6.0.3",
"@semantic-release/commit-analyzer": "^13.0.1", "@semantic-release/commit-analyzer": "^13.0.1",
"@semantic-release/git": "^10.0.1", "@semantic-release/git": "^10.0.1",
"@semantic-release/github": "^12.0.1", "@semantic-release/github": "^12.0.2",
"@semantic-release/npm": "^13.1.1", "@semantic-release/npm": "^13.1.1",
"@semantic-release/release-notes-generator": "^14.1.0", "@semantic-release/release-notes-generator": "^14.1.0",
"@testcontainers/redis": "^11.7.2", "@testcontainers/redis": "^11.8.0",
"@turbo/gen": "^2.6.0", "@turbo/gen": "^2.6.0",
"@vitejs/plugin-react": "^5.1.0", "@vitejs/plugin-react": "^5.1.0",
"@vitest/coverage-v8": "^4.0.6", "@vitest/coverage-v8": "^4.0.8",
"@vitest/ui": "^4.0.6", "@vitest/ui": "^4.0.8",
"conventional-changelog-conventionalcommits": "^9.1.0", "conventional-changelog-conventionalcommits": "^9.1.0",
"cross-env": "^10.1.0", "cross-env": "^10.1.0",
"jsdom": "^27.1.0", "jsdom": "^27.1.0",
"prettier": "^3.6.2", "prettier": "^3.6.2",
"semantic-release": "^25.0.1", "semantic-release": "^25.0.2",
"testcontainers": "^11.7.2", "testcontainers": "^11.8.0",
"turbo": "^2.6.0", "turbo": "^2.6.0",
"typescript": "^5.9.3", "typescript": "^5.9.3",
"vite-tsconfig-paths": "^5.1.4", "vite-tsconfig-paths": "^5.1.4",
"vitest": "^4.0.6" "vitest": "^4.0.8"
}, },
"packageManager": "pnpm@10.20.0", "packageManager": "pnpm@10.20.0",
"engines": { "engines": {
@@ -77,10 +77,10 @@
"overrides": { "overrides": {
"@babel/helpers@<7.26.10": ">=7.28.4", "@babel/helpers@<7.26.10": ">=7.28.4",
"@babel/runtime@<7.26.10": ">=7.28.4", "@babel/runtime@<7.26.10": ">=7.28.4",
"axios@>=1.0.0 <1.8.2": ">=1.13.1", "axios@>=1.0.0 <1.8.2": ">=1.13.2",
"brace-expansion@>=2.0.0 <=2.0.1": ">=4.0.1", "brace-expansion@>=2.0.0 <=2.0.1": ">=4.0.1",
"brace-expansion@>=1.0.0 <=1.1.11": ">=4.0.1", "brace-expansion@>=1.0.0 <=1.1.11": ">=4.0.1",
"esbuild@<=0.24.2": ">=0.25.12", "esbuild@<=0.24.2": ">=0.26.0",
"form-data@>=4.0.0 <4.0.4": ">=4.0.4", "form-data@>=4.0.0 <4.0.4": ">=4.0.4",
"hono@<4.6.5": ">=4.10.4", "hono@<4.6.5": ">=4.10.4",
"linkifyjs@<4.3.2": ">=4.3.2", "linkifyjs@<4.3.2": ">=4.3.2",
@@ -88,12 +88,12 @@
"prismjs@<1.30.0": ">=1.30.0", "prismjs@<1.30.0": ">=1.30.0",
"proxmox-api>undici": "7.16.0", "proxmox-api>undici": "7.16.0",
"react-is": "^19.2.0", "react-is": "^19.2.0",
"rollup@>=4.0.0 <4.22.4": ">=4.52.5", "rollup@>=4.0.0 <4.22.4": ">=4.53.1",
"sha.js@<=2.4.11": ">=2.4.12", "sha.js@<=2.4.11": ">=2.4.12",
"tar-fs@>=3.0.0 <3.0.9": ">=3.1.1", "tar-fs@>=3.0.0 <3.0.9": ">=3.1.1",
"tar-fs@>=2.0.0 <2.1.3": ">=3.1.1", "tar-fs@>=2.0.0 <2.1.3": ">=3.1.1",
"tmp@<=0.2.3": ">=0.2.5", "tmp@<=0.2.3": ">=0.2.5",
"vite@>=5.0.0 <=5.4.18": ">=7.1.12" "vite@>=5.0.0 <=5.4.18": ">=7.2.2"
}, },
"patchedDependencies": { "patchedDependencies": {
"@types/node-unifi": "patches/@types__node-unifi.patch", "@types/node-unifi": "patches/@types__node-unifi.patch",

View File

@@ -32,7 +32,7 @@
"@homarr/eslint-config": "workspace:^0.2.0", "@homarr/eslint-config": "workspace:^0.2.0",
"@homarr/prettier-config": "workspace:^0.1.0", "@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0",
"eslint": "^9.39.0", "eslint": "^9.39.1",
"typescript": "^5.9.3" "typescript": "^5.9.3"
} }
} }

View File

@@ -43,7 +43,7 @@
"@homarr/translation": "workspace:^0.1.0", "@homarr/translation": "workspace:^0.1.0",
"@homarr/validation": "workspace:^0.1.0", "@homarr/validation": "workspace:^0.1.0",
"@kubernetes/client-node": "^1.4.0", "@kubernetes/client-node": "^1.4.0",
"@tanstack/react-query": "^5.90.6", "@tanstack/react-query": "^5.90.7",
"@trpc/client": "^11.7.1", "@trpc/client": "^11.7.1",
"@trpc/react-query": "^11.7.1", "@trpc/react-query": "^11.7.1",
"@trpc/server": "^11.7.1", "@trpc/server": "^11.7.1",
@@ -60,7 +60,7 @@
"@homarr/eslint-config": "workspace:^0.2.0", "@homarr/eslint-config": "workspace:^0.2.0",
"@homarr/prettier-config": "workspace:^0.1.0", "@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0",
"eslint": "^9.39.0", "eslint": "^9.39.1",
"prettier": "^3.6.2", "prettier": "^3.6.2",
"typescript": "^5.9.3" "typescript": "^5.9.3"
} }

View File

@@ -47,7 +47,7 @@
"@homarr/tsconfig": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0",
"@types/bcrypt": "6.0.0", "@types/bcrypt": "6.0.0",
"@types/cookies": "0.9.2", "@types/cookies": "0.9.2",
"eslint": "^9.39.0", "eslint": "^9.39.1",
"prettier": "^3.6.2", "prettier": "^3.6.2",
"typescript": "^5.9.3" "typescript": "^5.9.3"
} }

View File

@@ -32,7 +32,7 @@
"@homarr/eslint-config": "workspace:^0.2.0", "@homarr/eslint-config": "workspace:^0.2.0",
"@homarr/prettier-config": "workspace:^0.1.0", "@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0",
"eslint": "^9.39.0", "eslint": "^9.39.1",
"typescript": "^5.9.3" "typescript": "^5.9.3"
} }
} }

View File

@@ -30,7 +30,7 @@
"@homarr/eslint-config": "workspace:^0.2.0", "@homarr/eslint-config": "workspace:^0.2.0",
"@homarr/prettier-config": "workspace:^0.1.0", "@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0",
"eslint": "^9.39.0", "eslint": "^9.39.1",
"typescript": "^5.9.3" "typescript": "^5.9.3"
} }
} }

View File

@@ -34,8 +34,8 @@
"@homarr/eslint-config": "workspace:^0.2.0", "@homarr/eslint-config": "workspace:^0.2.0",
"@homarr/prettier-config": "workspace:^0.1.0", "@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0",
"esbuild": "^0.25.12", "esbuild": "^0.26.0",
"eslint": "^9.39.0", "eslint": "^9.39.1",
"typescript": "^5.9.3" "typescript": "^5.9.3"
} }
} }

View File

@@ -44,7 +44,7 @@
"@homarr/eslint-config": "workspace:^0.2.0", "@homarr/eslint-config": "workspace:^0.2.0",
"@homarr/prettier-config": "workspace:^0.1.0", "@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0",
"eslint": "^9.39.0", "eslint": "^9.39.1",
"typescript": "^5.9.3" "typescript": "^5.9.3"
} }
} }

View File

@@ -32,7 +32,7 @@
"@homarr/eslint-config": "workspace:^0.2.0", "@homarr/eslint-config": "workspace:^0.2.0",
"@homarr/prettier-config": "workspace:^0.1.0", "@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0",
"eslint": "^9.39.0", "eslint": "^9.39.1",
"typescript": "^5.9.3" "typescript": "^5.9.3"
} }
} }

View File

@@ -29,7 +29,7 @@
"@homarr/core": "workspace:^0.1.0", "@homarr/core": "workspace:^0.1.0",
"@homarr/cron-jobs": "workspace:^0.1.0", "@homarr/cron-jobs": "workspace:^0.1.0",
"@homarr/log": "workspace:^0.1.0", "@homarr/log": "workspace:^0.1.0",
"@tanstack/react-query": "^5.90.6", "@tanstack/react-query": "^5.90.7",
"@trpc/client": "^11.7.1", "@trpc/client": "^11.7.1",
"@trpc/server": "^11.7.1", "@trpc/server": "^11.7.1",
"@trpc/tanstack-react-query": "^11.7.1", "@trpc/tanstack-react-query": "^11.7.1",
@@ -43,7 +43,7 @@
"@homarr/tsconfig": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0",
"@types/node-cron": "^3.0.11", "@types/node-cron": "^3.0.11",
"@types/react": "19.2.2", "@types/react": "19.2.2",
"eslint": "^9.39.0", "eslint": "^9.39.1",
"typescript": "^5.9.3" "typescript": "^5.9.3"
} }
} }

View File

@@ -29,7 +29,7 @@
"@homarr/eslint-config": "workspace:^0.2.0", "@homarr/eslint-config": "workspace:^0.2.0",
"@homarr/prettier-config": "workspace:^0.1.0", "@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0",
"eslint": "^9.39.0", "eslint": "^9.39.1",
"typescript": "^5.9.3" "typescript": "^5.9.3"
} }
} }

View File

@@ -33,7 +33,7 @@
"@homarr/prettier-config": "workspace:^0.1.0", "@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0",
"@types/node-cron": "^3.0.11", "@types/node-cron": "^3.0.11",
"eslint": "^9.39.0", "eslint": "^9.39.1",
"typescript": "^5.9.3" "typescript": "^5.9.3"
} }
} }

View File

@@ -44,7 +44,7 @@
"@homarr/eslint-config": "workspace:^0.2.0", "@homarr/eslint-config": "workspace:^0.2.0",
"@homarr/prettier-config": "workspace:^0.1.0", "@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0",
"eslint": "^9.39.0", "eslint": "^9.39.1",
"typescript": "^5.9.3" "typescript": "^5.9.3"
} }
} }

View File

@@ -49,10 +49,10 @@
"@homarr/definitions": "workspace:^0.1.0", "@homarr/definitions": "workspace:^0.1.0",
"@homarr/log": "workspace:^0.1.0", "@homarr/log": "workspace:^0.1.0",
"@homarr/server-settings": "workspace:^0.1.0", "@homarr/server-settings": "workspace:^0.1.0",
"@mantine/core": "^8.3.6", "@mantine/core": "^8.3.7",
"@paralleldrive/cuid2": "^3.1.0", "@paralleldrive/cuid2": "^3.1.0",
"@testcontainers/mysql": "^11.7.2", "@testcontainers/mysql": "^11.8.0",
"@testcontainers/postgresql": "^11.7.2", "@testcontainers/postgresql": "^11.8.0",
"better-sqlite3": "^12.4.1", "better-sqlite3": "^12.4.1",
"dotenv": "^17.2.3", "dotenv": "^17.2.3",
"drizzle-kit": "^0.31.6", "drizzle-kit": "^0.31.6",
@@ -69,8 +69,8 @@
"@types/better-sqlite3": "7.6.13", "@types/better-sqlite3": "7.6.13",
"@types/pg": "^8.15.6", "@types/pg": "^8.15.6",
"dotenv-cli": "^11.0.0", "dotenv-cli": "^11.0.0",
"esbuild": "^0.25.12", "esbuild": "^0.26.0",
"eslint": "^9.39.0", "eslint": "^9.39.1",
"prettier": "^3.6.2", "prettier": "^3.6.2",
"tsx": "4.20.4", "tsx": "4.20.4",
"typescript": "^5.9.3" "typescript": "^5.9.3"

View File

@@ -24,14 +24,14 @@
"prettier": "@homarr/prettier-config", "prettier": "@homarr/prettier-config",
"dependencies": { "dependencies": {
"@homarr/common": "workspace:^0.1.0", "@homarr/common": "workspace:^0.1.0",
"fast-xml-parser": "^5.3.0", "fast-xml-parser": "^5.3.1",
"zod": "^4.1.12" "zod": "^4.1.12"
}, },
"devDependencies": { "devDependencies": {
"@homarr/eslint-config": "workspace:^0.2.0", "@homarr/eslint-config": "workspace:^0.2.0",
"@homarr/prettier-config": "workspace:^0.1.0", "@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0",
"eslint": "^9.39.0", "eslint": "^9.39.1",
"tsx": "4.20.4", "tsx": "4.20.4",
"typescript": "^5.9.3" "typescript": "^5.9.3"
} }

View File

@@ -33,7 +33,7 @@
"@homarr/prettier-config": "workspace:^0.1.0", "@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0",
"@types/dockerode": "^3.3.45", "@types/dockerode": "^3.3.45",
"eslint": "^9.39.0", "eslint": "^9.39.1",
"typescript": "^5.9.3" "typescript": "^5.9.3"
} }
} }

View File

@@ -26,7 +26,7 @@
"@homarr/common": "workspace:^0.1.0", "@homarr/common": "workspace:^0.1.0",
"@homarr/translation": "workspace:^0.1.0", "@homarr/translation": "workspace:^0.1.0",
"@homarr/validation": "workspace:^0.1.0", "@homarr/validation": "workspace:^0.1.0",
"@mantine/form": "^8.3.6", "@mantine/form": "^8.3.7",
"mantine-form-zod-resolver": "^1.3.0", "mantine-form-zod-resolver": "^1.3.0",
"zod": "^4.1.12" "zod": "^4.1.12"
}, },
@@ -34,7 +34,7 @@
"@homarr/eslint-config": "workspace:^0.2.0", "@homarr/eslint-config": "workspace:^0.2.0",
"@homarr/prettier-config": "workspace:^0.1.0", "@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0",
"eslint": "^9.39.0", "eslint": "^9.39.1",
"typescript": "^5.9.3" "typescript": "^5.9.3"
} }
} }

View File

@@ -30,7 +30,7 @@
"@homarr/translation": "workspace:^0.1.0", "@homarr/translation": "workspace:^0.1.0",
"@homarr/ui": "workspace:^0.1.0", "@homarr/ui": "workspace:^0.1.0",
"@homarr/validation": "workspace:^0.1.0", "@homarr/validation": "workspace:^0.1.0",
"@mantine/core": "^8.3.6", "@mantine/core": "^8.3.7",
"react": "19.2.0", "react": "19.2.0",
"zod": "^4.1.12" "zod": "^4.1.12"
}, },
@@ -38,7 +38,7 @@
"@homarr/eslint-config": "workspace:^0.2.0", "@homarr/eslint-config": "workspace:^0.2.0",
"@homarr/prettier-config": "workspace:^0.1.0", "@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0",
"eslint": "^9.39.0", "eslint": "^9.39.1",
"typescript": "^5.9.3" "typescript": "^5.9.3"
} }
} }

View File

@@ -31,7 +31,7 @@
"@homarr/eslint-config": "workspace:^0.2.0", "@homarr/eslint-config": "workspace:^0.2.0",
"@homarr/prettier-config": "workspace:^0.1.0", "@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0",
"eslint": "^9.39.0", "eslint": "^9.39.1",
"typescript": "^5.9.3" "typescript": "^5.9.3"
} }
} }

View File

@@ -33,7 +33,7 @@
"@homarr/prettier-config": "workspace:^0.1.0", "@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0",
"@types/bcrypt": "6.0.0", "@types/bcrypt": "6.0.0",
"eslint": "^9.39.0", "eslint": "^9.39.1",
"typescript": "^5.9.3" "typescript": "^5.9.3"
} }
} }

View File

@@ -26,7 +26,7 @@
"prettier": "@homarr/prettier-config", "prettier": "@homarr/prettier-config",
"dependencies": { "dependencies": {
"@ctrl/deluge": "^7.5.0", "@ctrl/deluge": "^7.5.0",
"@ctrl/qbittorrent": "^9.10.0", "@ctrl/qbittorrent": "^9.11.0",
"@ctrl/transmission": "^7.4.0", "@ctrl/transmission": "^7.4.0",
"@gitbeaker/rest": "^43.8.0", "@gitbeaker/rest": "^43.8.0",
"@homarr/certificates": "workspace:^0.1.0", "@homarr/certificates": "workspace:^0.1.0",
@@ -57,7 +57,7 @@
"@homarr/tsconfig": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0",
"@types/node-unifi": "^2.5.1", "@types/node-unifi": "^2.5.1",
"@types/xml2js": "^0.4.14", "@types/xml2js": "^0.4.14",
"eslint": "^9.39.0", "eslint": "^9.39.1",
"typescript": "^5.9.3" "typescript": "^5.9.3"
} }
} }

View File

@@ -33,7 +33,7 @@
"@homarr/eslint-config": "workspace:^0.2.0", "@homarr/eslint-config": "workspace:^0.2.0",
"@homarr/prettier-config": "workspace:^0.1.0", "@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0",
"eslint": "^9.39.0", "eslint": "^9.39.1",
"typescript": "^5.9.3" "typescript": "^5.9.3"
} }
} }

View File

@@ -33,7 +33,7 @@
"@homarr/translation": "workspace:^0.1.0", "@homarr/translation": "workspace:^0.1.0",
"@homarr/ui": "workspace:^0.1.0", "@homarr/ui": "workspace:^0.1.0",
"@homarr/validation": "workspace:^0.1.0", "@homarr/validation": "workspace:^0.1.0",
"@mantine/core": "^8.3.6", "@mantine/core": "^8.3.7",
"@tabler/icons-react": "^3.35.0", "@tabler/icons-react": "^3.35.0",
"dayjs": "^1.11.19", "dayjs": "^1.11.19",
"next": "16.0.1", "next": "16.0.1",
@@ -45,7 +45,7 @@
"@homarr/eslint-config": "workspace:^0.2.0", "@homarr/eslint-config": "workspace:^0.2.0",
"@homarr/prettier-config": "workspace:^0.1.0", "@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0",
"eslint": "^9.39.0", "eslint": "^9.39.1",
"typescript": "^5.9.3" "typescript": "^5.9.3"
} }
} }

View File

@@ -24,15 +24,15 @@
"dependencies": { "dependencies": {
"@homarr/translation": "workspace:^0.1.0", "@homarr/translation": "workspace:^0.1.0",
"@homarr/ui": "workspace:^0.1.0", "@homarr/ui": "workspace:^0.1.0",
"@mantine/core": "^8.3.6", "@mantine/core": "^8.3.7",
"@mantine/hooks": "^8.3.6", "@mantine/hooks": "^8.3.7",
"react": "19.2.0" "react": "19.2.0"
}, },
"devDependencies": { "devDependencies": {
"@homarr/eslint-config": "workspace:^0.2.0", "@homarr/eslint-config": "workspace:^0.2.0",
"@homarr/prettier-config": "workspace:^0.1.0", "@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0",
"eslint": "^9.39.0", "eslint": "^9.39.1",
"typescript": "^5.9.3" "typescript": "^5.9.3"
} }
} }

View File

@@ -24,14 +24,14 @@
"prettier": "@homarr/prettier-config", "prettier": "@homarr/prettier-config",
"dependencies": { "dependencies": {
"@homarr/ui": "workspace:^0.1.0", "@homarr/ui": "workspace:^0.1.0",
"@mantine/notifications": "^8.3.6", "@mantine/notifications": "^8.3.7",
"@tabler/icons-react": "^3.35.0" "@tabler/icons-react": "^3.35.0"
}, },
"devDependencies": { "devDependencies": {
"@homarr/eslint-config": "workspace:^0.2.0", "@homarr/eslint-config": "workspace:^0.2.0",
"@homarr/prettier-config": "workspace:^0.1.0", "@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0",
"eslint": "^9.39.0", "eslint": "^9.39.1",
"typescript": "^5.9.3" "typescript": "^5.9.3"
} }
} }

View File

@@ -37,8 +37,8 @@
"@homarr/translation": "workspace:^0.1.0", "@homarr/translation": "workspace:^0.1.0",
"@homarr/ui": "workspace:^0.1.0", "@homarr/ui": "workspace:^0.1.0",
"@homarr/validation": "workspace:^0.1.0", "@homarr/validation": "workspace:^0.1.0",
"@mantine/core": "^8.3.6", "@mantine/core": "^8.3.7",
"@mantine/hooks": "^8.3.6", "@mantine/hooks": "^8.3.7",
"adm-zip": "0.5.16", "adm-zip": "0.5.16",
"next": "16.0.1", "next": "16.0.1",
"react": "19.2.0", "react": "19.2.0",
@@ -52,7 +52,7 @@
"@homarr/prettier-config": "workspace:^0.1.0", "@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0",
"@types/adm-zip": "0.5.7", "@types/adm-zip": "0.5.7",
"eslint": "^9.39.0", "eslint": "^9.39.1",
"typescript": "^5.9.3" "typescript": "^5.9.3"
} }
} }

View File

@@ -29,7 +29,7 @@
"@homarr/eslint-config": "workspace:^0.2.0", "@homarr/eslint-config": "workspace:^0.2.0",
"@homarr/prettier-config": "workspace:^0.1.0", "@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0",
"eslint": "^9.39.0", "eslint": "^9.39.1",
"typescript": "^5.9.3" "typescript": "^5.9.3"
} }
} }

View File

@@ -30,7 +30,7 @@
"@homarr/eslint-config": "workspace:^0.2.0", "@homarr/eslint-config": "workspace:^0.2.0",
"@homarr/prettier-config": "workspace:^0.1.0", "@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0",
"eslint": "^9.39.0", "eslint": "^9.39.1",
"typescript": "^5.9.3" "typescript": "^5.9.3"
} }
} }

View File

@@ -34,7 +34,7 @@
"@homarr/eslint-config": "workspace:^0.2.0", "@homarr/eslint-config": "workspace:^0.2.0",
"@homarr/prettier-config": "workspace:^0.1.0", "@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0",
"eslint": "^9.39.0", "eslint": "^9.39.1",
"typescript": "^5.9.3" "typescript": "^5.9.3"
} }
} }

View File

@@ -39,7 +39,7 @@
"@homarr/eslint-config": "workspace:^0.2.0", "@homarr/eslint-config": "workspace:^0.2.0",
"@homarr/prettier-config": "workspace:^0.1.0", "@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0",
"eslint": "^9.39.0", "eslint": "^9.39.1",
"typescript": "^5.9.3" "typescript": "^5.9.3"
} }
} }

View File

@@ -20,11 +20,19 @@ export const fetchStockPriceHandler = createCachedWidgetRequestHandler({
if (data.chart.result.length !== 1) { if (data.chart.result.length !== 1) {
throw new Error("Received multiple results"); throw new Error("Received multiple results");
} }
if (!data.chart.result[0]) { const firstResult = data.chart.result[0];
if (!firstResult) {
throw new Error("Received invalid data"); throw new Error("Received invalid data");
} }
return {
return data.chart.result[0]; priceHistory:
firstResult.indicators.quote[0]?.close.filter(
// Filter out null values from price arrays (Yahoo Finance returns null for missing data points)
(value) => value !== null && value !== undefined,
) ?? [],
symbol: firstResult.meta.symbol,
shortName: firstResult.meta.shortName,
};
}, },
cacheDuration: dayjs.duration(5, "minutes"), cacheDuration: dayjs.duration(5, "minutes"),
}); });
@@ -43,7 +51,7 @@ const dataSchema = z
indicators: z.object({ indicators: z.object({
quote: z.array( quote: z.array(
z.object({ z.object({
close: z.array(z.number()), close: z.array(z.number().nullish()),
}), }),
), ),
}), }),

View File

@@ -29,7 +29,7 @@
"@homarr/eslint-config": "workspace:^0.2.0", "@homarr/eslint-config": "workspace:^0.2.0",
"@homarr/prettier-config": "workspace:^0.1.0", "@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0",
"eslint": "^9.39.0", "eslint": "^9.39.1",
"typescript": "^5.9.3" "typescript": "^5.9.3"
} }
} }

View File

@@ -26,7 +26,7 @@
"@homarr/api": "workspace:^0.1.0", "@homarr/api": "workspace:^0.1.0",
"@homarr/db": "workspace:^0.1.0", "@homarr/db": "workspace:^0.1.0",
"@homarr/server-settings": "workspace:^0.1.0", "@homarr/server-settings": "workspace:^0.1.0",
"@mantine/dates": "^8.3.6", "@mantine/dates": "^8.3.7",
"next": "16.0.1", "next": "16.0.1",
"react": "19.2.0", "react": "19.2.0",
"react-dom": "19.2.0" "react-dom": "19.2.0"
@@ -35,7 +35,7 @@
"@homarr/eslint-config": "workspace:^0.2.0", "@homarr/eslint-config": "workspace:^0.2.0",
"@homarr/prettier-config": "workspace:^0.1.0", "@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0",
"eslint": "^9.39.0", "eslint": "^9.39.1",
"typescript": "^5.9.3" "typescript": "^5.9.3"
} }
} }

View File

@@ -33,9 +33,9 @@
"@homarr/settings": "workspace:^0.1.0", "@homarr/settings": "workspace:^0.1.0",
"@homarr/translation": "workspace:^0.1.0", "@homarr/translation": "workspace:^0.1.0",
"@homarr/ui": "workspace:^0.1.0", "@homarr/ui": "workspace:^0.1.0",
"@mantine/core": "^8.3.6", "@mantine/core": "^8.3.7",
"@mantine/hooks": "^8.3.6", "@mantine/hooks": "^8.3.7",
"@mantine/spotlight": "^8.3.6", "@mantine/spotlight": "^8.3.7",
"@tabler/icons-react": "^3.35.0", "@tabler/icons-react": "^3.35.0",
"jotai": "^2.15.1", "jotai": "^2.15.1",
"next": "16.0.1", "next": "16.0.1",
@@ -47,7 +47,7 @@
"@homarr/eslint-config": "workspace:^0.2.0", "@homarr/eslint-config": "workspace:^0.2.0",
"@homarr/prettier-config": "workspace:^0.1.0", "@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0",
"eslint": "^9.39.0", "eslint": "^9.39.1",
"typescript": "^5.9.3" "typescript": "^5.9.3"
} }
} }

View File

@@ -33,7 +33,7 @@
"deepmerge": "4.3.1", "deepmerge": "4.3.1",
"mantine-react-table": "2.0.0-beta.9", "mantine-react-table": "2.0.0-beta.9",
"next": "16.0.1", "next": "16.0.1",
"next-intl": "4.4.0", "next-intl": "4.5.0",
"react": "19.2.0", "react": "19.2.0",
"react-dom": "19.2.0" "react-dom": "19.2.0"
}, },
@@ -41,7 +41,7 @@
"@homarr/eslint-config": "workspace:^0.2.0", "@homarr/eslint-config": "workspace:^0.2.0",
"@homarr/prettier-config": "workspace:^0.1.0", "@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0",
"eslint": "^9.39.0", "eslint": "^9.39.1",
"typescript": "^5.9.3" "typescript": "^5.9.3"
} }
} }

View File

@@ -649,14 +649,14 @@
"app": { "app": {
"option": { "option": {
"existing": { "existing": {
"title": "", "title": "Vorhanden",
"label": "" "label": "Vorhandene App auswählen"
}, },
"new": { "new": {
"title": "", "title": "Neu",
"url": { "url": {
"label": "", "label": "App URL",
"description": "" "description": "Die URL, welche die App öffnet, sobald sie vom Dashboard aus aufgerufen wird"
} }
} }
} }
@@ -676,9 +676,9 @@
}, },
"app": { "app": {
"action": { "action": {
"add": "", "add": "Eine App verknüpfen",
"remove": "", "remove": "Verknüpfung aufheben",
"select": "" "select": "Wählen Sie eine App zum Verknüpfen aus"
} }
} }
}, },
@@ -709,7 +709,7 @@
"description": "Integration \"{kind}\" kann mit den Suchmaschinen verwendet werden. Wählen Sie dies, um die Suchmaschine automatisch zu konfigurieren." "description": "Integration \"{kind}\" kann mit den Suchmaschinen verwendet werden. Wählen Sie dies, um die Suchmaschine automatisch zu konfigurieren."
}, },
"app": { "app": {
"sectionTitle": "" "sectionTitle": "Verknüpfte App"
}, },
"createApp": { "createApp": {
"label": "App erstellen", "label": "App erstellen",
@@ -1051,7 +1051,7 @@
"add": "Hinzufügen", "add": "Hinzufügen",
"apply": "Übernehmen", "apply": "Übernehmen",
"backToOverview": "Zurück zur Übersicht", "backToOverview": "Zurück zur Übersicht",
"change": "", "change": "Verändern",
"create": "Erstellen", "create": "Erstellen",
"createAnother": "Erstellen und neu starten", "createAnother": "Erstellen und neu starten",
"edit": "Bearbeiten", "edit": "Bearbeiten",
@@ -1174,8 +1174,8 @@
}, },
"unit": { "unit": {
"speed": { "speed": {
"kilometersPerHour": "", "kilometersPerHour": "km/h",
"milesPerHour": "" "milesPerHour": "mph"
} }
} }
}, },
@@ -1190,7 +1190,7 @@
"label": "Titel" "label": "Titel"
}, },
"customCssClasses": { "customCssClasses": {
"label": "" "label": "Benutzerdefinierte CSS Klassen"
}, },
"borderColor": { "borderColor": {
"label": "Rahmenfarbe" "label": "Rahmenfarbe"
@@ -1780,7 +1780,7 @@
"description": "Nur bei aktuellem Wetter" "description": "Nur bei aktuellem Wetter"
}, },
"useImperialSpeed": { "useImperialSpeed": {
"label": "" "label": "Verwende miles per hour für die Windgeschwindigkeit"
}, },
"location": { "location": {
"label": "Wetterstandort" "label": "Wetterstandort"
@@ -1800,12 +1800,12 @@
"description": "Wie das Datum aussehen sollte" "description": "Wie das Datum aussehen sollte"
} }
}, },
"currentWindSpeed": "{currentWindSpeed} km/h", "currentWindSpeed": "{currentWindSpeed} {unit}",
"dailyForecast": { "dailyForecast": {
"sunrise": "Sonnenaufgang", "sunrise": "Sonnenaufgang",
"sunset": "Sonnenuntergang", "sunset": "Sonnenuntergang",
"maxWindSpeed": "Maximale Windgeschwindigkeit: {maxWindSpeed} km/h", "maxWindSpeed": "Maximale Windgeschwindigkeit: {maxWindSpeed} {unit}",
"maxWindGusts": "Maximale Windböen: {maxWindGusts} km/h" "maxWindGusts": "Maximale Windböen: {maxWindGusts} {unit}"
}, },
"kind": { "kind": {
"clear": "Klar", "clear": "Klar",
@@ -3013,8 +3013,8 @@
"integration": "Integrationen", "integration": "Integrationen",
"app": "Apps", "app": "Apps",
"group": "Gruppen", "group": "Gruppen",
"searchEngine": "", "searchEngine": "Suchmaschinen",
"media": "" "media": "Medien"
}, },
"statisticLabel": { "statisticLabel": {
"boards": "Boards", "boards": "Boards",
@@ -3023,8 +3023,8 @@
"authorization": "Autorisierung" "authorization": "Autorisierung"
}, },
"heroBanner": { "heroBanner": {
"title": "", "title": "Willkommen zurück zu Ihrem",
"subtitle": "" "subtitle": "{app} Board"
} }
}, },
"board": { "board": {

View File

@@ -754,86 +754,86 @@
"notFound": "Not found", "notFound": "Not found",
"tooManyRequests": "Too many requests", "tooManyRequests": "Too many requests",
"internalServerError": "Internal server error", "internalServerError": "Internal server error",
"serviceUnavailable": "", "serviceUnavailable": "Service unavailable",
"gatewayTimeout": "" "gatewayTimeout": "Gateway timeout"
} }
}, },
"certificate": { "certificate": {
"title": "", "title": "Certificate error",
"description": { "description": {
"expired": "", "expired": "The certificate has expired.",
"notYetValid": "", "notYetValid": "The certificate is not yet valid.",
"untrusted": "", "untrusted": "The certificate is not trusted.",
"hostnameMismatch": "" "hostnameMismatch": "The certificate hostname does not match the URL."
}, },
"alert": { "alert": {
"permission": { "permission": {
"title": "", "title": "Not enough permissions",
"message": "" "message": "You are not allowed to trust or upload certificates. Please contact your administrator to upload the necessary root certificate."
}, },
"hostnameMismatch": { "hostnameMismatch": {
"title": "", "title": "Hostname mismatch",
"message": "" "message": "The hostname in the certificate does not match the hostname you are connecting to. This could indicate a security risk, but you can still choose to trust this certificate."
}, },
"extract": { "extract": {
"title": "", "title": "CA certificate extraction failed",
"message": "" "message": "Only self-signed certificates without a chain can be fetched automatically. If you are using a self-signed certificate, please make sure to upload the CA certificate manually. You can find instructions on how to do this <docsLink></docsLink>."
} }
}, },
"action": { "action": {
"retry": { "retry": {
"label": "" "label": "Retry creation"
}, },
"trust": { "trust": {
"label": "" "label": "Trust certificate"
}, },
"upload": { "upload": {
"label": "" "label": "Upload certificate"
} }
}, },
"hostnameMismatch": { "hostnameMismatch": {
"confirm": { "confirm": {
"title": "", "title": "Trust hostname mismatch",
"message": "" "message": "Are you sure you want to trust the certificate with a hostname mismatch?"
}, },
"notification": { "notification": {
"success": { "success": {
"title": "", "title": "Trusted certificate",
"message": "" "message": "Added hostname to trusted certificate list"
}, },
"error": { "error": {
"title": "", "title": "Failed to trust certificate",
"message": "" "message": "The certificate with a hostname mismatch could not be trusted"
} }
} }
}, },
"selfSigned": { "selfSigned": {
"confirm": { "confirm": {
"title": "", "title": "Trust self-signed certificate",
"message": "" "message": "Are you sure you want to trust this self-signed certificate?"
}, },
"notification": { "notification": {
"success": { "success": {
"title": "", "title": "Trusted certificate",
"message": "" "message": "Added certificate to trusted certificate list"
}, },
"error": { "error": {
"title": "", "title": "Failed to trust certificate",
"message": "" "message": "Failed to add certificate to trusted certificate list"
} }
} }
}, },
"details": { "details": {
"title": "", "title": "Details",
"description": "", "description": "Review the certificate information before deciding to trust it.",
"content": { "content": {
"action": "", "action": "Show content",
"title": "" "title": "PEM Certificate"
} }
} }
}, },
"request": { "request": {
"title": "", "title": "Request error",
"description": { "description": {
"connection": { "connection": {
"hostUnreachable": "", "hostUnreachable": "",
@@ -4456,50 +4456,50 @@
"title": "", "title": "",
"description": "", "description": "",
"noResults": { "noResults": {
"title": "" "title": "There are no hostnames yet"
}, },
"toCertificates": "" "toCertificates": "Certificates"
} }
}, },
"action": { "action": {
"create": { "create": {
"label": "", "label": "Add certificate",
"notification": { "notification": {
"success": { "success": {
"title": "", "title": "Certificate added",
"message": "" "message": "The certificate was added successfully"
}, },
"error": { "error": {
"title": "", "title": "Failed to add certificate",
"message": "" "message": "The certificate could not be added"
} }
} }
}, },
"remove": { "remove": {
"label": "", "label": "Remove certificate",
"confirm": "", "confirm": "Are you sure you want to remove the certificate?",
"notification": { "notification": {
"success": { "success": {
"title": "", "title": "Certificate removed",
"message": "" "message": "The certificate was removed successfully"
}, },
"error": { "error": {
"title": "", "title": "Certificate not removed",
"message": "" "message": "The certificate could not be removed"
} }
} }
}, },
"removeHostname": { "removeHostname": {
"label": "", "label": "Remove trusted hostname",
"confirm": "", "confirm": "Are you sure you want to remove this trusted hostname? This can cause some integrations to stop working.",
"notification": { "notification": {
"success": { "success": {
"title": "", "title": "Hostname removed",
"message": "" "message": "The hostname was removed successfully"
}, },
"error": { "error": {
"title": "", "title": "Hostname not removed",
"message": "" "message": "The hostname could not be removed"
} }
} }
} }
@@ -4508,10 +4508,10 @@
"log": { "log": {
"level": { "level": {
"option": { "option": {
"debug": "", "debug": "Debug",
"info": "", "info": "Info",
"warn": "", "warn": "Warn",
"error": "" "error": "Error"
} }
} }
} }

View File

@@ -653,10 +653,10 @@
"label": "Seleziona app esistente" "label": "Seleziona app esistente"
}, },
"new": { "new": {
"title": "", "title": "Nuovo",
"url": { "url": {
"label": "Url app", "label": "Url app",
"description": "" "description": "L'Url che l'app aprirà quando vi si accede dalla dashboard"
} }
} }
} }
@@ -676,9 +676,9 @@
}, },
"app": { "app": {
"action": { "action": {
"add": "", "add": "Collega un'app",
"remove": "", "remove": "Scollega",
"select": "" "select": "Seleziona un'app da collegare"
} }
} }
}, },
@@ -709,7 +709,7 @@
"description": "Integrazione \"{kind}\" può essere utilizzato con i motori di ricerca. Selezionare questa opzione per configurare automaticamente il motore di ricerca." "description": "Integrazione \"{kind}\" può essere utilizzato con i motori di ricerca. Selezionare questa opzione per configurare automaticamente il motore di ricerca."
}, },
"app": { "app": {
"sectionTitle": "" "sectionTitle": "App Collegata"
}, },
"createApp": { "createApp": {
"label": "Crea app", "label": "Crea app",
@@ -1051,7 +1051,7 @@
"add": "Aggiungi", "add": "Aggiungi",
"apply": "Applica", "apply": "Applica",
"backToOverview": "Torna alla panoramica", "backToOverview": "Torna alla panoramica",
"change": "", "change": "Cambia",
"create": "Crea", "create": "Crea",
"createAnother": "", "createAnother": "",
"edit": "Modifica", "edit": "Modifica",
@@ -2103,7 +2103,7 @@
}, },
"index": { "index": {
"columnTitle": "#", "columnTitle": "#",
"detailsTitle": "" "detailsTitle": "Indice corrente all'interno del client"
}, },
"id": { "id": {
"columnTitle": "Id" "columnTitle": "Id"
@@ -2949,7 +2949,7 @@
}, },
"breakpoint": { "breakpoint": {
"label": "", "label": "",
"description": "" "description": "Il layout verrà utilizzato su tutti gli schermi più grandi di questo breakpoint fino al breakpoint più grande successivo."
} }
} }
}, },
@@ -3013,7 +3013,7 @@
"integration": "Integrazioni", "integration": "Integrazioni",
"app": "Applicazioni", "app": "Applicazioni",
"group": "Gruppi", "group": "Gruppi",
"searchEngine": "", "searchEngine": "Motori di ricerca",
"media": "Media" "media": "Media"
}, },
"statisticLabel": { "statisticLabel": {
@@ -3023,8 +3023,8 @@
"authorization": "Autorizzazione" "authorization": "Autorizzazione"
}, },
"heroBanner": { "heroBanner": {
"title": "", "title": "Bentornato sulla tua",
"subtitle": "" "subtitle": "{app} Board"
} }
}, },
"board": { "board": {
@@ -3358,7 +3358,7 @@
"label": "Controllo aggiornamenti" "label": "Controllo aggiornamenti"
}, },
"mediaTranscoding": { "mediaTranscoding": {
"label": "" "label": "Transcodifica del media"
}, },
"networkController": { "networkController": {
"label": "Controller di rete" "label": "Controller di rete"
@@ -3510,7 +3510,7 @@
"subtitle": "{count} utilizzato nel Codice di Homarr" "subtitle": "{count} utilizzato nel Codice di Homarr"
}, },
"hotkeys": { "hotkeys": {
"title": "", "title": "Tasti di scelta rapida",
"subtitle": "Scorciatoie da tastiera per migliorare il flusso di lavoro", "subtitle": "Scorciatoie da tastiera per migliorare il flusso di lavoro",
"field": { "field": {
"shortcut": "Scorciatoia", "shortcut": "Scorciatoia",
@@ -3520,7 +3520,7 @@
"toggleBoardEdit": "", "toggleBoardEdit": "",
"toggleColorScheme": "", "toggleColorScheme": "",
"saveNotebook": "", "saveNotebook": "",
"openSpotlight": "" "openSpotlight": "Apri ricerca"
}, },
"note": "" "note": ""
} }

View File

@@ -30,9 +30,9 @@
"@homarr/log": "workspace:^0.1.0", "@homarr/log": "workspace:^0.1.0",
"@homarr/translation": "workspace:^0.1.0", "@homarr/translation": "workspace:^0.1.0",
"@homarr/validation": "workspace:^0.1.0", "@homarr/validation": "workspace:^0.1.0",
"@mantine/core": "^8.3.6", "@mantine/core": "^8.3.7",
"@mantine/dates": "^8.3.6", "@mantine/dates": "^8.3.7",
"@mantine/hooks": "^8.3.6", "@mantine/hooks": "^8.3.7",
"@tabler/icons-react": "^3.35.0", "@tabler/icons-react": "^3.35.0",
"mantine-react-table": "2.0.0-beta.9", "mantine-react-table": "2.0.0-beta.9",
"next": "16.0.1", "next": "16.0.1",
@@ -45,7 +45,7 @@
"@homarr/prettier-config": "workspace:^0.1.0", "@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0",
"@types/css-modules": "^1.0.5", "@types/css-modules": "^1.0.5",
"eslint": "^9.39.0", "eslint": "^9.39.1",
"typescript": "^5.9.3" "typescript": "^5.9.3"
} }
} }

View File

@@ -31,7 +31,7 @@
"@homarr/eslint-config": "workspace:^0.2.0", "@homarr/eslint-config": "workspace:^0.2.0",
"@homarr/prettier-config": "workspace:^0.1.0", "@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0",
"eslint": "^9.39.0", "eslint": "^9.39.1",
"typescript": "^5.9.3" "typescript": "^5.9.3"
} }
} }

View File

@@ -48,9 +48,9 @@
"@homarr/translation": "workspace:^0.1.0", "@homarr/translation": "workspace:^0.1.0",
"@homarr/ui": "workspace:^0.1.0", "@homarr/ui": "workspace:^0.1.0",
"@homarr/validation": "workspace:^0.1.0", "@homarr/validation": "workspace:^0.1.0",
"@mantine/charts": "^8.3.6", "@mantine/charts": "^8.3.7",
"@mantine/core": "^8.3.6", "@mantine/core": "^8.3.7",
"@mantine/hooks": "^8.3.6", "@mantine/hooks": "^8.3.7",
"@tabler/icons-react": "^3.35.0", "@tabler/icons-react": "^3.35.0",
"@tiptap/extension-color": "2.27.1", "@tiptap/extension-color": "2.27.1",
"@tiptap/extension-highlight": "2.27.1", "@tiptap/extension-highlight": "2.27.1",
@@ -85,7 +85,7 @@
"@homarr/prettier-config": "workspace:^0.1.0", "@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0",
"@types/video.js": "^7.3.58", "@types/video.js": "^7.3.58",
"eslint": "^9.39.0", "eslint": "^9.39.1",
"typescript": "^5.9.3" "typescript": "^5.9.3"
} }
} }

View File

@@ -11,8 +11,9 @@ import classes from "./component.module.css";
export default function IFrameWidget({ options, isEditMode }: WidgetComponentProps<"iframe">) { export default function IFrameWidget({ options, isEditMode }: WidgetComponentProps<"iframe">) {
const t = useI18n(); const t = useI18n();
const { embedUrl, ...permissions } = options; const { embedUrl, allowScrolling, ...permissions } = options;
const allowedPermissions = getAllowedPermissions(permissions); const allowedPermissions = getAllowedPermissions(permissions);
const sandboxFlags = getSandboxFlags(permissions);
if (embedUrl.trim() === "") return <NoUrl />; if (embedUrl.trim() === "") return <NoUrl />;
if (!isSupportedProtocol(embedUrl)) { if (!isSupportedProtocol(embedUrl)) {
@@ -27,7 +28,8 @@ export default function IFrameWidget({ options, isEditMode }: WidgetComponentPro
src={embedUrl} src={embedUrl}
title="widget iframe" title="widget iframe"
allow={allowedPermissions.join(" ")} allow={allowedPermissions.join(" ")}
scrolling={options.allowScrolling ? "yes" : "no"} scrolling={allowScrolling ? "yes" : "no"}
sandbox={sandboxFlags.join(" ")}
> >
<Text>{t("widget.iframe.error.noBrowerSupport")}</Text> <Text>{t("widget.iframe.error.noBrowerSupport")}</Text>
</iframe> </iframe>
@@ -80,6 +82,22 @@ const getAllowedPermissions = (
.map(([key]) => permissionMapping[key]); .map(([key]) => permissionMapping[key]);
}; };
const getSandboxFlags = (
permissions: Omit<WidgetComponentProps<"iframe">["options"], "embedUrl" | "allowScrolling">,
) => {
const baseSandbox = ["allow-scripts", "allow-same-origin", "allow-forms", "allow-popups"];
if (permissions.allowFullScreen) {
baseSandbox.push("allow-presentation");
}
if (permissions.allowPayment) {
baseSandbox.push("allow-popups-to-escape-sandbox");
}
return baseSandbox;
};
const permissionMapping = { const permissionMapping = {
allowAutoPlay: "autoplay", allowAutoPlay: "autoplay",
allowCamera: "camera", allowCamera: "camera",

View File

@@ -26,15 +26,13 @@ export default function StockPriceWidget({ options, width, height }: WidgetCompo
const theme = useMantineTheme(); const theme = useMantineTheme();
const [{ data }] = clientApi.widget.stockPrice.getPriceHistory.useSuspenseQuery(options); const [{ data }] = clientApi.widget.stockPrice.getPriceHistory.useSuspenseQuery(options);
const stockValues = data.indicators.quote[0]?.close ?? []; const stockValuesChange = round(calculateChange(data.priceHistory.at(-1) ?? 0, data.priceHistory[0] ?? 0));
const stockValuesChange = round(calculateChange(stockValues[stockValues.length - 1] ?? 0, stockValues[0] ?? 0));
const stockValuesChangePercentage = round( const stockValuesChangePercentage = round(
calculateChangePercentage(stockValues[stockValues.length - 1] ?? 0, stockValues[0] ?? 0), calculateChangePercentage(data.priceHistory.at(-1) ?? 0, data.priceHistory[0] ?? 0),
); );
const stockValuesMin = Math.min(...stockValues); const stockValuesMin = Math.min(...data.priceHistory);
const stockGraphValues = stockValues.map((value) => value - stockValuesMin + 50); const stockGraphValues = data.priceHistory.map((value) => value - stockValuesMin + 50);
return ( return (
<Flex h="100%" w="100%"> <Flex h="100%" w="100%">
@@ -57,17 +55,17 @@ export default function StockPriceWidget({ options, width, height }: WidgetCompo
) : ( ) : (
<IconTrendingDown size="1.5rem" color={theme.colors.red[7]} /> <IconTrendingDown size="1.5rem" color={theme.colors.red[7]} />
)} )}
{data.meta.symbol} {data.symbol}
</Text> </Text>
{width > 280 && height > 280 && ( {width > 280 && height > 280 && (
<Text size="md" lh="1"> <Text size="md" lh="1">
{data.meta.shortName} {data.shortName}
</Text> </Text>
)} )}
</Stack> </Stack>
<Title pos="absolute" bottom={10} right={10} order={width > 280 ? 1 : 2} fw={700}> <Title pos="absolute" bottom={10} right={10} order={width > 280 ? 1 : 2} fw={700}>
{new Intl.NumberFormat().format(round(stockValues[stockValues.length - 1] ?? 0))} {new Intl.NumberFormat().format(round(data.priceHistory.at(-1) ?? 0))}
</Title> </Title>
{width > 280 && ( {width > 280 && (
@@ -90,11 +88,11 @@ export default function StockPriceWidget({ options, width, height }: WidgetCompo
) : ( ) : (
<IconTrendingDown size="1.5rem" color={theme.colors.red[7]} /> <IconTrendingDown size="1.5rem" color={theme.colors.red[7]} />
)} )}
{data.meta.symbol} {data.symbol}
</Text> </Text>
{width > 280 && height > 280 && ( {width > 280 && height > 280 && (
<Text size="md" lh="1"> <Text size="md" lh="1">
{data.meta.shortName} {data.shortName}
</Text> </Text>
)} )}
</Stack> </Stack>

1576
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@@ -29,7 +29,7 @@
"devDependencies": { "devDependencies": {
"@homarr/prettier-config": "workspace:^0.1.0", "@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0",
"eslint": "^9.39.0", "eslint": "^9.39.1",
"typescript": "^5.9.3" "typescript": "^5.9.3"
} }
} }