diff --git a/apps/nextjs/package.json b/apps/nextjs/package.json index 76591198d..189a2d501 100644 --- a/apps/nextjs/package.json +++ b/apps/nextjs/package.json @@ -47,6 +47,7 @@ "chroma-js": "^2.4.2", "dayjs": "^1.11.10", "dotenv": "^16.4.5", + "glob": "^10.3.12", "jotai": "^2.8.0", "next": "^14.2.3", "postcss-preset-mantine": "^1.15.0", @@ -60,10 +61,10 @@ "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", + "@types/chroma-js": "2.4.4", "@types/node": "^20.12.7", "@types/react": "^18.3.1", "@types/react-dom": "^18.3.0", - "@types/chroma-js": "2.4.4", "concurrently": "^8.2.2", "eslint": "^8.57.0", "prettier": "^3.2.5", diff --git a/apps/nextjs/src/app/[locale]/manage/about/page.tsx b/apps/nextjs/src/app/[locale]/manage/about/page.tsx index b7ff7b2a7..450995a74 100644 --- a/apps/nextjs/src/app/[locale]/manage/about/page.tsx +++ b/apps/nextjs/src/app/[locale]/manage/about/page.tsx @@ -13,10 +13,11 @@ import { Title, } from "@mantine/core"; import { IconLanguage, IconLibrary, IconUsers } from "@tabler/icons-react"; +import { setStaticParamsLocale } from "next-international/server"; -import { getScopedI18n } from "@homarr/translation/server"; +import { getScopedI18n, getStaticParams } from "@homarr/translation/server"; -import { getPackageAttributes } from "~/versions/package-reader"; +import { getPackageAttributesAsync } from "~/versions/package-reader"; import logo from "../../../../../public/logo/logo.png"; import classes from "./accordion.module.css"; @@ -29,9 +30,16 @@ export async function generateMetadata() { }; } -export default async function AboutPage() { +interface PageProps { + params: { + locale: string; + }; +} + +export default async function AboutPage({ params: { locale } }: PageProps) { + setStaticParamsLocale(locale); const t = await getScopedI18n("management.page.about"); - const attributes = getPackageAttributes(); + const attributes = await getPackageAttributesAsync(); return (
@@ -75,15 +83,17 @@ export default async function AboutPage() { - {Object.entries(attributes.dependencies).map(([key, value]) => ( - - {value.includes("workspace:") ? ( - {key} - ) : ( - {key} - )} - - ))} + {Object.entries(attributes.dependencies) + .sort(([key1], [key2]) => key1.localeCompare(key2)) + .map(([key, value]) => ( + + {value.includes("workspace:") ? ( + {key} + ) : ( + {key} + )} + + ))} @@ -91,3 +101,9 @@ export default async function AboutPage() {
); } + +export function generateStaticParams() { + return getStaticParams(); +} + +export const dynamic = "force-static"; diff --git a/apps/nextjs/src/versions/package-reader.ts b/apps/nextjs/src/versions/package-reader.ts index 4142309ee..0862c711c 100644 --- a/apps/nextjs/src/versions/package-reader.ts +++ b/apps/nextjs/src/versions/package-reader.ts @@ -1,13 +1,40 @@ +import fsPromises from "fs/promises"; +import { glob } from "glob"; + import packageJson from "~/../package.json"; const getPackageVersion = () => packageJson.version; -const getDependencies = (): PackageJsonDependencies => packageJson.dependencies; +const getDependenciesAsync = async (): Promise => { + const pathNames = await glob("**/package.json", { + ignore: "node_modules/**", + cwd: "../../", + absolute: true, + }); + const packageContents = await Promise.all( + pathNames.map(async (path) => await fsPromises.readFile(path, "utf-8")), + ); + const packageDependencies = packageContents + .map( + (packageContent) => + (JSON.parse(packageContent) as PackageJson).dependencies, + ) + .filter((dependencies) => dependencies !== undefined); -export const getPackageAttributes = () => { + let dependencies = {}; + for (const dependenciesOfPackage of packageDependencies) { + dependencies = { ...dependencies, ...dependenciesOfPackage }; + } + return dependencies; +}; + +export const getPackageAttributesAsync = async () => { return { version: getPackageVersion(), - dependencies: getDependencies(), + dependencies: await getDependenciesAsync(), }; }; type PackageJsonDependencies = { [key in string]: string }; +interface PackageJson { + dependencies: PackageJsonDependencies | undefined; +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4974982cb..97db7aba3 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -159,6 +159,9 @@ importers: dotenv: specifier: ^16.4.5 version: 16.4.5 + glob: + specifier: ^10.3.12 + version: 10.3.12 jotai: specifier: ^2.8.0 version: 2.8.0(@types/react@18.3.1)(react@18.3.1) @@ -3521,6 +3524,11 @@ packages: engines: {node: '>=16 || 14 >=14.17'} hasBin: true + glob@10.3.12: + resolution: {integrity: sha512-TCNv8vJ+xz4QiqTpfOJA7HvYv+tNIRHKfUWw/q+v2jdgN4ebz+KY9tGx5J4rHP0o84mNP+ApH66HRX8us3Khqg==} + engines: {node: '>=16 || 14 >=14.17'} + hasBin: true + glob@7.2.3: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} @@ -4499,6 +4507,10 @@ packages: resolution: {integrity: sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==} engines: {node: '>=16 || 14 >=14.17'} + path-scurry@1.10.2: + resolution: {integrity: sha512-7xTavNy5RQXnsjANvVvMkEjvloOinkAjv/Z6Ildz9v2RinZ4SBKTWFOVRbaF8p0vpHnyjV/UwNDdKuUv6M5qcA==} + engines: {node: '>=16 || 14 >=14.17'} + path-type@4.0.0: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} @@ -8432,6 +8444,14 @@ snapshots: minipass: 7.0.4 path-scurry: 1.10.1 + glob@10.3.12: + dependencies: + foreground-child: 3.1.1 + jackspeak: 2.3.6 + minimatch: 9.0.4 + minipass: 7.0.4 + path-scurry: 1.10.2 + glob@7.2.3: dependencies: fs.realpath: 1.0.0 @@ -9491,6 +9511,11 @@ snapshots: lru-cache: 10.2.0 minipass: 7.0.4 + path-scurry@1.10.2: + dependencies: + lru-cache: 10.2.0 + minipass: 7.0.4 + path-type@4.0.0: {} pathe@1.1.2: {}