Compare commits
No files matched your search
@@ -64,7 +64,7 @@ jobs:
|
|||||||
- uses: actions/setup-node@v6
|
- uses: actions/setup-node@v6
|
||||||
if: env.SKIP_RELEASE == 'false'
|
if: env.SKIP_RELEASE == 'false'
|
||||||
with:
|
with:
|
||||||
node-version: 24.11.0
|
node-version: 24.11.1
|
||||||
cache: "pnpm"
|
cache: "pnpm"
|
||||||
- run: npm i -g pnpm
|
- run: npm i -g pnpm
|
||||||
if: env.SKIP_RELEASE == 'false'
|
if: env.SKIP_RELEASE == 'false'
|
||||||
|
|||||||
@@ -1,3 +1,41 @@
|
|||||||
|
## [1.44.0](https://github.com/homarr-labs/homarr/compare/v1.43.3...v1.44.0) (2025-11-21)
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **pi-hole:** support no-auth ([#4480](https://github.com/homarr-labs/homarr/issues/4480)) ([c89e35e](https://github.com/homarr-labs/homarr/commit/c89e35e13c794bbdf98748c00644b86f7f5dbe68))
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **deps:** update dependency @tanstack/react-query to ^5.90.8 ([#4494](https://github.com/homarr-labs/homarr/issues/4494)) ([a5b6203](https://github.com/homarr-labs/homarr/commit/a5b6203be6ac3c2308614f10ef6a17590917e2c9))
|
||||||
|
* **deps:** update dependency @tanstack/react-query to ^5.90.9 ([#4508](https://github.com/homarr-labs/homarr/issues/4508)) ([b3db5d5](https://github.com/homarr-labs/homarr/commit/b3db5d5f7bc2d146f0b2c230a52e7bd4efad3bcb))
|
||||||
|
* **deps:** update dependency @tanstack/react-query-next-experimental to ^5.91.0 ([#4505](https://github.com/homarr-labs/homarr/issues/4505)) ([8ea6cff](https://github.com/homarr-labs/homarr/commit/8ea6cffb537ca54a413c583ab8b8fd24a52185be))
|
||||||
|
* **deps:** update dependency drizzle-kit to ^0.31.7 ([#4507](https://github.com/homarr-labs/homarr/issues/4507)) ([b4f9fb8](https://github.com/homarr-labs/homarr/commit/b4f9fb8b46a8f74e2d7896dfe98e80618cfbcde4))
|
||||||
|
* **deps:** update dependency fast-xml-parser to ^5.3.2 ([#4510](https://github.com/homarr-labs/homarr/issues/4510)) ([5e57a49](https://github.com/homarr-labs/homarr/commit/5e57a4906bcedc53d220e983827293f4a699c425))
|
||||||
|
* **deps:** update dependency next-intl to v4.5.1 ([#4484](https://github.com/homarr-labs/homarr/issues/4484)) ([06942ec](https://github.com/homarr-labs/homarr/commit/06942ecbcd245f5540f2960f437ca2955a5ed0c3))
|
||||||
|
* **deps:** update dependency next-intl to v4.5.3 ([#4503](https://github.com/homarr-labs/homarr/issues/4503)) ([0642773](https://github.com/homarr-labs/homarr/commit/064277373cacd3309d8da3779d5451d195da7f81))
|
||||||
|
* **deps:** update dependency sass to ^1.94.0 ([#4482](https://github.com/homarr-labs/homarr/issues/4482)) ([19ecede](https://github.com/homarr-labs/homarr/commit/19ecedea4370924d47545ca8d9d46a0b7c016cc9))
|
||||||
|
* **deps:** update mantine monorepo to ^8.3.8 ([#4516](https://github.com/homarr-labs/homarr/issues/4516)) ([ded4e72](https://github.com/homarr-labs/homarr/commit/ded4e72e5407b0076495a06111f3b04445f27276))
|
||||||
|
* **deps:** update nextjs monorepo to v16.0.3 ([#4504](https://github.com/homarr-labs/homarr/issues/4504)) ([7d0c1a1](https://github.com/homarr-labs/homarr/commit/7d0c1a14fdf1731ff44e3d00793cf4cd1c3e9b1f))
|
||||||
|
* **deps:** update testcontainers-node monorepo to ^11.8.1 ([#4486](https://github.com/homarr-labs/homarr/issues/4486)) ([64657d8](https://github.com/homarr-labs/homarr/commit/64657d831cbe28a59708b280b07889b9f0232743))
|
||||||
|
* **deps:** update turbo monorepo to ^2.6.1 ([#4483](https://github.com/homarr-labs/homarr/issues/4483)) ([cd124d6](https://github.com/homarr-labs/homarr/commit/cd124d6e8392eef5df0092481ec3cc26599f2902))
|
||||||
|
* **iframe:** allow clicking links within ([#4521](https://github.com/homarr-labs/homarr/issues/4521)) ([5a418d7](https://github.com/homarr-labs/homarr/commit/5a418d73bdb07cf3d3270983b6881f2de8d58ad7))
|
||||||
|
* **media-requests:** incorrect availability mapping ([#4520](https://github.com/homarr-labs/homarr/issues/4520)) ([d9cc35b](https://github.com/homarr-labs/homarr/commit/d9cc35b9859a14f44c4e4b13c6518287f8d18e54))
|
||||||
|
|
||||||
|
## [1.43.3](https://github.com/homarr-labs/homarr/compare/v1.43.2...v1.43.3) (2025-11-14)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **deps:** update dependency @ctrl/qbittorrent to ^9.11.0 ([#4456](https://github.com/homarr-labs/homarr/issues/4456)) ([ddfed18](https://github.com/homarr-labs/homarr/commit/ddfed18acf44596dba15ea0ef56233c4936f9775))
|
||||||
|
* **deps:** update dependency @tanstack/react-query to ^5.90.7 ([#4451](https://github.com/homarr-labs/homarr/issues/4451)) ([7bc2f87](https://github.com/homarr-labs/homarr/commit/7bc2f87f31f1babe691fa4a086a3897977f2d871))
|
||||||
|
* **deps:** update dependency fast-xml-parser to ^5.3.1 ([#4435](https://github.com/homarr-labs/homarr/issues/4435)) ([65f2e82](https://github.com/homarr-labs/homarr/commit/65f2e825fdb9e5e79b814c9b49f663d1afac784d))
|
||||||
|
* **deps:** update dependency fastify to ^5.6.2 ([#4471](https://github.com/homarr-labs/homarr/issues/4471)) ([e7071bf](https://github.com/homarr-labs/homarr/commit/e7071bf2bf6a45ff760cd3e7bd06382d2ed66cdc))
|
||||||
|
* **deps:** update dependency next-intl to v4.5.0 ([#4462](https://github.com/homarr-labs/homarr/issues/4462)) ([51ce5da](https://github.com/homarr-labs/homarr/commit/51ce5da45bdccf061e593097ed751cf09d663437))
|
||||||
|
* **deps:** update dependency swagger-ui-react to ^5.30.2 ([#4442](https://github.com/homarr-labs/homarr/issues/4442)) ([d3edfcf](https://github.com/homarr-labs/homarr/commit/d3edfcf3dca3d34afd5ef8ec21599cd08fde5092))
|
||||||
|
* **deps:** update mantine monorepo to ^8.3.7 ([#4472](https://github.com/homarr-labs/homarr/issues/4472)) ([8a87dba](https://github.com/homarr-labs/homarr/commit/8a87dbad59786fa9789dd3efb8d9424bb950e977))
|
||||||
|
* **deps:** update testcontainers-node monorepo to ^11.8.0 ([#4450](https://github.com/homarr-labs/homarr/issues/4450)) ([f648af0](https://github.com/homarr-labs/homarr/commit/f648af0e2b2b5d5f8180402c2734ea0c04559daa))
|
||||||
|
* **stock-price:** ignore missing data points in price history ([#4429](https://github.com/homarr-labs/homarr/issues/4429)) ([c30c98b](https://github.com/homarr-labs/homarr/commit/c30c98b153fbec21551e45aedf83e0ae29d6e773))
|
||||||
|
* **users:** next button in create form always disabled ([#4443](https://github.com/homarr-labs/homarr/issues/4443)) ([1c1f8a4](https://github.com/homarr-labs/homarr/commit/1c1f8a48d259c65ebeeec6856e1fe339defb4aaf))
|
||||||
|
|
||||||
## [1.43.2](https://github.com/homarr-labs/homarr/compare/v1.43.1...v1.43.2) (2025-11-07)
|
## [1.43.2](https://github.com/homarr-labs/homarr/compare/v1.43.1...v1.43.2) (2025-11-07)
|
||||||
|
|
||||||
### Bug Fixes
|
### Bug Fixes
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
+16
-15
@@ -50,17 +50,17 @@
|
|||||||
"@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.8",
|
||||||
"@mantine/core": "^8.3.6",
|
"@mantine/core": "^8.3.8",
|
||||||
"@mantine/dropzone": "^8.3.6",
|
"@mantine/dropzone": "^8.3.8",
|
||||||
"@mantine/hooks": "^8.3.6",
|
"@mantine/hooks": "^8.3.8",
|
||||||
"@mantine/modals": "^8.3.6",
|
"@mantine/modals": "^8.3.8",
|
||||||
"@mantine/tiptap": "^8.3.6",
|
"@mantine/tiptap": "^8.3.8",
|
||||||
"@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.9",
|
||||||
"@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.91.0",
|
||||||
"@trpc/client": "^11.7.1",
|
"@trpc/client": "^11.7.1",
|
||||||
"@trpc/next": "^11.7.1",
|
"@trpc/next": "^11.7.1",
|
||||||
"@trpc/react-query": "^11.7.1",
|
"@trpc/react-query": "^11.7.1",
|
||||||
@@ -75,18 +75,19 @@
|
|||||||
"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.3",
|
||||||
"postcss-preset-mantine": "^1.18.0",
|
"postcss-preset-mantine": "^1.18.0",
|
||||||
"prismjs": "^1.30.0",
|
"prismjs": "^1.30.0",
|
||||||
"react": "19.2.0",
|
"react": "19.2.0",
|
||||||
"react-dom": "19.2.0",
|
"react-dom": "19.2.0",
|
||||||
"react-error-boundary": "^6.0.0",
|
"react-error-boundary": "^6.0.0",
|
||||||
"react-simple-code-editor": "^0.14.1",
|
"react-simple-code-editor": "^0.14.1",
|
||||||
"sass": "^1.93.3",
|
"sass": "^1.94.0",
|
||||||
"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.1",
|
||||||
"@types/prismjs": "^1.26.5",
|
"@types/prismjs": "^1.26.5",
|
||||||
"@types/react": "19.2.2",
|
"@types/react": "19.2.5",
|
||||||
"@types/react-dom": "19.2.2",
|
"@types/react-dom": "19.2.3",
|
||||||
"@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"
|
||||||
|
|||||||
+7
-8
@@ -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}
|
||||||
|
|||||||
@@ -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,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -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.1",
|
||||||
"dotenv-cli": "^11.0.0",
|
"dotenv-cli": "^11.0.0",
|
||||||
"esbuild": "^0.25.12",
|
"esbuild": "^0.27.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"
|
||||||
|
|||||||
@@ -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.27.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"
|
||||||
}
|
}
|
||||||
|
|||||||
+20
-20
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "homarr",
|
"name": "homarr",
|
||||||
"version": "1.43.2",
|
"version": "1.44.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "cross-env CI=true turbo build",
|
"build": "cross-env CI=true turbo build",
|
||||||
@@ -39,28 +39,28 @@
|
|||||||
"@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.2",
|
||||||
"@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.1",
|
||||||
"@turbo/gen": "^2.6.0",
|
"@turbo/gen": "^2.6.1",
|
||||||
"@vitejs/plugin-react": "^5.1.0",
|
"@vitejs/plugin-react": "^5.1.1",
|
||||||
"@vitest/coverage-v8": "^4.0.6",
|
"@vitest/coverage-v8": "^4.0.9",
|
||||||
"@vitest/ui": "^4.0.6",
|
"@vitest/ui": "^4.0.9",
|
||||||
"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.2.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.1",
|
||||||
"turbo": "^2.6.0",
|
"turbo": "^2.6.1",
|
||||||
"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.9"
|
||||||
},
|
},
|
||||||
"packageManager": "pnpm@10.20.0",
|
"packageManager": "pnpm@10.22.0",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=24.11.0"
|
"node": ">=24.11.1"
|
||||||
},
|
},
|
||||||
"pnpm": {
|
"pnpm": {
|
||||||
"onlyBuiltDependencies": [
|
"onlyBuiltDependencies": [
|
||||||
@@ -77,23 +77,23 @@
|
|||||||
"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.27.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.6",
|
||||||
"linkifyjs@<4.3.2": ">=4.3.2",
|
"linkifyjs@<4.3.2": ">=4.3.2",
|
||||||
"nanoid@>=4.0.0 <5.0.9": ">=5.1.6",
|
"nanoid@>=4.0.0 <5.0.9": ">=5.1.6",
|
||||||
"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.2",
|
||||||
"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",
|
||||||
|
|||||||
@@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -43,13 +43,13 @@
|
|||||||
"@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.9",
|
||||||
"@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",
|
||||||
"@trpc/tanstack-react-query": "^11.7.1",
|
"@trpc/tanstack-react-query": "^11.7.1",
|
||||||
"lodash.clonedeep": "^4.5.0",
|
"lodash.clonedeep": "^4.5.0",
|
||||||
"next": "16.0.1",
|
"next": "16.0.3",
|
||||||
"react": "19.2.0",
|
"react": "19.2.0",
|
||||||
"react-dom": "19.2.0",
|
"react-dom": "19.2.0",
|
||||||
"superjson": "2.2.5",
|
"superjson": "2.2.5",
|
||||||
@@ -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"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { z } from "zod/v4";
|
|||||||
|
|
||||||
import { getIntegrationKindsByCategory } from "@homarr/definitions";
|
import { getIntegrationKindsByCategory } from "@homarr/definitions";
|
||||||
import { createIntegrationAsync } from "@homarr/integrations";
|
import { createIntegrationAsync } from "@homarr/integrations";
|
||||||
|
import { mediaRequestStatusConfiguration } from "@homarr/integrations/types";
|
||||||
import type { MediaRequest } from "@homarr/integrations/types";
|
import type { MediaRequest } from "@homarr/integrations/types";
|
||||||
import { mediaRequestListRequestHandler } from "@homarr/request-handler/media-request-list";
|
import { mediaRequestListRequestHandler } from "@homarr/request-handler/media-request-list";
|
||||||
import { mediaRequestStatsRequestHandler } from "@homarr/request-handler/media-request-stats";
|
import { mediaRequestStatsRequestHandler } from "@homarr/request-handler/media-request-stats";
|
||||||
@@ -35,7 +36,10 @@ export const mediaRequestsRouter = createTRPCRouter({
|
|||||||
return dataB.createdAt.getTime() - dataA.createdAt.getTime();
|
return dataB.createdAt.getTime() - dataA.createdAt.getTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
return dataA.status - dataB.status;
|
return (
|
||||||
|
mediaRequestStatusConfiguration[dataA.status].position -
|
||||||
|
mediaRequestStatusConfiguration[dataB.status].position
|
||||||
|
);
|
||||||
});
|
});
|
||||||
}),
|
}),
|
||||||
subscribeToLatestRequests: publicProcedure
|
subscribeToLatestRequests: publicProcedure
|
||||||
|
|||||||
@@ -35,7 +35,7 @@
|
|||||||
"bcrypt": "^6.0.0",
|
"bcrypt": "^6.0.0",
|
||||||
"cookies": "^0.9.1",
|
"cookies": "^0.9.1",
|
||||||
"ldapts": "8.0.9",
|
"ldapts": "8.0.9",
|
||||||
"next": "16.0.1",
|
"next": "16.0.3",
|
||||||
"next-auth": "5.0.0-beta.30",
|
"next-auth": "5.0.0-beta.30",
|
||||||
"react": "19.2.0",
|
"react": "19.2.0",
|
||||||
"react-dom": "19.2.0",
|
"react-dom": "19.2.0",
|
||||||
@@ -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"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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.27.0",
|
||||||
"eslint": "^9.39.0",
|
"eslint": "^9.39.1",
|
||||||
"typescript": "^5.9.3"
|
"typescript": "^5.9.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -32,7 +32,7 @@
|
|||||||
"@paralleldrive/cuid2": "^3.1.0",
|
"@paralleldrive/cuid2": "^3.1.0",
|
||||||
"dayjs": "^1.11.19",
|
"dayjs": "^1.11.19",
|
||||||
"dns-caching": "^0.2.7",
|
"dns-caching": "^0.2.7",
|
||||||
"next": "16.0.1",
|
"next": "16.0.3",
|
||||||
"octokit": "^5.0.5",
|
"octokit": "^5.0.5",
|
||||||
"react": "19.2.0",
|
"react": "19.2.0",
|
||||||
"react-dom": "19.2.0",
|
"react-dom": "19.2.0",
|
||||||
@@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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.9",
|
||||||
"@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",
|
||||||
@@ -42,8 +42,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/node-cron": "^3.0.11",
|
"@types/node-cron": "^3.0.11",
|
||||||
"@types/react": "19.2.2",
|
"@types/react": "19.2.5",
|
||||||
"eslint": "^9.39.0",
|
"eslint": "^9.39.1",
|
||||||
"typescript": "^5.9.3"
|
"typescript": "^5.9.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -49,13 +49,13 @@
|
|||||||
"@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.8",
|
||||||
"@paralleldrive/cuid2": "^3.1.0",
|
"@paralleldrive/cuid2": "^3.1.0",
|
||||||
"@testcontainers/mysql": "^11.7.2",
|
"@testcontainers/mysql": "^11.8.1",
|
||||||
"@testcontainers/postgresql": "^11.7.2",
|
"@testcontainers/postgresql": "^11.8.1",
|
||||||
"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.7",
|
||||||
"drizzle-orm": "^0.44.7",
|
"drizzle-orm": "^0.44.7",
|
||||||
"drizzle-zod": "^0.8.3",
|
"drizzle-zod": "^0.8.3",
|
||||||
"mysql2": "3.15.3",
|
"mysql2": "3.15.3",
|
||||||
@@ -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.27.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"
|
||||||
|
|||||||
@@ -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.2",
|
||||||
"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"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -145,7 +145,7 @@ export const integrationDefs = {
|
|||||||
},
|
},
|
||||||
piHole: {
|
piHole: {
|
||||||
name: "Pi-hole",
|
name: "Pi-hole",
|
||||||
secretKinds: [["apiKey"]],
|
secretKinds: [["apiKey"], []],
|
||||||
iconUrl: "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/svg/pi-hole.svg",
|
iconUrl: "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/svg/pi-hole.svg",
|
||||||
category: ["dnsHole"],
|
category: ["dnsHole"],
|
||||||
documentationUrl: createDocumentationLink("/docs/integrations/pi-hole"),
|
documentationUrl: createDocumentationLink("/docs/integrations/pi-hole"),
|
||||||
|
|||||||
@@ -32,8 +32,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",
|
||||||
"@types/dockerode": "^3.3.45",
|
"@types/dockerode": "^3.3.46",
|
||||||
"eslint": "^9.39.0",
|
"eslint": "^9.39.1",
|
||||||
"typescript": "^5.9.3"
|
"typescript": "^5.9.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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.8",
|
||||||
"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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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.8",
|
||||||
"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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -38,7 +38,7 @@ export type {
|
|||||||
FirewallMemorySummary,
|
FirewallMemorySummary,
|
||||||
} from "./interfaces/firewall-summary/firewall-summary-types";
|
} from "./interfaces/firewall-summary/firewall-summary-types";
|
||||||
export type { SystemHealthMonitoring } from "./interfaces/health-monitoring/health-monitoring-types";
|
export type { SystemHealthMonitoring } from "./interfaces/health-monitoring/health-monitoring-types";
|
||||||
export { MediaRequestStatus } from "./interfaces/media-requests/media-request-types";
|
export { UpstreamMediaRequestStatus } from "./interfaces/media-requests/media-request-types";
|
||||||
export type { MediaRequestList, MediaRequestStats } from "./interfaces/media-requests/media-request-types";
|
export type { MediaRequestList, MediaRequestStats } from "./interfaces/media-requests/media-request-types";
|
||||||
export type { StreamSession } from "./interfaces/media-server/media-server-types";
|
export type { StreamSession } from "./interfaces/media-server/media-server-types";
|
||||||
export type {
|
export type {
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { objectKeys } from "@homarr/common";
|
||||||
|
|
||||||
interface SerieSeason {
|
interface SerieSeason {
|
||||||
id: number;
|
id: number;
|
||||||
seasonNumber: number;
|
seasonNumber: number;
|
||||||
@@ -34,6 +36,64 @@ export interface MediaRequest {
|
|||||||
requestedBy?: Omit<RequestUser, "requestCount">;
|
requestedBy?: Omit<RequestUser, "requestCount">;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const mediaAvailabilityConfiguration = {
|
||||||
|
available: {
|
||||||
|
color: "green",
|
||||||
|
},
|
||||||
|
partiallyAvailable: {
|
||||||
|
color: "yellow",
|
||||||
|
},
|
||||||
|
processing: {
|
||||||
|
color: "blue",
|
||||||
|
},
|
||||||
|
requested: {
|
||||||
|
color: "violet",
|
||||||
|
},
|
||||||
|
pending: {
|
||||||
|
color: "violet",
|
||||||
|
},
|
||||||
|
unknown: {
|
||||||
|
color: "orange",
|
||||||
|
},
|
||||||
|
deleted: {
|
||||||
|
color: "red",
|
||||||
|
},
|
||||||
|
blacklisted: {
|
||||||
|
color: "gray",
|
||||||
|
},
|
||||||
|
} satisfies Record<string, { color: string }>;
|
||||||
|
|
||||||
|
export const mediaAvailabilities = objectKeys(mediaAvailabilityConfiguration);
|
||||||
|
|
||||||
|
export type MediaAvailability = (typeof mediaAvailabilities)[number];
|
||||||
|
|
||||||
|
export const mediaRequestStatusConfiguration = {
|
||||||
|
pending: {
|
||||||
|
color: "blue",
|
||||||
|
position: 1,
|
||||||
|
},
|
||||||
|
approved: {
|
||||||
|
color: "green",
|
||||||
|
position: 2,
|
||||||
|
},
|
||||||
|
declined: {
|
||||||
|
color: "red",
|
||||||
|
position: 3,
|
||||||
|
},
|
||||||
|
failed: {
|
||||||
|
color: "red",
|
||||||
|
position: 4,
|
||||||
|
},
|
||||||
|
completed: {
|
||||||
|
color: "green",
|
||||||
|
position: 5,
|
||||||
|
},
|
||||||
|
} satisfies Record<string, { color: string; position: number }>;
|
||||||
|
|
||||||
|
export const mediaRequestStatuses = objectKeys(mediaRequestStatusConfiguration);
|
||||||
|
|
||||||
|
export type MediaRequestStatus = (typeof mediaRequestStatuses)[number];
|
||||||
|
|
||||||
export interface MediaRequestList {
|
export interface MediaRequestList {
|
||||||
integration: {
|
integration: {
|
||||||
id: string;
|
id: string;
|
||||||
@@ -66,7 +126,7 @@ export interface MediaRequestStats {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// https://github.com/fallenbagel/jellyseerr/blob/0fd03f38480f853e7015ad9229ed98160e37602e/server/constants/media.ts#L1
|
// https://github.com/fallenbagel/jellyseerr/blob/0fd03f38480f853e7015ad9229ed98160e37602e/server/constants/media.ts#L1
|
||||||
export enum MediaRequestStatus {
|
export enum UpstreamMediaRequestStatus {
|
||||||
PendingApproval = 1,
|
PendingApproval = 1,
|
||||||
Approved = 2,
|
Approved = 2,
|
||||||
Declined = 3,
|
Declined = 3,
|
||||||
@@ -75,12 +135,12 @@ export enum MediaRequestStatus {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// https://github.com/fallenbagel/jellyseerr/blob/0fd03f38480f853e7015ad9229ed98160e37602e/server/constants/media.ts#L14
|
// https://github.com/fallenbagel/jellyseerr/blob/0fd03f38480f853e7015ad9229ed98160e37602e/server/constants/media.ts#L14
|
||||||
export enum MediaAvailability {
|
export enum UpstreamMediaAvailability {
|
||||||
Unknown = 1,
|
Unknown = 1,
|
||||||
Pending = 2,
|
Pending = 2,
|
||||||
Processing = 3,
|
Processing = 3,
|
||||||
PartiallyAvailable = 4,
|
PartiallyAvailable = 4,
|
||||||
Available = 5,
|
Available = 5,
|
||||||
Blacklisted = 6,
|
JellyseerrBlacklistedOrOverseerrDeleted = 6,
|
||||||
Deleted = 7,
|
JellyseerrDeleted = 7,
|
||||||
}
|
}
|
||||||
@@ -1,3 +1,12 @@
|
|||||||
|
import type { MediaAvailability } from "../interfaces/media-requests/media-request-types";
|
||||||
|
import { UpstreamMediaAvailability } from "../interfaces/media-requests/media-request-types";
|
||||||
import { OverseerrIntegration } from "../overseerr/overseerr-integration";
|
import { OverseerrIntegration } from "../overseerr/overseerr-integration";
|
||||||
|
|
||||||
export class JellyseerrIntegration extends OverseerrIntegration {}
|
export class JellyseerrIntegration extends OverseerrIntegration {
|
||||||
|
protected override mapAvailability(availability: UpstreamMediaAvailability, inProgress: boolean): MediaAvailability {
|
||||||
|
// Availability statuses are not exactly the same between Jellyseerr and Overseerr (Jellyseerr has "blacklisted" additionally (deleted is the same value in overseerr))
|
||||||
|
if (availability === UpstreamMediaAvailability.JellyseerrBlacklistedOrOverseerrDeleted) return "blacklisted";
|
||||||
|
if (availability === UpstreamMediaAvailability.JellyseerrDeleted) return "deleted";
|
||||||
|
return super.mapAvailability(availability, inProgress);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,8 +1,13 @@
|
|||||||
import { objectEntries } from "@homarr/common";
|
|
||||||
|
|
||||||
import type { IMediaRequestIntegration } from "../../interfaces/media-requests/media-request-integration";
|
import type { IMediaRequestIntegration } from "../../interfaces/media-requests/media-request-integration";
|
||||||
import type { MediaInformation, MediaRequest, RequestStats, RequestUser } from "../../types";
|
import type {
|
||||||
import { MediaAvailability, MediaRequestStatus } from "../../types";
|
MediaAvailability,
|
||||||
|
MediaInformation,
|
||||||
|
MediaRequest,
|
||||||
|
MediaRequestStatus,
|
||||||
|
RequestStats,
|
||||||
|
RequestUser,
|
||||||
|
} from "../../types";
|
||||||
|
import { mediaAvailabilities, mediaRequestStatuses } from "../../types";
|
||||||
|
|
||||||
export class MediaRequestMockService implements IMediaRequestIntegration {
|
export class MediaRequestMockService implements IMediaRequestIntegration {
|
||||||
public async getSeriesInformationAsync(mediaType: "movie" | "tv", id: number): Promise<MediaInformation> {
|
public async getSeriesInformationAsync(mediaType: "movie" | "tv", id: number): Promise<MediaInformation> {
|
||||||
@@ -86,12 +91,10 @@ export class MediaRequestMockService implements IMediaRequestIntegration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static randomAvailability(): MediaAvailability {
|
private static randomAvailability(): MediaAvailability {
|
||||||
const values = objectEntries(MediaAvailability).filter(([key]) => typeof key === "number");
|
return mediaAvailabilities.at(Math.floor(Math.random() * mediaAvailabilities.length)) ?? "unknown";
|
||||||
return values[Math.floor(Math.random() * values.length)]?.[1] ?? MediaAvailability.Available;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static randomStatus(): MediaRequestStatus {
|
private static randomStatus(): MediaRequestStatus {
|
||||||
const values = objectEntries(MediaRequestStatus).filter(([key]) => typeof key === "number");
|
return mediaRequestStatuses.at(Math.floor(Math.random() * mediaRequestStatuses.length)) ?? "pending";
|
||||||
return values[Math.floor(Math.random() * values.length)]?.[1] ?? MediaRequestStatus.PendingApproval;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -9,8 +9,17 @@ import type { ISearchableIntegration } from "../base/searchable-integration";
|
|||||||
import { TestConnectionError } from "../base/test-connection/test-connection-error";
|
import { TestConnectionError } from "../base/test-connection/test-connection-error";
|
||||||
import type { TestingResult } from "../base/test-connection/test-connection-service";
|
import type { TestingResult } from "../base/test-connection/test-connection-service";
|
||||||
import type { IMediaRequestIntegration } from "../interfaces/media-requests/media-request-integration";
|
import type { IMediaRequestIntegration } from "../interfaces/media-requests/media-request-integration";
|
||||||
import type { MediaRequest, RequestStats, RequestUser } from "../interfaces/media-requests/media-request-types";
|
import type {
|
||||||
import { MediaAvailability, MediaRequestStatus } from "../interfaces/media-requests/media-request-types";
|
MediaAvailability,
|
||||||
|
MediaRequest,
|
||||||
|
MediaRequestStatus,
|
||||||
|
RequestStats,
|
||||||
|
RequestUser,
|
||||||
|
} from "../interfaces/media-requests/media-request-types";
|
||||||
|
import {
|
||||||
|
UpstreamMediaAvailability,
|
||||||
|
UpstreamMediaRequestStatus,
|
||||||
|
} from "../interfaces/media-requests/media-request-types";
|
||||||
|
|
||||||
interface OverseerrSearchResult {
|
interface OverseerrSearchResult {
|
||||||
id: number;
|
id: number;
|
||||||
@@ -128,7 +137,7 @@ export class OverseerrIntegration
|
|||||||
|
|
||||||
if (pendingResults.length > 0 && allResults.length > 0) {
|
if (pendingResults.length > 0 && allResults.length > 0) {
|
||||||
requests = pendingResults.concat(
|
requests = pendingResults.concat(
|
||||||
allResults.filter(({ status }) => status !== MediaRequestStatus.PendingApproval),
|
allResults.filter(({ status }) => status !== UpstreamMediaRequestStatus.PendingApproval),
|
||||||
);
|
);
|
||||||
} else if (pendingResults.length > 0) requests = pendingResults;
|
} else if (pendingResults.length > 0) requests = pendingResults;
|
||||||
else if (allResults.length > 0) requests = allResults;
|
else if (allResults.length > 0) requests = allResults;
|
||||||
@@ -137,11 +146,15 @@ export class OverseerrIntegration
|
|||||||
return await Promise.all(
|
return await Promise.all(
|
||||||
requests.map(async (request): Promise<MediaRequest> => {
|
requests.map(async (request): Promise<MediaRequest> => {
|
||||||
const information = await this.getItemInformationAsync(request.media.tmdbId, request.type);
|
const information = await this.getItemInformationAsync(request.media.tmdbId, request.type);
|
||||||
|
|
||||||
|
// See https://github.com/seerr-team/seerr/blob/af083a3cd5c3e3d5d7917fdf4fdd67fe3f39c46b/src/components/StatusBadge/index.tsx#L40
|
||||||
|
const inProgress = (request.media.downloadStatus ?? []).length >= 1;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: request.id,
|
id: request.id,
|
||||||
name: information.name,
|
name: information.name,
|
||||||
status: request.status,
|
status: this.mapRequestStatus(request.status),
|
||||||
availability: request.media.status,
|
availability: this.mapAvailability(request.media.status, inProgress),
|
||||||
backdropImageUrl: `https://image.tmdb.org/t/p/original/${information.backdropPath}`,
|
backdropImageUrl: `https://image.tmdb.org/t/p/original/${information.backdropPath}`,
|
||||||
posterImagePath: `https://image.tmdb.org/t/p/w600_and_h900_bestv2/${information.posterPath}`,
|
posterImagePath: `https://image.tmdb.org/t/p/w600_and_h900_bestv2/${information.posterPath}`,
|
||||||
href: this.externalUrl(`/${request.type}/${request.media.tmdbId}`).toString(),
|
href: this.externalUrl(`/${request.type}/${request.media.tmdbId}`).toString(),
|
||||||
@@ -161,6 +174,42 @@ export class OverseerrIntegration
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected mapRequestStatus(status: UpstreamMediaRequestStatus): MediaRequestStatus {
|
||||||
|
switch (status) {
|
||||||
|
case UpstreamMediaRequestStatus.PendingApproval:
|
||||||
|
return "pending";
|
||||||
|
case UpstreamMediaRequestStatus.Approved:
|
||||||
|
return "approved";
|
||||||
|
case UpstreamMediaRequestStatus.Declined:
|
||||||
|
return "declined";
|
||||||
|
case UpstreamMediaRequestStatus.Failed:
|
||||||
|
return "failed";
|
||||||
|
case UpstreamMediaRequestStatus.Completed:
|
||||||
|
return "completed";
|
||||||
|
default:
|
||||||
|
return "failed";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// See https://github.com/seerr-team/seerr/blob/af083a3cd5c3e3d5d7917fdf4fdd67fe3f39c46b/src/components/StatusBadge/index.tsx#L153-L387
|
||||||
|
protected mapAvailability(availability: UpstreamMediaAvailability, inProgress: boolean): MediaAvailability {
|
||||||
|
switch (availability) {
|
||||||
|
case UpstreamMediaAvailability.Available:
|
||||||
|
return inProgress ? "processing" : "available";
|
||||||
|
case UpstreamMediaAvailability.PartiallyAvailable:
|
||||||
|
return inProgress ? "processing" : "partiallyAvailable";
|
||||||
|
case UpstreamMediaAvailability.Processing:
|
||||||
|
return inProgress ? "processing" : "requested";
|
||||||
|
case UpstreamMediaAvailability.Pending:
|
||||||
|
return "pending";
|
||||||
|
case UpstreamMediaAvailability.JellyseerrBlacklistedOrOverseerrDeleted:
|
||||||
|
return "deleted";
|
||||||
|
case UpstreamMediaAvailability.Unknown:
|
||||||
|
default:
|
||||||
|
return inProgress ? "processing" : "unknown";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public async getStatsAsync(): Promise<RequestStats> {
|
public async getStatsAsync(): Promise<RequestStats> {
|
||||||
const response = await fetchWithTrustedCertificatesAsync(this.url("/api/v1/request/count"), {
|
const response = await fetchWithTrustedCertificatesAsync(this.url("/api/v1/request/count"), {
|
||||||
headers: {
|
headers: {
|
||||||
@@ -339,11 +388,12 @@ const getRequestsSchema = z.object({
|
|||||||
.array(
|
.array(
|
||||||
z.object({
|
z.object({
|
||||||
id: z.number(),
|
id: z.number(),
|
||||||
status: z.nativeEnum(MediaRequestStatus),
|
status: z.enum(UpstreamMediaRequestStatus),
|
||||||
createdAt: z.string().transform((value) => new Date(value)),
|
createdAt: z.string().transform((value) => new Date(value)),
|
||||||
media: z.object({
|
media: z.object({
|
||||||
status: z.nativeEnum(MediaAvailability),
|
status: z.enum(UpstreamMediaAvailability),
|
||||||
tmdbId: z.number(),
|
tmdbId: z.number(),
|
||||||
|
downloadStatus: z.array(z.unknown()).optional(),
|
||||||
}),
|
}),
|
||||||
type: z.enum(["movie", "tv"]),
|
type: z.enum(["movie", "tv"]),
|
||||||
requestedBy: z
|
requestedBy: z
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import { dnsBlockingGetSchema, sessionResponseSchema, statsSummaryGetSchema } fr
|
|||||||
const localLogger = logger.child({ module: "PiHoleIntegrationV6" });
|
const localLogger = logger.child({ module: "PiHoleIntegrationV6" });
|
||||||
|
|
||||||
export class PiHoleIntegrationV6 extends Integration implements DnsHoleSummaryIntegration {
|
export class PiHoleIntegrationV6 extends Integration implements DnsHoleSummaryIntegration {
|
||||||
private readonly sessionStore: SessionStore<string>;
|
private readonly sessionStore: SessionStore<{ sid: string | null }>;
|
||||||
|
|
||||||
constructor(integration: IntegrationInput) {
|
constructor(integration: IntegrationInput) {
|
||||||
super(integration);
|
super(integration);
|
||||||
@@ -28,7 +28,7 @@ export class PiHoleIntegrationV6 extends Integration implements DnsHoleSummaryIn
|
|||||||
const response = await this.withAuthAsync(async (sessionId) => {
|
const response = await this.withAuthAsync(async (sessionId) => {
|
||||||
return await fetchWithTrustedCertificatesAsync(this.url("/api/dns/blocking"), {
|
return await fetchWithTrustedCertificatesAsync(this.url("/api/dns/blocking"), {
|
||||||
headers: {
|
headers: {
|
||||||
sid: sessionId,
|
sid: sessionId ?? undefined,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -46,7 +46,7 @@ export class PiHoleIntegrationV6 extends Integration implements DnsHoleSummaryIn
|
|||||||
const response = await this.withAuthAsync(async (sessionId) => {
|
const response = await this.withAuthAsync(async (sessionId) => {
|
||||||
return fetchWithTrustedCertificatesAsync(this.url("/api/stats/summary"), {
|
return fetchWithTrustedCertificatesAsync(this.url("/api/stats/summary"), {
|
||||||
headers: {
|
headers: {
|
||||||
sid: sessionId,
|
sid: sessionId ?? undefined,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -85,7 +85,7 @@ export class PiHoleIntegrationV6 extends Integration implements DnsHoleSummaryIn
|
|||||||
const response = await this.withAuthAsync(async (sessionId) => {
|
const response = await this.withAuthAsync(async (sessionId) => {
|
||||||
return await fetchWithTrustedCertificatesAsync(this.url("/api/dns/blocking"), {
|
return await fetchWithTrustedCertificatesAsync(this.url("/api/dns/blocking"), {
|
||||||
headers: {
|
headers: {
|
||||||
sid: sessionId,
|
sid: sessionId ?? undefined,
|
||||||
},
|
},
|
||||||
body: JSON.stringify({ blocking: true }),
|
body: JSON.stringify({ blocking: true }),
|
||||||
method: "POST",
|
method: "POST",
|
||||||
@@ -101,7 +101,7 @@ export class PiHoleIntegrationV6 extends Integration implements DnsHoleSummaryIn
|
|||||||
const response = await this.withAuthAsync(async (sessionId) => {
|
const response = await this.withAuthAsync(async (sessionId) => {
|
||||||
return await fetchWithTrustedCertificatesAsync(this.url("/api/dns/blocking"), {
|
return await fetchWithTrustedCertificatesAsync(this.url("/api/dns/blocking"), {
|
||||||
headers: {
|
headers: {
|
||||||
sid: sessionId,
|
sid: sessionId ?? undefined,
|
||||||
},
|
},
|
||||||
body: JSON.stringify({ blocking: false, timer: duration }),
|
body: JSON.stringify({ blocking: false, timer: duration }),
|
||||||
method: "POST",
|
method: "POST",
|
||||||
@@ -118,12 +118,16 @@ export class PiHoleIntegrationV6 extends Integration implements DnsHoleSummaryIn
|
|||||||
* @param callback
|
* @param callback
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
private async withAuthAsync(callback: (sessionId: string) => Promise<UndiciResponse>) {
|
private async withAuthAsync(callback: (sessionId: string | null) => Promise<UndiciResponse>) {
|
||||||
|
if (!super.hasSecretValue("apiKey")) {
|
||||||
|
return await callback(null);
|
||||||
|
}
|
||||||
|
|
||||||
const storedSession = await this.sessionStore.getAsync();
|
const storedSession = await this.sessionStore.getAsync();
|
||||||
|
|
||||||
if (storedSession) {
|
if (storedSession) {
|
||||||
localLogger.debug("Using stored session for request", { integrationId: this.integration.id });
|
localLogger.debug("Using stored session for request", { integrationId: this.integration.id });
|
||||||
const response = await callback(storedSession);
|
const response = await callback(storedSession.sid);
|
||||||
if (response.status !== 401) {
|
if (response.status !== 401) {
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
@@ -132,7 +136,7 @@ export class PiHoleIntegrationV6 extends Integration implements DnsHoleSummaryIn
|
|||||||
}
|
}
|
||||||
|
|
||||||
const sessionId = await this.getSessionAsync();
|
const sessionId = await this.getSessionAsync();
|
||||||
await this.sessionStore.setAsync(sessionId);
|
await this.sessionStore.setAsync({ sid: sessionId });
|
||||||
const response = await callback(sessionId);
|
const response = await callback(sessionId);
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
@@ -141,11 +145,13 @@ export class PiHoleIntegrationV6 extends Integration implements DnsHoleSummaryIn
|
|||||||
* Get a session id from the Pi-hole server
|
* Get a session id from the Pi-hole server
|
||||||
* @returns The session id
|
* @returns The session id
|
||||||
*/
|
*/
|
||||||
private async getSessionAsync(fetchAsync: typeof undiciFetch = fetchWithTrustedCertificatesAsync): Promise<string> {
|
private async getSessionAsync(
|
||||||
const apiKey = super.getSecretValue("apiKey");
|
fetchAsync: typeof undiciFetch = fetchWithTrustedCertificatesAsync,
|
||||||
|
): Promise<string | null> {
|
||||||
|
const apiKey = super.hasSecretValue("apiKey") ? super.getSecretValue("apiKey") : null;
|
||||||
const response = await fetchAsync(this.url("/api/auth"), {
|
const response = await fetchAsync(this.url("/api/auth"), {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
body: JSON.stringify({ password: apiKey }),
|
body: JSON.stringify({ password: apiKey ?? "" }),
|
||||||
headers: {
|
headers: {
|
||||||
"User-Agent": "Homarr",
|
"User-Agent": "Homarr",
|
||||||
},
|
},
|
||||||
@@ -156,8 +162,13 @@ export class PiHoleIntegrationV6 extends Integration implements DnsHoleSummaryIn
|
|||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
const result = await sessionResponseSchema.parseAsync(data);
|
const result = await sessionResponseSchema.parseAsync(data);
|
||||||
|
|
||||||
if (!result.session.sid) {
|
if (!result.session.valid) {
|
||||||
throw new ResponseError({ status: 401, url: response.url });
|
throw new ResponseError(
|
||||||
|
{ status: 401, url: response.url },
|
||||||
|
{
|
||||||
|
cause: result.session.message ? new Error(result.session.message) : undefined,
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
localLogger.info("Received session id successfully", { integrationId: this.integration.id });
|
localLogger.info("Received session id successfully", { integrationId: this.integration.id });
|
||||||
@@ -170,9 +181,14 @@ export class PiHoleIntegrationV6 extends Integration implements DnsHoleSummaryIn
|
|||||||
* @param sessionId The session id to remove
|
* @param sessionId The session id to remove
|
||||||
*/
|
*/
|
||||||
private async clearSessionAsync(
|
private async clearSessionAsync(
|
||||||
sessionId: string,
|
sessionId: string | null,
|
||||||
fetchAsync: typeof undiciFetch = fetchWithTrustedCertificatesAsync,
|
fetchAsync: typeof undiciFetch = fetchWithTrustedCertificatesAsync,
|
||||||
) {
|
) {
|
||||||
|
if (!sessionId) {
|
||||||
|
localLogger.debug("No session id to clear");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const response = await fetchAsync(this.url("/api/auth"), {
|
const response = await fetchAsync(this.url("/api/auth"), {
|
||||||
method: "DELETE",
|
method: "DELETE",
|
||||||
headers: {
|
headers: {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { z } from "zod/v4";
|
|||||||
|
|
||||||
export const sessionResponseSchema = z.object({
|
export const sessionResponseSchema = z.object({
|
||||||
session: z.object({
|
session: z.object({
|
||||||
|
valid: z.boolean(),
|
||||||
sid: z.string().nullable(),
|
sid: z.string().nullable(),
|
||||||
message: z.string().nullable(),
|
message: z.string().nullable(),
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -33,10 +33,10 @@
|
|||||||
"@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.8",
|
||||||
"@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.3",
|
||||||
"react": "19.2.0",
|
"react": "19.2.0",
|
||||||
"react-dom": "19.2.0",
|
"react-dom": "19.2.0",
|
||||||
"zod": "^4.1.12"
|
"zod": "^4.1.12"
|
||||||
@@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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.8",
|
||||||
"@mantine/hooks": "^8.3.6",
|
"@mantine/hooks": "^8.3.8",
|
||||||
"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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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.8",
|
||||||
"@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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -37,10 +37,10 @@
|
|||||||
"@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.8",
|
||||||
"@mantine/hooks": "^8.3.6",
|
"@mantine/hooks": "^8.3.8",
|
||||||
"adm-zip": "0.5.16",
|
"adm-zip": "0.5.16",
|
||||||
"next": "16.0.1",
|
"next": "16.0.3",
|
||||||
"react": "19.2.0",
|
"react": "19.2.0",
|
||||||
"react-dom": "19.2.0",
|
"react-dom": "19.2.0",
|
||||||
"superjson": "2.2.5",
|
"superjson": "2.2.5",
|
||||||
@@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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()),
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -26,8 +26,8 @@
|
|||||||
"@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.8",
|
||||||
"next": "16.0.1",
|
"next": "16.0.3",
|
||||||
"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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -33,12 +33,12 @@
|
|||||||
"@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.8",
|
||||||
"@mantine/hooks": "^8.3.6",
|
"@mantine/hooks": "^8.3.8",
|
||||||
"@mantine/spotlight": "^8.3.6",
|
"@mantine/spotlight": "^8.3.8",
|
||||||
"@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.3",
|
||||||
"react": "19.2.0",
|
"react": "19.2.0",
|
||||||
"react-dom": "19.2.0",
|
"react-dom": "19.2.0",
|
||||||
"use-deep-compare-effect": "^1.8.1"
|
"use-deep-compare-effect": "^1.8.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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -32,8 +32,8 @@
|
|||||||
"dayjs": "^1.11.19",
|
"dayjs": "^1.11.19",
|
||||||
"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.3",
|
||||||
"next-intl": "4.4.0",
|
"next-intl": "4.5.3",
|
||||||
"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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -649,14 +649,14 @@
|
|||||||
"app": {
|
"app": {
|
||||||
"option": {
|
"option": {
|
||||||
"existing": {
|
"existing": {
|
||||||
"title": "",
|
"title": "现有",
|
||||||
"label": ""
|
"label": "选择现有应用"
|
||||||
},
|
},
|
||||||
"new": {
|
"new": {
|
||||||
"title": "",
|
"title": "新建",
|
||||||
"url": {
|
"url": {
|
||||||
"label": "",
|
"label": "应用网址",
|
||||||
"description": ""
|
"description": "当从面板访问时应用将打开的网址"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -676,9 +676,9 @@
|
|||||||
},
|
},
|
||||||
"app": {
|
"app": {
|
||||||
"action": {
|
"action": {
|
||||||
"add": "",
|
"add": "链接应用",
|
||||||
"remove": "",
|
"remove": "取消连接",
|
||||||
"select": ""
|
"select": "选择要链接的应用"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -709,7 +709,7 @@
|
|||||||
"description": "集成“{kind}”可以与搜索引擎一起使用。勾选此项可自动配置搜索引擎。"
|
"description": "集成“{kind}”可以与搜索引擎一起使用。勾选此项可自动配置搜索引擎。"
|
||||||
},
|
},
|
||||||
"app": {
|
"app": {
|
||||||
"sectionTitle": ""
|
"sectionTitle": "关联的应用"
|
||||||
},
|
},
|
||||||
"createApp": {
|
"createApp": {
|
||||||
"label": "创建应用",
|
"label": "创建应用",
|
||||||
@@ -1051,7 +1051,7 @@
|
|||||||
"add": "添加",
|
"add": "添加",
|
||||||
"apply": "应用",
|
"apply": "应用",
|
||||||
"backToOverview": "返回概览",
|
"backToOverview": "返回概览",
|
||||||
"change": "",
|
"change": "更改",
|
||||||
"create": "创建",
|
"create": "创建",
|
||||||
"createAnother": "创建并重新开始",
|
"createAnother": "创建并重新开始",
|
||||||
"edit": "编辑",
|
"edit": "编辑",
|
||||||
|
|||||||
@@ -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": {
|
||||||
|
|||||||
@@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2232,6 +2232,7 @@
|
|||||||
"unknown": "Unknown",
|
"unknown": "Unknown",
|
||||||
"pending": "Pending",
|
"pending": "Pending",
|
||||||
"processing": "Processing",
|
"processing": "Processing",
|
||||||
|
"requested": "Requested",
|
||||||
"partiallyAvailable": "Partial",
|
"partiallyAvailable": "Partial",
|
||||||
"available": "Available",
|
"available": "Available",
|
||||||
"blacklisted": "Blacklisted",
|
"blacklisted": "Blacklisted",
|
||||||
|
|||||||
@@ -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": ""
|
||||||
}
|
}
|
||||||
@@ -3748,7 +3748,7 @@
|
|||||||
"label": "Nome"
|
"label": "Nome"
|
||||||
},
|
},
|
||||||
"namespace": {
|
"namespace": {
|
||||||
"label": ""
|
"label": "Spazio dei nomi"
|
||||||
},
|
},
|
||||||
"className": {
|
"className": {
|
||||||
"label": "Nome classe"
|
"label": "Nome classe"
|
||||||
|
|||||||
@@ -649,14 +649,14 @@
|
|||||||
"app": {
|
"app": {
|
||||||
"option": {
|
"option": {
|
||||||
"existing": {
|
"existing": {
|
||||||
"title": "",
|
"title": "既存",
|
||||||
"label": ""
|
"label": "既存のアプリを選択"
|
||||||
},
|
},
|
||||||
"new": {
|
"new": {
|
||||||
"title": "",
|
"title": "新規作成",
|
||||||
"url": {
|
"url": {
|
||||||
"label": "",
|
"label": "アプリURL",
|
||||||
"description": ""
|
"description": "ダッシュボードからアクセスしたときにアプリが開くURL"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -676,9 +676,9 @@
|
|||||||
},
|
},
|
||||||
"app": {
|
"app": {
|
||||||
"action": {
|
"action": {
|
||||||
"add": "",
|
"add": "アプリにリンクする",
|
||||||
"remove": "",
|
"remove": "リンクを解除する",
|
||||||
"select": ""
|
"select": "リンクするアプリを選択する"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -709,7 +709,7 @@
|
|||||||
"description": "連携機能 \"{kind}\" は、検索エンジンで使用できます。検索エンジンを自動的に設定するには、これにチェックを入れてください。"
|
"description": "連携機能 \"{kind}\" は、検索エンジンで使用できます。検索エンジンを自動的に設定するには、これにチェックを入れてください。"
|
||||||
},
|
},
|
||||||
"app": {
|
"app": {
|
||||||
"sectionTitle": ""
|
"sectionTitle": "リンクされたアプリ"
|
||||||
},
|
},
|
||||||
"createApp": {
|
"createApp": {
|
||||||
"label": "アプリの作成",
|
"label": "アプリの作成",
|
||||||
@@ -1051,7 +1051,7 @@
|
|||||||
"add": "追加",
|
"add": "追加",
|
||||||
"apply": "適用",
|
"apply": "適用",
|
||||||
"backToOverview": "概要に戻る",
|
"backToOverview": "概要に戻る",
|
||||||
"change": "",
|
"change": "変更する",
|
||||||
"create": "作成",
|
"create": "作成",
|
||||||
"createAnother": "作成・新規入力",
|
"createAnother": "作成・新規入力",
|
||||||
"edit": "編集",
|
"edit": "編集",
|
||||||
@@ -1174,8 +1174,8 @@
|
|||||||
},
|
},
|
||||||
"unit": {
|
"unit": {
|
||||||
"speed": {
|
"speed": {
|
||||||
"kilometersPerHour": "",
|
"kilometersPerHour": "km/h",
|
||||||
"milesPerHour": ""
|
"milesPerHour": "mph"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -1190,7 +1190,7 @@
|
|||||||
"label": "タイトル"
|
"label": "タイトル"
|
||||||
},
|
},
|
||||||
"customCssClasses": {
|
"customCssClasses": {
|
||||||
"label": ""
|
"label": "カスタム css クラス"
|
||||||
},
|
},
|
||||||
"borderColor": {
|
"borderColor": {
|
||||||
"label": "境界線の色"
|
"label": "境界線の色"
|
||||||
@@ -1780,7 +1780,7 @@
|
|||||||
"description": "現在の天気のみ表示"
|
"description": "現在の天気のみ表示"
|
||||||
},
|
},
|
||||||
"useImperialSpeed": {
|
"useImperialSpeed": {
|
||||||
"label": ""
|
"label": "風速にmphを使用する"
|
||||||
},
|
},
|
||||||
"location": {
|
"location": {
|
||||||
"label": "天候の場所"
|
"label": "天候の場所"
|
||||||
@@ -1800,12 +1800,12 @@
|
|||||||
"description": "日付がどのように見えるか"
|
"description": "日付がどのように見えるか"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"currentWindSpeed": "時速 {currentWindSpeed} km",
|
"currentWindSpeed": "時速 {currentWindSpeed} {unit}",
|
||||||
"dailyForecast": {
|
"dailyForecast": {
|
||||||
"sunrise": "日出",
|
"sunrise": "日出",
|
||||||
"sunset": "日没",
|
"sunset": "日没",
|
||||||
"maxWindSpeed": "最大風速: {maxWindSpeed} km/h",
|
"maxWindSpeed": "最大風速: {maxWindSpeed} {unit}",
|
||||||
"maxWindGusts": "最大瞬間風速: {maxWindGusts} km/h"
|
"maxWindGusts": "最大瞬間風速: {maxWindGusts} {unit}"
|
||||||
},
|
},
|
||||||
"kind": {
|
"kind": {
|
||||||
"clear": "晴れ",
|
"clear": "晴れ",
|
||||||
@@ -3013,8 +3013,8 @@
|
|||||||
"integration": "連携機能",
|
"integration": "連携機能",
|
||||||
"app": "アプリ",
|
"app": "アプリ",
|
||||||
"group": "グループ",
|
"group": "グループ",
|
||||||
"searchEngine": "",
|
"searchEngine": "検索エンジン",
|
||||||
"media": ""
|
"media": "メディア"
|
||||||
},
|
},
|
||||||
"statisticLabel": {
|
"statisticLabel": {
|
||||||
"boards": "ボード",
|
"boards": "ボード",
|
||||||
@@ -3023,8 +3023,8 @@
|
|||||||
"authorization": "認可"
|
"authorization": "認可"
|
||||||
},
|
},
|
||||||
"heroBanner": {
|
"heroBanner": {
|
||||||
"title": "",
|
"title": "おかえりなさい",
|
||||||
"subtitle": ""
|
"subtitle": "{app} ボード"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"board": {
|
"board": {
|
||||||
|
|||||||
@@ -30,12 +30,12 @@
|
|||||||
"@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.8",
|
||||||
"@mantine/dates": "^8.3.6",
|
"@mantine/dates": "^8.3.8",
|
||||||
"@mantine/hooks": "^8.3.6",
|
"@mantine/hooks": "^8.3.8",
|
||||||
"@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.3",
|
||||||
"react": "19.2.0",
|
"react": "19.2.0",
|
||||||
"react-dom": "19.2.0",
|
"react-dom": "19.2.0",
|
||||||
"svgson": "^5.3.1"
|
"svgson": "^5.3.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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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.8",
|
||||||
"@mantine/core": "^8.3.6",
|
"@mantine/core": "^8.3.8",
|
||||||
"@mantine/hooks": "^8.3.6",
|
"@mantine/hooks": "^8.3.8",
|
||||||
"@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",
|
||||||
@@ -72,7 +72,7 @@
|
|||||||
"dayjs": "^1.11.19",
|
"dayjs": "^1.11.19",
|
||||||
"mantine-form-zod-resolver": "^1.3.0",
|
"mantine-form-zod-resolver": "^1.3.0",
|
||||||
"mantine-react-table": "2.0.0-beta.9",
|
"mantine-react-table": "2.0.0-beta.9",
|
||||||
"next": "16.0.1",
|
"next": "16.0.3",
|
||||||
"react": "19.2.0",
|
"react": "19.2.0",
|
||||||
"react-dom": "19.2.0",
|
"react-dom": "19.2.0",
|
||||||
"react-markdown": "^10.1.0",
|
"react-markdown": "^10.1.0",
|
||||||
@@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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,28 @@ 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",
|
||||||
|
"allow-top-navigation-by-user-activation",
|
||||||
|
];
|
||||||
|
|
||||||
|
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",
|
||||||
|
|||||||
@@ -3,10 +3,11 @@
|
|||||||
import { ActionIcon, Anchor, Avatar, Badge, Card, Group, Image, ScrollArea, Stack, Text, Tooltip } from "@mantine/core";
|
import { ActionIcon, Anchor, Avatar, Badge, Card, Group, Image, ScrollArea, Stack, Text, Tooltip } from "@mantine/core";
|
||||||
import { IconThumbDown, IconThumbUp } from "@tabler/icons-react";
|
import { IconThumbDown, IconThumbUp } from "@tabler/icons-react";
|
||||||
|
|
||||||
|
import type { RouterInputs, RouterOutputs } from "@homarr/api";
|
||||||
import { clientApi } from "@homarr/api/client";
|
import { clientApi } from "@homarr/api/client";
|
||||||
import { useRequiredBoard } from "@homarr/boards/context";
|
import { useRequiredBoard } from "@homarr/boards/context";
|
||||||
import { MediaAvailability, MediaRequestStatus } from "@homarr/integrations/types";
|
import type { MediaRequestStatus } from "@homarr/integrations/types";
|
||||||
import type { ScopedTranslationFunction } from "@homarr/translation";
|
import { mediaAvailabilityConfiguration, mediaRequestStatusConfiguration } from "@homarr/integrations/types";
|
||||||
import { useScopedI18n } from "@homarr/translation/client";
|
import { useScopedI18n } from "@homarr/translation/client";
|
||||||
|
|
||||||
import type { WidgetComponentProps } from "../../definition";
|
import type { WidgetComponentProps } from "../../definition";
|
||||||
@@ -18,7 +19,6 @@ export default function MediaServerWidget({
|
|||||||
options,
|
options,
|
||||||
width,
|
width,
|
||||||
}: WidgetComponentProps<"mediaRequests-requestList">) {
|
}: WidgetComponentProps<"mediaRequests-requestList">) {
|
||||||
const t = useScopedI18n("widget.mediaRequests-requestList");
|
|
||||||
const [mediaRequests] = clientApi.widget.mediaRequests.getLatestRequests.useSuspenseQuery(
|
const [mediaRequests] = clientApi.widget.mediaRequests.getLatestRequests.useSuspenseQuery(
|
||||||
{
|
{
|
||||||
integrationIds,
|
integrationIds,
|
||||||
@@ -48,20 +48,18 @@ export default function MediaServerWidget({
|
|||||||
return dataB.createdAt.getTime() - dataA.createdAt.getTime();
|
return dataB.createdAt.getTime() - dataA.createdAt.getTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
return dataA.status - dataB.status;
|
return (
|
||||||
|
mediaRequestStatusConfiguration[dataA.status].position -
|
||||||
|
mediaRequestStatusConfiguration[dataB.status].position
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
const { mutate: mutateRequestAnswer } = clientApi.widget.mediaRequests.answerRequest.useMutation();
|
|
||||||
const board = useRequiredBoard();
|
|
||||||
|
|
||||||
if (mediaRequests.length === 0) throw new NoIntegrationDataError();
|
if (mediaRequests.length === 0) throw new NoIntegrationDataError();
|
||||||
|
|
||||||
const isTiny = width < 256;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ScrollArea
|
<ScrollArea
|
||||||
className="mediaRequests-list-scrollArea"
|
className="mediaRequests-list-scrollArea"
|
||||||
@@ -70,193 +68,188 @@ export default function MediaServerWidget({
|
|||||||
>
|
>
|
||||||
<Stack className="mediaRequests-list-list" gap="xs" p="sm">
|
<Stack className="mediaRequests-list-list" gap="xs" p="sm">
|
||||||
{mediaRequests.map((mediaRequest) => (
|
{mediaRequests.map((mediaRequest) => (
|
||||||
<Card
|
<MediaRequestCard
|
||||||
className={`mediaRequests-list-item-wrapper mediaRequests-list-item-${mediaRequest.type} mediaRequests-list-item-${mediaRequest.status}`}
|
|
||||||
key={`${mediaRequest.integrationId}-${mediaRequest.id}`}
|
key={`${mediaRequest.integrationId}-${mediaRequest.id}`}
|
||||||
radius={board.itemRadius}
|
request={mediaRequest}
|
||||||
p="xs"
|
isTiny={width <= 256}
|
||||||
withBorder
|
options={options}
|
||||||
>
|
/>
|
||||||
<Image
|
|
||||||
className="mediaRequests-list-item-background"
|
|
||||||
src={mediaRequest.backdropImageUrl}
|
|
||||||
pos="absolute"
|
|
||||||
w="100%"
|
|
||||||
h="100%"
|
|
||||||
opacity={0.2}
|
|
||||||
top={0}
|
|
||||||
left={0}
|
|
||||||
alt=""
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Group
|
|
||||||
className="mediaRequests-list-item-contents"
|
|
||||||
h="100%"
|
|
||||||
style={{ zIndex: 1 }}
|
|
||||||
justify="space-between"
|
|
||||||
wrap="nowrap"
|
|
||||||
gap={0}
|
|
||||||
>
|
|
||||||
<Group className="mediaRequests-list-item-left-side" h="100%" gap="md" wrap="nowrap" flex={1}>
|
|
||||||
{!isTiny && (
|
|
||||||
<Image
|
|
||||||
className="mediaRequests-list-item-poster"
|
|
||||||
src={mediaRequest.posterImagePath}
|
|
||||||
h={40}
|
|
||||||
w="auto"
|
|
||||||
radius={"md"}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<Stack gap={0} w="100%">
|
|
||||||
<Group justify="space-between" gap="xs" className="mediaRequests-list-item-top-group">
|
|
||||||
<Group gap="xs">
|
|
||||||
<Text className="mediaRequests-list-item-media-year" size="xs">
|
|
||||||
{mediaRequest.airDate?.getFullYear() ?? t("toBeDetermined")}
|
|
||||||
</Text>
|
|
||||||
{!isTiny && (
|
|
||||||
<Badge
|
|
||||||
className="mediaRequests-list-item-media-status"
|
|
||||||
color={getAvailabilityProperties(mediaRequest.availability, t).color}
|
|
||||||
variant="light"
|
|
||||||
size="xs"
|
|
||||||
>
|
|
||||||
{getAvailabilityProperties(mediaRequest.availability, t).label}
|
|
||||||
</Badge>
|
|
||||||
)}
|
|
||||||
</Group>
|
|
||||||
<Group className="mediaRequests-list-item-request-user" gap={4} wrap="nowrap">
|
|
||||||
<Avatar
|
|
||||||
className="mediaRequests-list-item-request-user-avatar"
|
|
||||||
src={mediaRequest.requestedBy?.avatar}
|
|
||||||
size="xs"
|
|
||||||
/>
|
|
||||||
<Anchor
|
|
||||||
className="mediaRequests-list-item-request-user-name"
|
|
||||||
href={mediaRequest.requestedBy?.link}
|
|
||||||
c="var(--mantine-color-text)"
|
|
||||||
target={options.linksTargetNewTab ? "_blank" : "_self"}
|
|
||||||
fz="xs"
|
|
||||||
lineClamp={1}
|
|
||||||
style={{ wordBreak: "break-all" }}
|
|
||||||
>
|
|
||||||
{(mediaRequest.requestedBy?.displayName ?? "") || "unknown"}
|
|
||||||
</Anchor>
|
|
||||||
</Group>
|
|
||||||
</Group>
|
|
||||||
<Group gap="xs" justify="space-between" className="mediaRequests-list-item-bottom-group">
|
|
||||||
<Anchor
|
|
||||||
className="mediaRequests-list-item-info-second-line mediaRequests-list-item-media-title"
|
|
||||||
href={mediaRequest.href}
|
|
||||||
c="var(--mantine-color-text)"
|
|
||||||
target={options.linksTargetNewTab ? "_blank" : "_self"}
|
|
||||||
fz={isTiny ? "xs" : "sm"}
|
|
||||||
fw={"bold"}
|
|
||||||
title={mediaRequest.name}
|
|
||||||
lineClamp={1}
|
|
||||||
>
|
|
||||||
{mediaRequest.name || "unknown"}
|
|
||||||
</Anchor>
|
|
||||||
{mediaRequest.status === MediaRequestStatus.PendingApproval ? (
|
|
||||||
<Group className="mediaRequests-list-item-pending-buttons" gap="sm">
|
|
||||||
<Tooltip label={t("pending.approve")}>
|
|
||||||
<ActionIcon
|
|
||||||
className="mediaRequests-list-item-pending-button-approve"
|
|
||||||
variant="light"
|
|
||||||
color="green"
|
|
||||||
size="xs"
|
|
||||||
radius="md"
|
|
||||||
onClick={() => {
|
|
||||||
mutateRequestAnswer({
|
|
||||||
integrationId: mediaRequest.integrationId,
|
|
||||||
requestId: mediaRequest.id,
|
|
||||||
answer: "approve",
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<IconThumbUp size={16} />
|
|
||||||
</ActionIcon>
|
|
||||||
</Tooltip>
|
|
||||||
<Tooltip label={t("pending.decline")}>
|
|
||||||
<ActionIcon
|
|
||||||
className="mediaRequests-list-item-pending-button-decline"
|
|
||||||
variant="light"
|
|
||||||
color="red"
|
|
||||||
size="xs"
|
|
||||||
radius="md"
|
|
||||||
onClick={() => {
|
|
||||||
mutateRequestAnswer({
|
|
||||||
integrationId: mediaRequest.integrationId,
|
|
||||||
requestId: mediaRequest.id,
|
|
||||||
answer: "decline",
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<IconThumbDown size={16} />
|
|
||||||
</ActionIcon>
|
|
||||||
</Tooltip>
|
|
||||||
</Group>
|
|
||||||
) : (
|
|
||||||
<StatusBadge status={mediaRequest.status} />
|
|
||||||
)}
|
|
||||||
</Group>
|
|
||||||
</Stack>
|
|
||||||
</Group>
|
|
||||||
</Group>
|
|
||||||
</Card>
|
|
||||||
))}
|
))}
|
||||||
</Stack>
|
</Stack>
|
||||||
</ScrollArea>
|
</ScrollArea>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const statusMapping = {
|
interface MediaRequestCardProps {
|
||||||
[MediaRequestStatus.PendingApproval]: { color: "blue", label: (t) => t("pending") },
|
request: RouterOutputs["widget"]["mediaRequests"]["getLatestRequests"][number];
|
||||||
[MediaRequestStatus.Approved]: { color: "green", label: (t) => t("approved") },
|
isTiny: boolean;
|
||||||
[MediaRequestStatus.Declined]: { color: "red", label: (t) => t("declined") },
|
options: WidgetComponentProps<"mediaRequests-requestList">["options"];
|
||||||
[MediaRequestStatus.Failed]: { color: "red", label: (t) => t("failed") },
|
}
|
||||||
[MediaRequestStatus.Completed]: { color: "green", label: (t) => t("completed") },
|
|
||||||
} satisfies Record<
|
const MediaRequestCard = ({ request, isTiny, options }: MediaRequestCardProps) => {
|
||||||
MediaRequestStatus,
|
const board = useRequiredBoard();
|
||||||
{
|
const t = useScopedI18n("widget.mediaRequests-requestList");
|
||||||
color: string;
|
|
||||||
label: (t: ScopedTranslationFunction<"widget.mediaRequests-requestList.status">) => string;
|
return (
|
||||||
}
|
<Card
|
||||||
>;
|
className={`mediaRequests-list-item-wrapper mediaRequests-list-item-${request.type} mediaRequests-list-item-${request.status}`}
|
||||||
|
radius={board.itemRadius}
|
||||||
|
p="xs"
|
||||||
|
withBorder
|
||||||
|
>
|
||||||
|
<Image
|
||||||
|
className="mediaRequests-list-item-background"
|
||||||
|
src={request.backdropImageUrl}
|
||||||
|
pos="absolute"
|
||||||
|
w="100%"
|
||||||
|
h="100%"
|
||||||
|
opacity={0.2}
|
||||||
|
top={0}
|
||||||
|
left={0}
|
||||||
|
alt=""
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Group
|
||||||
|
className="mediaRequests-list-item-contents"
|
||||||
|
h="100%"
|
||||||
|
style={{ zIndex: 1 }}
|
||||||
|
justify="space-between"
|
||||||
|
wrap="nowrap"
|
||||||
|
gap={0}
|
||||||
|
>
|
||||||
|
<Group className="mediaRequests-list-item-left-side" h="100%" gap="md" wrap="nowrap" flex={1}>
|
||||||
|
{!isTiny && (
|
||||||
|
<Image
|
||||||
|
className="mediaRequests-list-item-poster"
|
||||||
|
src={request.posterImagePath}
|
||||||
|
h={40}
|
||||||
|
w="auto"
|
||||||
|
radius={"md"}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<Stack gap={0} w="100%">
|
||||||
|
<Group justify="space-between" gap="xs" className="mediaRequests-list-item-top-group">
|
||||||
|
<Group gap="xs">
|
||||||
|
<Text className="mediaRequests-list-item-media-year" size="xs">
|
||||||
|
{request.airDate?.getFullYear() ?? t("toBeDetermined")}
|
||||||
|
</Text>
|
||||||
|
{!isTiny && (
|
||||||
|
<Badge
|
||||||
|
className="mediaRequests-list-item-media-status"
|
||||||
|
color={mediaAvailabilityConfiguration[request.availability].color}
|
||||||
|
variant="light"
|
||||||
|
size="xs"
|
||||||
|
>
|
||||||
|
{t(`availability.${request.availability}`)}
|
||||||
|
</Badge>
|
||||||
|
)}
|
||||||
|
</Group>
|
||||||
|
<Group className="mediaRequests-list-item-request-user" gap={4} wrap="nowrap">
|
||||||
|
<Avatar
|
||||||
|
className="mediaRequests-list-item-request-user-avatar"
|
||||||
|
src={request.requestedBy?.avatar}
|
||||||
|
size="xs"
|
||||||
|
/>
|
||||||
|
<Anchor
|
||||||
|
className="mediaRequests-list-item-request-user-name"
|
||||||
|
href={request.requestedBy?.link}
|
||||||
|
c="var(--mantine-color-text)"
|
||||||
|
target={options.linksTargetNewTab ? "_blank" : "_self"}
|
||||||
|
fz="xs"
|
||||||
|
lineClamp={1}
|
||||||
|
style={{ wordBreak: "break-all" }}
|
||||||
|
>
|
||||||
|
{(request.requestedBy?.displayName ?? "") || "unknown"}
|
||||||
|
</Anchor>
|
||||||
|
</Group>
|
||||||
|
</Group>
|
||||||
|
<Group gap="xs" justify="space-between" className="mediaRequests-list-item-bottom-group">
|
||||||
|
<Anchor
|
||||||
|
className="mediaRequests-list-item-info-second-line mediaRequests-list-item-media-title"
|
||||||
|
href={request.href}
|
||||||
|
c="var(--mantine-color-text)"
|
||||||
|
target={options.linksTargetNewTab ? "_blank" : "_self"}
|
||||||
|
fz={isTiny ? "xs" : "sm"}
|
||||||
|
fw={"bold"}
|
||||||
|
title={request.name}
|
||||||
|
lineClamp={1}
|
||||||
|
>
|
||||||
|
{request.name || "unknown"}
|
||||||
|
</Anchor>
|
||||||
|
{request.status === "pending" ? (
|
||||||
|
<DecisionButtons requestId={request.id} integrationId={request.integrationId} />
|
||||||
|
) : (
|
||||||
|
<StatusBadge status={request.status} />
|
||||||
|
)}
|
||||||
|
</Group>
|
||||||
|
</Stack>
|
||||||
|
</Group>
|
||||||
|
</Group>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
interface DecisionButtonsProps {
|
||||||
|
requestId: number;
|
||||||
|
integrationId: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const DecisionButtons = ({ requestId, integrationId }: DecisionButtonsProps) => {
|
||||||
|
const { mutate: mutateRequestAnswer } = clientApi.widget.mediaRequests.answerRequest.useMutation();
|
||||||
|
const t = useScopedI18n("widget.mediaRequests-requestList");
|
||||||
|
const handleDecision = (answer: RouterInputs["widget"]["mediaRequests"]["answerRequest"]["answer"]) => {
|
||||||
|
mutateRequestAnswer({
|
||||||
|
integrationId,
|
||||||
|
requestId,
|
||||||
|
answer,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Group className="mediaRequests-list-item-pending-buttons" gap="sm">
|
||||||
|
<Tooltip label={t("pending.approve")}>
|
||||||
|
<ActionIcon
|
||||||
|
className="mediaRequests-list-item-pending-button-approve"
|
||||||
|
variant="light"
|
||||||
|
color="green"
|
||||||
|
size="xs"
|
||||||
|
radius="md"
|
||||||
|
onClick={() => {
|
||||||
|
handleDecision("approve");
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<IconThumbUp size={16} />
|
||||||
|
</ActionIcon>
|
||||||
|
</Tooltip>
|
||||||
|
<Tooltip label={t("pending.decline")}>
|
||||||
|
<ActionIcon
|
||||||
|
className="mediaRequests-list-item-pending-button-decline"
|
||||||
|
variant="light"
|
||||||
|
color="red"
|
||||||
|
size="xs"
|
||||||
|
radius="md"
|
||||||
|
onClick={() => {
|
||||||
|
handleDecision("decline");
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<IconThumbDown size={16} />
|
||||||
|
</ActionIcon>
|
||||||
|
</Tooltip>
|
||||||
|
</Group>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
interface StatusBadgeProps {
|
interface StatusBadgeProps {
|
||||||
status: MediaRequestStatus;
|
status: MediaRequestStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
const StatusBadge = ({ status }: StatusBadgeProps) => {
|
const StatusBadge = ({ status }: StatusBadgeProps) => {
|
||||||
const { color, label } = statusMapping[status];
|
|
||||||
const tStatus = useScopedI18n("widget.mediaRequests-requestList.status");
|
const tStatus = useScopedI18n("widget.mediaRequests-requestList.status");
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Badge size="xs" color={color} variant="light">
|
<Badge size="xs" color={mediaRequestStatusConfiguration[status].color} variant="light">
|
||||||
{label(tStatus)}
|
{tStatus(status)}
|
||||||
</Badge>
|
</Badge>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
function getAvailabilityProperties(
|
|
||||||
mediaRequestAvailability: MediaAvailability,
|
|
||||||
t: ScopedTranslationFunction<"widget.mediaRequests-requestList">,
|
|
||||||
) {
|
|
||||||
switch (mediaRequestAvailability) {
|
|
||||||
case MediaAvailability.Available:
|
|
||||||
return { color: "green", label: t("availability.available") };
|
|
||||||
case MediaAvailability.PartiallyAvailable:
|
|
||||||
return { color: "yellow", label: t("availability.partiallyAvailable") };
|
|
||||||
case MediaAvailability.Processing:
|
|
||||||
return { color: "blue", label: t("availability.processing") };
|
|
||||||
case MediaAvailability.Pending:
|
|
||||||
return { color: "violet", label: t("availability.pending") };
|
|
||||||
case MediaAvailability.Blacklisted:
|
|
||||||
return { color: "gray", label: t("availability.blacklisted") };
|
|
||||||
case MediaAvailability.Deleted:
|
|
||||||
return { color: "red", label: t("availability.deleted") };
|
|
||||||
default:
|
|
||||||
return { color: "orange", label: t("availability.unknown") };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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>
|
||||||
|
|||||||
Generated
+1496
-922
File diff suppressed because it is too large.
Load diff
@@ -1 +1 @@
|
|||||||
[{"login":"ajnart","avatar_url":"https://avatars.githubusercontent.com/u/49837342?v=4"},{"login":"manuel-rw","avatar_url":"https://avatars.githubusercontent.com/u/30572287?v=4"},{"login":"Meierschlumpf","avatar_url":"https://avatars.githubusercontent.com/u/63781622?v=4"},{"login":"SeDemal","avatar_url":"https://avatars.githubusercontent.com/u/26098587?v=4"},{"login":"lammersbjorn","avatar_url":"https://avatars.githubusercontent.com/u/71191962?v=4"},{"login":"LarveyOfficial","avatar_url":"https://avatars.githubusercontent.com/u/39219859?v=4"},{"login":"c00ldude1oo","avatar_url":"https://avatars.githubusercontent.com/u/15677803?v=4"},{"login":"InterN0te","avatar_url":"https://avatars.githubusercontent.com/u/10882916?v=4"},{"login":"Aimsucks","avatar_url":"https://avatars.githubusercontent.com/u/1828486?v=4"},{"login":"JannesV","avatar_url":"https://avatars.githubusercontent.com/u/5984244?v=4"},{"login":"MauriceNino","avatar_url":"https://avatars.githubusercontent.com/u/18658092?v=4"},{"login":"hillaliy","avatar_url":"https://avatars.githubusercontent.com/u/950010?v=4"},{"login":"Skeeww","avatar_url":"https://avatars.githubusercontent.com/u/9639992?v=4"},{"login":"RichyHBM","avatar_url":"https://avatars.githubusercontent.com/u/5472275?v=4"},{"login":"Bonfire","avatar_url":"https://avatars.githubusercontent.com/u/5704760?v=4"},{"login":"wieli99","avatar_url":"https://avatars.githubusercontent.com/u/46794825?v=4"},{"login":"ishaanparlikar","avatar_url":"https://avatars.githubusercontent.com/u/43013132?v=4"},{"login":"Zareix","avatar_url":"https://avatars.githubusercontent.com/u/29818713?v=4"},{"login":"tuggan","avatar_url":"https://avatars.githubusercontent.com/u/4325608?v=4"},{"login":"Spillebulle","avatar_url":"https://avatars.githubusercontent.com/u/46653946?v=4"},{"login":"tancak","avatar_url":"https://avatars.githubusercontent.com/u/11760749?v=4"},{"login":"spkesDE","avatar_url":"https://avatars.githubusercontent.com/u/1682314?v=4"},{"login":"j3lte","avatar_url":"https://avatars.githubusercontent.com/u/2557568?v=4"},{"login":"dslatt","avatar_url":"https://avatars.githubusercontent.com/u/5211001?v=4"},{"login":"Malong11-007","avatar_url":"https://avatars.githubusercontent.com/u/40298510?v=4"},{"login":"StefanB7","avatar_url":"https://avatars.githubusercontent.com/u/22056509?v=4"},{"login":"souravghosh01","avatar_url":"https://avatars.githubusercontent.com/u/37548139?v=4"},{"login":"SR3u","avatar_url":"https://avatars.githubusercontent.com/u/2380522?v=4"},{"login":"Rikpat","avatar_url":"https://avatars.githubusercontent.com/u/33869814?v=4"},{"login":"NormanJS","avatar_url":"https://avatars.githubusercontent.com/u/83409549?v=4"},{"login":"No-Maines-Land","avatar_url":"https://avatars.githubusercontent.com/u/20687725?v=4"},{"login":"stark1tty","avatar_url":"https://avatars.githubusercontent.com/u/69326376?v=4"},{"login":"Momcilo42","avatar_url":"https://avatars.githubusercontent.com/u/10118137?v=4"},{"login":"marius-arch","avatar_url":"https://avatars.githubusercontent.com/u/72494359?v=4"},{"login":"Lumilias","avatar_url":"https://avatars.githubusercontent.com/u/10852161?v=4"},{"login":"Havock94","avatar_url":"https://avatars.githubusercontent.com/u/7635248?v=4"},{"login":"Lollyde","avatar_url":"https://avatars.githubusercontent.com/u/11347524?v=4"},{"login":"krishnamuppaneni","avatar_url":"https://avatars.githubusercontent.com/u/4703366?v=4"},{"login":"devtobi","avatar_url":"https://avatars.githubusercontent.com/u/28538704?v=4"},{"login":"TyxTang","avatar_url":"https://avatars.githubusercontent.com/u/90897955?v=4"},{"login":"VinnyVynce","avatar_url":"https://avatars.githubusercontent.com/u/19630511?v=4"},{"login":"WillyJL","avatar_url":"https://avatars.githubusercontent.com/u/49810075?v=4"},{"login":"anonysoul","avatar_url":"https://avatars.githubusercontent.com/u/105715150?v=4"},{"login":"cospeedster","avatar_url":"https://avatars.githubusercontent.com/u/52749645?v=4"},{"login":"diederbert","avatar_url":"https://avatars.githubusercontent.com/u/162878798?v=4"},{"login":"digdilem","avatar_url":"https://avatars.githubusercontent.com/u/4052275?v=4"},{"login":"dinghino","avatar_url":"https://avatars.githubusercontent.com/u/14729459?v=4"},{"login":"gfomichev","avatar_url":"https://avatars.githubusercontent.com/u/1596146?v=4"},{"login":"gnattu","avatar_url":"https://avatars.githubusercontent.com/u/12995396?v=4"},{"login":"tuxpizza","avatar_url":"https://avatars.githubusercontent.com/u/84710786?v=4"},{"login":"xmarkurion","avatar_url":"https://avatars.githubusercontent.com/u/46654687?v=4"},{"login":"huanga","avatar_url":"https://avatars.githubusercontent.com/u/732970?v=4"},{"login":"taos15","avatar_url":"https://avatars.githubusercontent.com/u/122130728?v=4"},{"login":"arghyadipchak","avatar_url":"https://avatars.githubusercontent.com/u/32430374?v=4"},{"login":"AuthorShin","avatar_url":"https://avatars.githubusercontent.com/u/4959043?v=4"},{"login":"benniblot","avatar_url":"https://avatars.githubusercontent.com/u/47Line truncated
|
[{"login":"ajnart","avatar_url":"https://avatars.githubusercontent.com/u/49837342?v=4"},{"login":"manuel-rw","avatar_url":"https://avatars.githubusercontent.com/u/30572287?v=4"},{"login":"Meierschlumpf","avatar_url":"https://avatars.githubusercontent.com/u/63781622?v=4"},{"login":"SeDemal","avatar_url":"https://avatars.githubusercontent.com/u/26098587?v=4"},{"login":"lammersbjorn","avatar_url":"https://avatars.githubusercontent.com/u/71191962?v=4"},{"login":"LarveyOfficial","avatar_url":"https://avatars.githubusercontent.com/u/39219859?v=4"},{"login":"c00ldude1oo","avatar_url":"https://avatars.githubusercontent.com/u/15677803?v=4"},{"login":"InterN0te","avatar_url":"https://avatars.githubusercontent.com/u/10882916?v=4"},{"login":"Aimsucks","avatar_url":"https://avatars.githubusercontent.com/u/1828486?v=4"},{"login":"JannesV","avatar_url":"https://avatars.githubusercontent.com/u/5984244?v=4"},{"login":"MauriceNino","avatar_url":"https://avatars.githubusercontent.com/u/18658092?v=4"},{"login":"hillaliy","avatar_url":"https://avatars.githubusercontent.com/u/950010?v=4"},{"login":"Skeeww","avatar_url":"https://avatars.githubusercontent.com/u/9639992?v=4"},{"login":"RichyHBM","avatar_url":"https://avatars.githubusercontent.com/u/5472275?v=4"},{"login":"Bonfire","avatar_url":"https://avatars.githubusercontent.com/u/5704760?v=4"},{"login":"wieli99","avatar_url":"https://avatars.githubusercontent.com/u/46794825?v=4"},{"login":"ishaanparlikar","avatar_url":"https://avatars.githubusercontent.com/u/43013132?v=4"},{"login":"Zareix","avatar_url":"https://avatars.githubusercontent.com/u/29818713?v=4"},{"login":"tuggan","avatar_url":"https://avatars.githubusercontent.com/u/4325608?v=4"},{"login":"Spillebulle","avatar_url":"https://avatars.githubusercontent.com/u/46653946?v=4"},{"login":"tancak","avatar_url":"https://avatars.githubusercontent.com/u/11760749?v=4"},{"login":"spkesDE","avatar_url":"https://avatars.githubusercontent.com/u/1682314?v=4"},{"login":"j3lte","avatar_url":"https://avatars.githubusercontent.com/u/2557568?v=4"},{"login":"dslatt","avatar_url":"https://avatars.githubusercontent.com/u/5211001?v=4"},{"login":"Malong11-007","avatar_url":"https://avatars.githubusercontent.com/u/40298510?v=4"},{"login":"StefanB7","avatar_url":"https://avatars.githubusercontent.com/u/22056509?v=4"},{"login":"souravghosh01","avatar_url":"https://avatars.githubusercontent.com/u/37548139?v=4"},{"login":"SR3u","avatar_url":"https://avatars.githubusercontent.com/u/2380522?v=4"},{"login":"Rikpat","avatar_url":"https://avatars.githubusercontent.com/u/33869814?v=4"},{"login":"NormanJS","avatar_url":"https://avatars.githubusercontent.com/u/83409549?v=4"},{"login":"No-Maines-Land","avatar_url":"https://avatars.githubusercontent.com/u/20687725?v=4"},{"login":"stark1tty","avatar_url":"https://avatars.githubusercontent.com/u/69326376?v=4"},{"login":"Momcilo42","avatar_url":"https://avatars.githubusercontent.com/u/10118137?v=4"},{"login":"marius-arch","avatar_url":"https://avatars.githubusercontent.com/u/72494359?v=4"},{"login":"Lumilias","avatar_url":"https://avatars.githubusercontent.com/u/10852161?v=4"},{"login":"Havock94","avatar_url":"https://avatars.githubusercontent.com/u/7635248?v=4"},{"login":"Lollyde","avatar_url":"https://avatars.githubusercontent.com/u/11347524?v=4"},{"login":"krishnamuppaneni","avatar_url":"https://avatars.githubusercontent.com/u/4703366?v=4"},{"login":"devtobi","avatar_url":"https://avatars.githubusercontent.com/u/28538704?v=4"},{"login":"TyxTang","avatar_url":"https://avatars.githubusercontent.com/u/90897955?v=4"},{"login":"VinnyVynce","avatar_url":"https://avatars.githubusercontent.com/u/19630511?v=4"},{"login":"WillyJL","avatar_url":"https://avatars.githubusercontent.com/u/49810075?v=4"},{"login":"anonysoul","avatar_url":"https://avatars.githubusercontent.com/u/105715150?v=4"},{"login":"cospeedster","avatar_url":"https://avatars.githubusercontent.com/u/52749645?v=4"},{"login":"diederbert","avatar_url":"https://avatars.githubusercontent.com/u/162878798?v=4"},{"login":"digdilem","avatar_url":"https://avatars.githubusercontent.com/u/4052275?v=4"},{"login":"dinghino","avatar_url":"https://avatars.githubusercontent.com/u/14729459?v=4"},{"login":"gfomichev","avatar_url":"https://avatars.githubusercontent.com/u/1596146?v=4"},{"login":"gnattu","avatar_url":"https://avatars.githubusercontent.com/u/12995396?v=4"},{"login":"tuxpizza","avatar_url":"https://avatars.githubusercontent.com/u/84710786?v=4"},{"login":"xmarkurion","avatar_url":"https://avatars.githubusercontent.com/u/46654687?v=4"},{"login":"huanga","avatar_url":"https://avatars.githubusercontent.com/u/732970?v=4"},{"login":"taos15","avatar_url":"https://avatars.githubusercontent.com/u/122130728?v=4"},{"login":"arghyadipchak","avatar_url":"https://avatars.githubusercontent.com/u/32430374?v=4"},{"login":"AuthorShin","avatar_url":"https://avatars.githubusercontent.com/u/4959043?v=4"},{"login":"benniblot","avatar_url":"https://avatars.githubusercontent.com/u/47Line truncated
|
||||||
@@ -17,9 +17,9 @@
|
|||||||
},
|
},
|
||||||
"prettier": "@homarr/prettier-config",
|
"prettier": "@homarr/prettier-config",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@next/eslint-plugin-next": "16.0.1",
|
"@next/eslint-plugin-next": "16.0.3",
|
||||||
"eslint-config-prettier": "^10.1.8",
|
"eslint-config-prettier": "^10.1.8",
|
||||||
"eslint-config-turbo": "^2.6.0",
|
"eslint-config-turbo": "^2.6.1",
|
||||||
"eslint-plugin-import": "^2.32.0",
|
"eslint-plugin-import": "^2.32.0",
|
||||||
"eslint-plugin-jsx-a11y": "^6.10.2",
|
"eslint-plugin-jsx-a11y": "^6.10.2",
|
||||||
"eslint-plugin-react": "^7.37.5",
|
"eslint-plugin-react": "^7.37.5",
|
||||||
@@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -7,7 +7,7 @@ runs:
|
|||||||
- uses: pnpm/action-setup@v4
|
- uses: pnpm/action-setup@v4
|
||||||
- uses: actions/setup-node@v6
|
- uses: actions/setup-node@v6
|
||||||
with:
|
with:
|
||||||
node-version: 24.11.0
|
node-version: 24.11.1
|
||||||
cache: "pnpm"
|
cache: "pnpm"
|
||||||
|
|
||||||
- shell: bash
|
- shell: bash
|
||||||
|
|||||||
Reference in new issue
Block a user