Merge branch 'dev' into feat/appearance-updates

This commit is contained in:
Kyle authored and GitHub committed 2026-04-13 14:31:50 -06:00
commit ab51d2f274
27 files changed
+983 -1008

No files matched your search

+6 -1
View File
@@ -9,7 +9,12 @@ jobs:
approve-automatic-prs:
runs-on: ubuntu-latest
timeout-minutes: 2
if: github.actor_id == 158783068 || github.actor_id == 190541745 || github.actor_id == 210161987 # Id of renovate bot and crowdin bot see https://api.github.com/users/homarr-renovate%5Bbot%5D and https://api.github.com/users/homarr-crowdin%5Bbot%5D and https://api.github.com/users/homarr-update-contributors%5Bbot%5D
# 158783068: homarr-renovate[bot]
# 190541745: homarr-crowdin[bot]
# 210161987: homarr-update-contributors[bot]
# 175486441: homarr-releases[bot]
# Extracted from https://api.github.com/users/<username>
if: github.actor_id == 158783068 || github.actor_id == 190541745 || github.actor_id == 210161987 || github.actor_id == 175486441
steps:
- name: Checkout code
uses: actions/checkout@v6
+3 -3
View File
@@ -73,14 +73,14 @@
"dotenv": "^17.4.1",
"flag-icons": "^7.5.0",
"glob": "^13.0.6",
"isomorphic-dompurify": "^3.7.1",
"isomorphic-dompurify": "^3.8.0",
"jotai": "^2.19.1",
"mantine-react-table": "2.0.0-beta.9",
"next": "16.2.3",
"postcss-preset-mantine": "^1.18.0",
"prismjs": "^1.30.0",
"react": "19.2.4",
"react-dom": "19.2.4",
"react": "19.2.5",
"react-dom": "19.2.5",
"react-error-boundary": "^6.1.1",
"react-simple-code-editor": "^0.14.1",
"sass": "^1.99.0",
@@ -1,3 +1,7 @@
.contributorCard {
background-color: light-dark(var(--mantine-color-gray-1), var(--mantine-color-dark-5));
}
.dependencyCard:hover {
background-color: light-dark(var(--mantine-color-gray-1), var(--mantine-color-dark-5));
}
@@ -12,8 +12,7 @@ import {
Flex,
Group,
Kbd,
List,
ListItem,
SimpleGrid,
Stack,
Table,
TableTbody,
@@ -22,9 +21,11 @@ import {
TableThead,
TableTr,
Text,
ThemeIcon,
Title,
UnstyledButton,
} from "@mantine/core";
import { IconKeyboard, IconLanguage, IconLibrary, IconUsers } from "@tabler/icons-react";
import { IconKeyboard, IconLanguage, IconLibrary, IconPackage, IconUsers } from "@tabler/icons-react";
import { capitalize, objectEntries } from "@homarr/common";
import { hotkeys } from "@homarr/definitions";
@@ -33,7 +34,8 @@ import { getScopedI18n } from "@homarr/translation/server";
import { homarrLogoPath } from "~/components/layout/logo/homarr-logo";
import { DynamicBreadcrumb } from "~/components/navigation/dynamic-breadcrumb";
import { createMetaTitle } from "~/metadata";
import { getPackageAttributesAsync } from "~/versions/package-reader";
import type { PackageJsonDependencies } from "~/versions/package-reader";
import { getPackageVersion } from "~/versions/package-reader";
import type githubContributorsJson from "../../../../../../../static-data/contributors.json";
import type crowdinContributorsJson from "../../../../../../../static-data/translators.json";
import classes from "./about.module.css";
@@ -57,7 +59,10 @@ const getHostAsync = async () => {
export default async function AboutPage() {
const baseServerUrl = `http://${await getHostAsync()}`;
const t = await getScopedI18n("management.page.about");
const attributes = await getPackageAttributesAsync();
const version = getPackageVersion();
const dependencies = (await fetch(`${baseServerUrl}/api/about/dependencies`).then((res) =>
res.json(),
)) as PackageJsonDependencies;
const githubContributors = (await fetch(`${baseServerUrl}/api/about/contributors/github`).then((res) =>
res.json(),
)) as typeof githubContributorsJson;
@@ -76,7 +81,7 @@ export default async function AboutPage() {
<Title order={1} tt="uppercase">
Homarr
</Title>
<Title order={2}>{t("version", { version: attributes.version })}</Title>
<Title order={2}>{t("version", { version })}</Title>
</Stack>
</Group>
</Center>
@@ -137,25 +142,42 @@ export default async function AboutPage() {
<Text>{t("accordion.libraries.title")}</Text>
<Text size="sm" c="dimmed">
{t("accordion.libraries.subtitle", {
count: String(Object.keys(attributes.dependencies).length),
count: String(Object.keys(dependencies).length),
})}
</Text>
</Stack>
</AccordionControl>
<AccordionPanel>
<List>
{Object.entries(attributes.dependencies)
<SimpleGrid cols={{ xs: 1, sm: 2, md: 3, lg: 4, xl: 5 }} spacing="md">
{Object.entries(dependencies)
.filter(([, value]) => !value.includes("workspace:"))
.sort(([key1], [key2]) => key1.localeCompare(key2))
.map(([key, value]) => (
<ListItem key={key}>
{value.includes("workspace:") ? (
<Text>{key}</Text>
) : (
<a href={`https://www.npmjs.com/package/${key}`}>{key}</a>
)}
</ListItem>
.map(([name, version]) => (
<UnstyledButton
key={name}
component="a"
href={`https://www.npmjs.com/package/${name}`}
target="_blank"
>
<Card withBorder radius="md" p="xs" className={classes.dependencyCard}>
<Group gap="sm" wrap="nowrap">
<ThemeIcon variant="light" size="lg" radius="md">
<IconPackage size="1.5rem" stroke={1.5} />
</ThemeIcon>
<Stack gap={0}>
<Text size="sm" fw="bold" lineClamp={1} title={name}>
{name}
</Text>
<Text size="sm" c="dimmed">
v{version.replace("^", "").replace("~", "")}
</Text>
</Stack>
</Group>
</Card>
</UnstyledButton>
))}
</List>
</SimpleGrid>
</AccordionPanel>
</AccordionItem>
<AccordionItem value="hotkeys">
@@ -0,0 +1,10 @@
import { NextResponse } from "next/server";
import { getDependenciesAsync } from "../../../../versions/package-reader";
export const GET = async () => {
const dependencies = await getDependenciesAsync();
return NextResponse.json(dependencies);
};
export const dynamic = "force-static";
+4 -11
View File
@@ -3,10 +3,10 @@ import { glob } from "glob";
import packageJson from "../../../../package.json";
const getPackageVersion = () => packageJson.version;
const getDependenciesAsync = async (): Promise<PackageJsonDependencies> => {
export const getPackageVersion = () => packageJson.version;
export const getDependenciesAsync = async (): Promise<PackageJsonDependencies> => {
const pathNames = await glob("**/package.json", {
ignore: "node_modules/**",
ignore: "**/node_modules/**",
cwd: "../../",
absolute: true,
});
@@ -22,14 +22,7 @@ const getDependenciesAsync = async (): Promise<PackageJsonDependencies> => {
return dependencies;
};
export const getPackageAttributesAsync = async () => {
return {
version: getPackageVersion(),
dependencies: await getDependenciesAsync(),
};
};
type PackageJsonDependencies = Record<string, string>;
export type PackageJsonDependencies = Record<string, string>;
interface PackageJson {
dependencies: PackageJsonDependencies | undefined;
}
+3 -3
View File
@@ -42,7 +42,7 @@
"@semantic-release/github": "^12.0.6",
"@semantic-release/npm": "^13.1.5",
"@semantic-release/release-notes-generator": "^14.1.0",
"@testcontainers/redis": "^11.13.0",
"@testcontainers/redis": "^11.14.0",
"@turbo/gen": "^2.9.5",
"@vitejs/plugin-react": "^5.2.0",
"@vitest/coverage-v8": "^4.1.3",
@@ -53,7 +53,7 @@
"json5": "^2.2.3",
"prettier": "^3.8.1",
"semantic-release": "^25.0.3",
"testcontainers": "^11.13.0",
"testcontainers": "^11.14.0",
"turbo": "^2.9.5",
"typescript": "^5.9.3",
"vite-tsconfig-paths": "^6.1.1",
@@ -89,7 +89,7 @@
"nanoid@>=4.0.0 <5.0.9": ">=5.1.7",
"prismjs@<1.30.0": ">=1.30.0",
"proxmox-api>undici": "7.24.6",
"react-is": "^19.2.4",
"react-is": "^19.2.5",
"rollup@>=4.0.0 <4.22.4": ">=4.60.1",
"sha.js@<=2.4.11": ">=2.4.12",
"tar-fs@>=3.0.0 <3.0.9": ">=3.1.2",
+2 -2
View File
@@ -48,8 +48,8 @@
"@trpc/tanstack-react-query": "^11.16.0",
"lodash.clonedeep": "^4.5.0",
"next": "16.2.3",
"react": "19.2.4",
"react-dom": "19.2.4",
"react": "19.2.5",
"react-dom": "19.2.5",
"superjson": "2.2.6",
"trpc-to-openapi": "^3.2.0",
"zod": "^4.3.6"
+2 -2
View File
@@ -36,8 +36,8 @@
"ldapts": "8.1.7",
"next": "16.2.3",
"next-auth": "5.0.0-beta.30",
"react": "19.2.4",
"react-dom": "19.2.4",
"react": "19.2.5",
"react-dom": "19.2.5",
"zod": "^4.3.6"
},
"devDependencies": {
+2 -2
View File
@@ -25,8 +25,8 @@
"prettier": "@homarr/prettier-config",
"dependencies": {
"@homarr/api": "workspace:^0.1.0",
"react": "19.2.4",
"react-dom": "19.2.4"
"react": "19.2.5",
"react-dom": "19.2.5"
},
"devDependencies": {
"@homarr/eslint-config": "workspace:^0.2.0",
+2 -2
View File
@@ -32,8 +32,8 @@
"dayjs": "^1.11.20",
"next": "16.2.3",
"octokit": "^5.0.5",
"react": "19.2.4",
"react-dom": "19.2.4",
"react": "19.2.5",
"react-dom": "19.2.5",
"undici": "7.24.6",
"zod": "^4.3.6",
"zod-validation-error": "^5.0.0"
+1 -1
View File
@@ -33,7 +33,7 @@
"@trpc/server": "^11.16.0",
"@trpc/tanstack-react-query": "^11.16.0",
"node-cron": "^4.2.1",
"react": "19.2.4",
"react": "19.2.5",
"zod": "^4.3.6"
},
"devDependencies": {
+2 -2
View File
@@ -49,8 +49,8 @@
"@homarr/server-settings": "workspace:^0.1.0",
"@mantine/core": "^8.3.18",
"@paralleldrive/cuid2": "^3.3.0",
"@testcontainers/mysql": "^11.13.0",
"@testcontainers/postgresql": "^11.13.0",
"@testcontainers/mysql": "^11.14.0",
"@testcontainers/postgresql": "^11.14.0",
"better-sqlite3": "^12.8.0",
"dotenv": "^17.4.1",
"drizzle-kit": "^0.31.10",
+1 -1
View File
@@ -24,7 +24,7 @@
"prettier": "@homarr/prettier-config",
"dependencies": {
"@homarr/common": "workspace:^0.1.0",
"fast-xml-parser": "^5.5.10",
"fast-xml-parser": "^5.5.11",
"zod": "^4.3.6"
},
"devDependencies": {
+1 -1
View File
@@ -31,7 +31,7 @@
"@homarr/ui": "workspace:^0.1.0",
"@homarr/validation": "workspace:^0.1.0",
"@mantine/core": "^8.3.18",
"react": "19.2.4",
"react": "19.2.5",
"zod": "^4.3.6"
},
"devDependencies": {
+2 -2
View File
@@ -37,8 +37,8 @@
"@tabler/icons-react": "^3.41.1",
"dayjs": "^1.11.20",
"next": "16.2.3",
"react": "19.2.4",
"react-dom": "19.2.4",
"react": "19.2.5",
"react-dom": "19.2.5",
"zod": "^4.3.6"
},
"devDependencies": {
+1 -1
View File
@@ -26,7 +26,7 @@
"@homarr/ui": "workspace:^0.1.0",
"@mantine/core": "^8.3.18",
"@mantine/hooks": "^8.3.18",
"react": "19.2.4"
"react": "19.2.5"
},
"devDependencies": {
"@homarr/eslint-config": "workspace:^0.2.0",
+2 -2
View File
@@ -41,8 +41,8 @@
"@mantine/hooks": "^8.3.18",
"adm-zip": "0.5.17",
"next": "16.2.3",
"react": "19.2.4",
"react-dom": "19.2.4",
"react": "19.2.5",
"react-dom": "19.2.5",
"superjson": "2.2.6",
"zod": "^4.3.6",
"zod-form-data": "^3.0.1"
+2 -2
View File
@@ -27,8 +27,8 @@
"@homarr/server-settings": "workspace:^0.1.0",
"@mantine/dates": "^8.3.18",
"next": "16.2.3",
"react": "19.2.4",
"react-dom": "19.2.4"
"react": "19.2.5",
"react-dom": "19.2.5"
},
"devDependencies": {
"@homarr/eslint-config": "workspace:^0.2.0",
+2 -2
View File
@@ -39,8 +39,8 @@
"@tabler/icons-react": "^3.41.1",
"jotai": "^2.19.1",
"next": "16.2.3",
"react": "19.2.4",
"react-dom": "19.2.4",
"react": "19.2.5",
"react-dom": "19.2.5",
"use-deep-compare-effect": "^1.8.1"
},
"devDependencies": {
+3 -3
View File
@@ -33,9 +33,9 @@
"deepmerge": "4.3.1",
"mantine-react-table": "2.0.0-beta.9",
"next": "16.2.3",
"next-intl": "4.9.0",
"react": "19.2.4",
"react-dom": "19.2.4"
"next-intl": "4.9.1",
"react": "19.2.5",
"react-dom": "19.2.5"
},
"devDependencies": {
"@homarr/eslint-config": "workspace:^0.2.0",
+44 -44
View File
@@ -1607,32 +1607,32 @@
}
},
"anchorNote": {
"name": "",
"description": "",
"name": "Nota Anchor",
"description": "Visualizza una nota selezionata da Ancoraggio",
"option": {
"noteId": {
"label": ""
"label": "Nota"
},
"showTitle": {
"label": ""
"label": "Mostra titolo"
},
"showUpdatedAt": {
"label": ""
"label": "Mostra ultimo aggiornamento"
}
},
"empty": "",
"emptyContent": "",
"notFound": "",
"noNotes": "",
"integrationRequired": "",
"updatedAt": "",
"untitled": "",
"edit": "",
"save": "",
"cancel": "",
"readOnlyViewer": "",
"saveForbidden": "",
"saveFailed": ""
"empty": "Seleziona una nota da visualizzare",
"emptyContent": "Questa nota non ha nessun contenuto",
"notFound": "Nota non trovata",
"noNotes": "Nessuna nota trovata",
"integrationRequired": "Seleziona prima l'integrazione di Anchor",
"updatedAt": "Aggiornato {date}",
"untitled": "Senza titolo",
"edit": "Modifica",
"save": "Salva",
"cancel": "Annulla",
"readOnlyViewer": "Hai accesso in modalità visualizzazione a questa nota. La modifica è disabilitata.",
"saveForbidden": "Non hai i permessi per modificare questa nota.",
"saveFailed": "Impossibile salvare questa nota. Per favore, riprova."
},
"iframe": {
"name": "iFrame",
@@ -2546,7 +2546,7 @@
"label": "Nascondi descrizione"
},
"showPosterImage": {
"label": ""
"label": "Mostra immagine poster"
}
}
},
@@ -2761,42 +2761,42 @@
"option": {}
},
"speedtestTracker": {
"name": "",
"description": "",
"name": "SpeedTest Tracker",
"description": "Visualizza i risultati del test di velocità della tua istanza di Speedtest Tracker.",
"option": {
"showLatestResult": {
"label": ""
"label": "Mostra l'ultimo risultato"
},
"showStats": {
"label": ""
"label": "Mostra medie"
},
"showRecentResults": {
"label": ""
"label": "Mostra risultati recenti"
},
"showPingGraph": {
"label": ""
"label": "Mostra grafico di ping"
}
},
"latestResult": "",
"averages": "",
"tests": "",
"recentResults": "",
"recentResultsSpeed": "",
"recentResultsPing": "",
"download": "",
"upload": "",
"ping": "",
"status": "",
"avgDownload": "",
"avgUpload": "",
"avgPing": "",
"healthy": "",
"unhealthy": "",
"ok": "",
"fail": "",
"noSectionsEnabled": "",
"latestResult": "Ultima Risultato",
"averages": "Medie",
"tests": "{count} test",
"recentResults": "Risultati Recenti",
"recentResultsSpeed": "Velocità",
"recentResultsPing": "Ping",
"download": "Download",
"upload": "Upload",
"ping": "Ping",
"status": "Stato",
"avgDownload": "Media di Download",
"avgUpload": "Media di Upload",
"avgPing": "Media di Ping",
"healthy": "Normale funzionamento",
"unhealthy": "Compromesso",
"ok": "OK",
"fail": "Fallito",
"noSectionsEnabled": "Abilita almeno una sezione nelle opzioni del widget.",
"error": {
"internalServerError": ""
"internalServerError": "Recupero dei dati di speedtest non riuscito"
}
},
"systemResources": {
+44 -44
View File
@@ -1607,32 +1607,32 @@
}
},
"anchorNote": {
"name": "",
"description": "",
"name": "Nota do Anchor",
"description": "Exibe a nota selecionada do Anchor",
"option": {
"noteId": {
"label": ""
"label": "Nota"
},
"showTitle": {
"label": ""
"label": "Mostrar título"
},
"showUpdatedAt": {
"label": ""
"label": "Exibir última atualização"
}
},
"empty": "",
"emptyContent": "",
"notFound": "",
"noNotes": "",
"integrationRequired": "",
"updatedAt": "",
"untitled": "",
"edit": "",
"save": "",
"cancel": "",
"readOnlyViewer": "",
"saveForbidden": "",
"saveFailed": ""
"empty": "Selecione uma nota para exibir",
"emptyContent": "Essa nota esta vazia",
"notFound": "Nenhuma nota encontrada",
"noNotes": "Nenhuma nota encontrada",
"integrationRequired": "Selecione primeiro uma integração do Anchor",
"updatedAt": "Atualizado em {date}",
"untitled": "Sem título",
"edit": "Editar",
"save": "Salvar",
"cancel": "Cancelar",
"readOnlyViewer": "Você tem acesso de visualização a esta nota. A edição está desativada.",
"saveForbidden": "Você não tem permissão para editar essa nota.",
"saveFailed": "Não foi possível salvar a nota. Tente novamente."
},
"iframe": {
"name": "iFrame",
@@ -2546,7 +2546,7 @@
"label": "Ocultar descrição"
},
"showPosterImage": {
"label": ""
"label": "Exibir pôster"
}
}
},
@@ -2761,42 +2761,42 @@
"option": {}
},
"speedtestTracker": {
"name": "",
"description": "",
"name": "Speedtest Tracker",
"description": "Exibe os resultados do teste de velocidade da sua instância do Speedtest Tracker.",
"option": {
"showLatestResult": {
"label": ""
"label": "Mostrar último resultado"
},
"showStats": {
"label": ""
"label": "Exibir médias"
},
"showRecentResults": {
"label": ""
"label": "Mostrar resultados recentes"
},
"showPingGraph": {
"label": ""
"label": "Exibir gráfico de ping"
}
},
"latestResult": "",
"averages": "",
"tests": "",
"recentResults": "",
"recentResultsSpeed": "",
"recentResultsPing": "",
"download": "",
"upload": "",
"ping": "",
"status": "",
"avgDownload": "",
"avgUpload": "",
"avgPing": "",
"healthy": "",
"unhealthy": "",
"ok": "",
"fail": "",
"noSectionsEnabled": "",
"latestResult": "Último resultado",
"averages": "Médias",
"tests": "Testes",
"recentResults": "Resultados recentes",
"recentResultsSpeed": "Velocidade",
"recentResultsPing": "Ping",
"download": "Download",
"upload": "Upload",
"ping": "Ping",
"status": "Status",
"avgDownload": "Download médio",
"avgUpload": "Upload médio",
"avgPing": "Ping médio",
"healthy": "Saudável",
"unhealthy": "Com problemas",
"ok": "Ok",
"fail": "Falhou",
"noSectionsEnabled": "Habilite ao menos uma seção nas opções do widget.",
"error": {
"internalServerError": ""
"internalServerError": "Falha ao obter dados do Speedtest"
}
},
"systemResources": {
+2 -2
View File
@@ -37,8 +37,8 @@
"crypto-js": "^4.2.0",
"mantine-react-table": "2.0.0-beta.9",
"next": "16.2.3",
"react": "19.2.4",
"react-dom": "19.2.4",
"react": "19.2.5",
"react-dom": "19.2.5",
"svgson": "^5.3.1"
},
"devDependencies": {
+18 -18
View File
@@ -52,29 +52,29 @@
"@mantine/core": "^8.3.18",
"@mantine/hooks": "^8.3.18",
"@tabler/icons-react": "^3.41.1",
"@tiptap/extension-color": "3.22.2",
"@tiptap/extension-highlight": "3.22.2",
"@tiptap/extension-image": "3.22.2",
"@tiptap/extension-link": "^3.22.2",
"@tiptap/extension-placeholder": "^3.22.2",
"@tiptap/extension-table": "3.22.2",
"@tiptap/extension-table-cell": "3.22.2",
"@tiptap/extension-table-header": "3.22.2",
"@tiptap/extension-table-row": "3.22.2",
"@tiptap/extension-task-item": "3.22.2",
"@tiptap/extension-task-list": "3.22.2",
"@tiptap/extension-text-align": "3.22.2",
"@tiptap/extension-text-style": "3.22.2",
"@tiptap/extension-underline": "3.22.2",
"@tiptap/react": "^3.22.2",
"@tiptap/starter-kit": "^3.22.2",
"@tiptap/extension-color": "3.22.3",
"@tiptap/extension-highlight": "3.22.3",
"@tiptap/extension-image": "3.22.3",
"@tiptap/extension-link": "^3.22.3",
"@tiptap/extension-placeholder": "^3.22.3",
"@tiptap/extension-table": "3.22.3",
"@tiptap/extension-table-cell": "3.22.3",
"@tiptap/extension-table-header": "3.22.3",
"@tiptap/extension-table-row": "3.22.3",
"@tiptap/extension-task-item": "3.22.3",
"@tiptap/extension-task-list": "3.22.3",
"@tiptap/extension-text-align": "3.22.3",
"@tiptap/extension-text-style": "3.22.3",
"@tiptap/extension-underline": "3.22.3",
"@tiptap/react": "^3.22.3",
"@tiptap/starter-kit": "^3.22.3",
"clsx": "^2.1.1",
"dayjs": "^1.11.20",
"mantine-form-zod-resolver": "^1.3.0",
"mantine-react-table": "2.0.0-beta.9",
"next": "16.2.3",
"react": "19.2.4",
"react-dom": "19.2.4",
"react": "19.2.5",
"react-dom": "19.2.5",
"react-markdown": "^10.1.0",
"react-quill-new": "^3.8.3",
"recharts": "^2.15.4",
+779 -838
View File
File diff suppressed because it is too large. Load diff
+1 -1
View File
@@ -24,7 +24,7 @@
"eslint-plugin-jsx-a11y": "^6.10.2",
"eslint-plugin-react": "^7.37.5",
"eslint-plugin-react-hooks": "^6.1.1",
"typescript-eslint": "^8.58.0"
"typescript-eslint": "^8.58.1"
},
"devDependencies": {
"@homarr/prettier-config": "workspace:^0.1.0",