Merge branch 'gethomepage:dev' into integration

This commit is contained in:
djeinstine 2024-12-26 08:00:29 +01:00 committed by GitHub
commit 49df67ef7a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 85 additions and 54 deletions

View File

@ -48,7 +48,7 @@ self-hosted / open-source alternative, we ask that any widgets, etc. are develop
## New Feature Guidelines ## New Feature Guidelines
- New features should usually be linked to an existing feature request. The purpose of this requirement is to avoid the addition (and maintenance) of features that might only benefit a small number of users. - New features should be linked to an existing feature request. The purpose of this requirement is to avoid the addition (and maintenance) of features that might only benefit a small number of users.
- If you have ideas for a larger feature you may want to open a discussion first. - If you have ideas for a larger feature you may want to open a discussion first.
## Service Widget Guidelines ## Service Widget Guidelines

View File

@ -335,7 +335,7 @@
}, },
"technitium": { "technitium": {
"totalQueries": "Richieste", "totalQueries": "Richieste",
"totalNoError": "Success", "totalNoError": "Successo",
"totalServerFailure": "Failures", "totalServerFailure": "Failures",
"totalNxDomain": "NX Domains", "totalNxDomain": "NX Domains",
"totalRefused": "Refused", "totalRefused": "Refused",
@ -590,7 +590,7 @@
"total": "Totale" "total": "Totale"
}, },
"peanut": { "peanut": {
"battery_charge": "Battery Charge", "battery_charge": "Carica Batteria",
"ups_load": "Carico UPS", "ups_load": "Carico UPS",
"ups_status": "Stato UPS", "ups_status": "Stato UPS",
"online": "Online", "online": "Online",
@ -854,7 +854,7 @@
}, },
"romm": { "romm": {
"platforms": "Piattaforme", "platforms": "Piattaforme",
"totalRoms": "Games", "totalRoms": "Giochi",
"saves": "Saves", "saves": "Saves",
"states": "States", "states": "States",
"screenshots": "Screenshots", "screenshots": "Screenshots",
@ -890,7 +890,7 @@
"sceneDuration": "Durata Delle Scene", "sceneDuration": "Durata Delle Scene",
"images": "Immagini", "images": "Immagini",
"imageSize": "Dimensioni immagine", "imageSize": "Dimensioni immagine",
"galleries": "Galleries", "galleries": "Gallerie",
"performers": "Esecutori", "performers": "Esecutori",
"studios": "Studi", "studios": "Studi",
"movies": "Film", "movies": "Film",
@ -933,7 +933,7 @@
}, },
"stocks": { "stocks": {
"stocks": "Stocks", "stocks": "Stocks",
"loading": "Loading", "loading": "Caricamento",
"open": "Open - US Market", "open": "Open - US Market",
"closed": "Closed - US Market", "closed": "Closed - US Market",
"invalidConfiguration": "Invalid Configuration" "invalidConfiguration": "Invalid Configuration"
@ -944,8 +944,8 @@
"version": "Versione" "version": "Versione"
}, },
"linkwarden": { "linkwarden": {
"links": "Links", "links": "Collegamenti",
"collections": "Collections", "collections": "Raccolte",
"tags": "Tag" "tags": "Tag"
}, },
"zabbix": { "zabbix": {
@ -957,12 +957,12 @@
"disaster": "Disaster" "disaster": "Disaster"
}, },
"lubelogger": { "lubelogger": {
"vehicle": "Vehicle", "vehicle": "Veicolo",
"vehicles": "Vehicles", "vehicles": "Veicoli",
"serviceRecords": "Service Records", "serviceRecords": "Service Records",
"reminders": "Reminders", "reminders": "Promemoria",
"nextReminder": "Next Reminder", "nextReminder": "Promemoria Seguente",
"none": "None" "none": "Nessuno"
}, },
"vikunja": { "vikunja": {
"projects": "Active Projects", "projects": "Active Projects",
@ -1000,7 +1000,7 @@
"suspended": "Suspended" "suspended": "Suspended"
}, },
"spoolman": { "spoolman": {
"loading": "Loading" "loading": "Caricamento"
}, },
"gitlab": { "gitlab": {
"groups": "Groups", "groups": "Groups",

View File

@ -311,13 +311,13 @@
}, },
"suwayomi": { "suwayomi": {
"download": "Gedownload", "download": "Gedownload",
"nondownload": "Non-Downloaded", "nondownload": "Niet gedownload",
"read": "Gelezen", "read": "Gelezen",
"unread": "Ongelezen", "unread": "Ongelezen",
"downloadedread": "Downloaded & Read", "downloadedread": "Gedownload & gelezen",
"downloadedunread": "Downloaded & Unread", "downloadedunread": "Gedownload & ongelezen",
"nondownloadedread": "Non-Downloaded & Read", "nondownloadedread": "Niet-gedownload & gelezen",
"nondownloadedunread": "Non-Downloaded & Unread" "nondownloadedunread": "Niet-gedownload & ongelezen"
}, },
"tailscale": { "tailscale": {
"address": "Adres", "address": "Adres",
@ -980,32 +980,32 @@
}, },
"beszel": { "beszel": {
"name": "Naam", "name": "Naam",
"systems": "Systems", "systems": "Systemen",
"up": "Online", "up": "Online",
"status": "Status", "status": "Status",
"updated": "Bijgewerkt", "updated": "Bijgewerkt",
"cpu": "CPU", "cpu": "CPU",
"memory": "GEH", "memory": "GEH",
"disk": "Disk", "disk": "Schijf",
"network": "NET" "network": "NET"
}, },
"argocd": { "argocd": {
"apps": "Apps", "apps": "Apps",
"synced": "Synced", "synced": "Gesynchroniseerd",
"outOfSync": "Out Of Sync", "outOfSync": "Niet gesynchroniseerd",
"healthy": "Gezond", "healthy": "Gezond",
"degraded": "Degraded", "degraded": "Gedegradeerd",
"progressing": "Progressing", "progressing": "Doorvoeren",
"missing": "Ontbreekt", "missing": "Ontbreekt",
"suspended": "Suspended" "suspended": "Onderbroken"
}, },
"spoolman": { "spoolman": {
"loading": "Laden" "loading": "Laden"
}, },
"gitlab": { "gitlab": {
"groups": "Groups", "groups": "Groepen",
"issues": "Problemen", "issues": "Problemen",
"merges": "Merge Requests", "merges": "Merge Verzoeken",
"projects": "Projects" "projects": "Projecten"
} }
} }

View File

@ -15,6 +15,7 @@ export default function ServicesGroup({
disableCollapse, disableCollapse,
useEqualHeights, useEqualHeights,
groupsInitiallyCollapsed, groupsInitiallyCollapsed,
isSubgroup,
}) { }) {
const panel = useRef(); const panel = useRef();
@ -22,14 +23,18 @@ export default function ServicesGroup({
if (layout?.initiallyCollapsed ?? groupsInitiallyCollapsed) panel.current.style.height = `0`; if (layout?.initiallyCollapsed ?? groupsInitiallyCollapsed) panel.current.style.height = `0`;
}, [layout, groupsInitiallyCollapsed]); }, [layout, groupsInitiallyCollapsed]);
let groupPadding = layout?.header === false ? "px-1" : "p-1 pb-0";
if (isSubgroup) groupPadding = "";
return ( return (
<div <div
key={group.name} key={group.name}
className={classNames( className={classNames(
"services-group", "services-group flex-1",
layout?.style === "row" ? "basis-full" : "basis-full md:basis-1/2 lg:basis-1/3 xl:basis-1/4", layout?.style === "row" ? "basis-full" : "basis-full md:basis-1/2 lg:basis-1/3 xl:basis-1/4",
layout?.style !== "row" && fiveColumns ? "3xl:basis-1/5" : "", layout?.style !== "row" && fiveColumns ? "3xl:basis-1/5" : "",
layout?.header === false ? "flex-1 px-1 -my-1" : "flex-1 p-1", groupPadding,
isSubgroup ? "subgroup" : "",
)} )}
> >
<Disclosure defaultOpen={!(layout?.initiallyCollapsed ?? groupsInitiallyCollapsed) ?? true}> <Disclosure defaultOpen={!(layout?.initiallyCollapsed ?? groupsInitiallyCollapsed) ?? true}>
@ -80,6 +85,7 @@ export default function ServicesGroup({
services={group.services} services={group.services}
layout={layout} layout={layout}
useEqualHeights={useEqualHeights} useEqualHeights={useEqualHeights}
header={layout?.header !== false}
/> />
{group.groups?.length > 0 && ( {group.groups?.length > 0 && (
<div <div
@ -96,6 +102,7 @@ export default function ServicesGroup({
disableCollapse={disableCollapse} disableCollapse={disableCollapse}
useEqualHeights={useEqualHeights} useEqualHeights={useEqualHeights}
groupsInitiallyCollapsed={groupsInitiallyCollapsed} groupsInitiallyCollapsed={groupsInitiallyCollapsed}
isSubgroup
/> />
))} ))}
</div> </div>

View File

@ -86,7 +86,7 @@ export default function Item({ service, groupName, useEqualHeights }) {
<div <div
className={`absolute top-0 right-0 flex flex-row justify-end ${ className={`absolute top-0 right-0 flex flex-row justify-end ${
statusStyle === "dot" ? "gap-0" : "gap-2 mr-2" statusStyle === "dot" ? "gap-0" : "gap-2 mr-2"
} z-30 service-tags`} } z-10 service-tags`}
> >
{service.ping && ( {service.ping && (
<div className="flex-shrink-0 flex items-center justify-center service-tag service-ping"> <div className="flex-shrink-0 flex items-center justify-center service-tag service-ping">

View File

@ -4,12 +4,13 @@ import { columnMap } from "../../utils/layout/columns";
import Item from "components/services/item"; import Item from "components/services/item";
export default function List({ groupName, services, layout, useEqualHeights }) { export default function List({ groupName, services, layout, useEqualHeights, header }) {
return ( return (
<ul <ul
className={classNames( className={classNames(
layout?.style === "row" ? `grid ${columnMap[layout?.columns]} gap-x-2` : "flex flex-col", layout?.style === "row" ? `grid ${columnMap[layout?.columns]} gap-x-2` : "flex flex-col",
"mt-3 services-list", header ? "mt-3" : "",
"services-list",
)} )}
> >
{services.map((service) => ( {services.map((service) => (

View File

@ -297,7 +297,6 @@ function Home({ initialSettings }) {
disableCollapse={settings.disableCollapse} disableCollapse={settings.disableCollapse}
useEqualHeights={settings.useEqualHeights} useEqualHeights={settings.useEqualHeights}
groupsInitiallyCollapsed={settings.groupsInitiallyCollapsed} groupsInitiallyCollapsed={settings.groupsInitiallyCollapsed}
bookmarksStyle={settings.bookmarksStyle}
/> />
) : ( ) : (
<BookmarksGroup <BookmarksGroup

View File

@ -63,3 +63,7 @@ dialog ::-webkit-scrollbar {
::-webkit-details-marker { ::-webkit-details-marker {
display: none; display: none;
} }
.chart + .chart {
margin-top: 2em;
}

View File

@ -20,8 +20,20 @@ export default function Component({ service }) {
widget.fields = widget.fields.slice(0, MAX_ALLOWED_FIELDS); widget.fields = widget.fields.slice(0, MAX_ALLOWED_FIELDS);
} }
if (systemsError) { let system = null;
return <Container service={service} error={systemsError} />; let finalError = systemsError;
if (systems && !systems.items) {
finalError = { message: "No items returned from beszel API" };
} else if (systems && systems.items && systemId) {
system = systems.items.find((item) => item.id === systemId);
if (!system) {
finalError = { message: `System with id ${systemId} not found` };
}
}
if (finalError) {
return <Container service={service} error={finalError} />;
} }
if (!systems) { if (!systems) {
@ -33,9 +45,7 @@ export default function Component({ service }) {
); );
} }
if (systemId) { if (system) {
const system = systems.items.find((item) => item.id === systemId);
return ( return (
<Container service={service}> <Container service={service}>
<Block label="beszel.name" value={system.name} /> <Block label="beszel.name" value={system.name} />

View File

@ -59,7 +59,7 @@ export default async function beszelProxyHandler(req, res) {
if (!token) { if (!token) {
[status, token] = await login(loginUrl, widget.username, widget.password, service); [status, token] = await login(loginUrl, widget.username, widget.password, service);
if (status !== 200) { if (status !== 200) {
logger.debug(`HTTP ${status} logging into Beszel: ${token}`); logger.debug(`HTTP ${status} logging into Beszel: ${JSON.stringify(token)}`);
return res.status(status).send(token); return res.status(status).send(token);
} }
} }
@ -72,13 +72,13 @@ export default async function beszelProxyHandler(req, res) {
}, },
}); });
if (status === 403) { if ([400, 403].includes(status)) {
logger.debug(`HTTP ${status} retrieving data from Beszel, logging in and trying again.`); logger.debug(`HTTP ${status} retrieving data from Beszel, logging in and trying again.`);
cache.del(`${tokenCacheKey}.${service}`); cache.del(`${tokenCacheKey}.${service}`);
[status, token] = await login(loginUrl, widget.username, widget.password, service); [status, token] = await login(loginUrl, widget.username, widget.password, service);
if (status !== 200) { if (status !== 200) {
logger.debug(`HTTP ${status} logging into Beszel: ${data}`); logger.debug(`HTTP ${status} logging into Beszel: ${JSON.stringify(data)}`);
return res.status(status).send(data); return res.status(status).send(data);
} }

View File

@ -8,7 +8,7 @@ class Chart extends PureComponent {
const { dataPoints, formatter, label } = this.props; const { dataPoints, formatter, label } = this.props;
return ( return (
<div className="absolute -top-1 -left-1 h-[120px] w-[calc(100%+0.5em)] z-0"> <div className="absolute -top-10 -left-2 h-[calc(100%+3em)] w-[calc(100%+1em)] z-0">
<div className="overflow-clip z-10 w-full h-full"> <div className="overflow-clip z-10 w-full h-full">
<ResponsiveContainer width="100%" height="100%"> <ResponsiveContainer width="100%" height="100%">
<AreaChart data={dataPoints}> <AreaChart data={dataPoints}>

View File

@ -8,7 +8,7 @@ class ChartDual extends PureComponent {
const { dataPoints, formatter, stack, label, stackOffset } = this.props; const { dataPoints, formatter, stack, label, stackOffset } = this.props;
return ( return (
<div className="absolute -top-1 -left-1 h-[120px] w-[calc(100%+0.5em)] z-0"> <div className="absolute -top-10 -left-2 h-[calc(100%+3em)] w-[calc(100%+1em)] z-0">
<div className="overflow-clip z-10 w-full h-full"> <div className="overflow-clip z-10 w-full h-full">
<ResponsiveContainer width="100%" height="100%"> <ResponsiveContainer width="100%" height="100%">
<AreaChart data={dataPoints} stackOffset={stackOffset ?? "none"}> <AreaChart data={dataPoints} stackOffset={stackOffset ?? "none"}>

View File

@ -18,9 +18,9 @@ export default function Container({ children, widget, error = null, chart = true
} }
return ( return (
<div className={classNames("service-container", chart ? "chart relative h-[120px]" : "")}> <div className={classNames("service-container", chart ? "chart relative h-[68px]" : "")}>
{children} {children}
<div className={`absolute top-0 right-0 bottom-0 left-0 overflow-clip pointer-events-none ${className}`} /> <div className={`absolute -top-10 right-0 bottom-0 left-0 overflow-clip pointer-events-none ${className}`} />
{chart && <div className="h-[68px] overflow-clip" />} {chart && <div className="h-[68px] overflow-clip" />}
{!chart && <div className="h-[16px] overflow-clip" />} {!chart && <div className="h-[16px] overflow-clip" />}
</div> </div>

View File

@ -43,7 +43,7 @@ export default function Component({ service }) {
return ( return (
<Container chart={chart}> <Container chart={chart}>
{chart && ( {chart && (
<div className="absolute top-0 left-0 right-0 bottom-0"> <div className="absolute -top-2 -left-2 -right-2 -bottom-2">
<div <div
style={{ style={{
height: `${Math.max(20, fsData.size / fsData.free)}%`, height: `${Math.max(20, fsData.size / fsData.free)}%`,

View File

@ -107,8 +107,12 @@ export default function Component({ service }) {
} }
return ( return (
<Container chart={chart} className="bg-gradient-to-br from-theme-500/30 via-theme-600/20 to-theme-700/10"> <Container chart={chart}>
<Block position="top-3 right-3"> {chart && (
<div className="bg-gradient-to-br from-theme-500/30 via-theme-600/20 to-theme-700/10 absolute -top-10 -left-2 -right-2 -bottom-2 h-[calc(100%+3em)] w-[calc(100%+1em)]" />
)}
<Block position="-top-6 right-2">
{quicklookData && quicklookData.cpu_name && chart && ( {quicklookData && quicklookData.cpu_name && chart && (
<div className="text-[0.6rem] opacity-50">{quicklookData.cpu_name}</div> <div className="text-[0.6rem] opacity-50">{quicklookData.cpu_name}</div>
)} )}
@ -124,7 +128,7 @@ export default function Component({ service }) {
</Block> </Block>
{chart && ( {chart && (
<Block position="bottom-3 left-3"> <Block position="bottom-3 left-2">
{systemData && systemData.linux_distro && <div className="text-xs opacity-50">{systemData.linux_distro}</div>} {systemData && systemData.linux_distro && <div className="text-xs opacity-50">{systemData.linux_distro}</div>}
{systemData && systemData.os_version && <div className="text-xs opacity-50">{systemData.os_version}</div>} {systemData && systemData.os_version && <div className="text-xs opacity-50">{systemData.os_version}</div>}
{systemData && systemData.hostname && <div className="text-xs opacity-75">{systemData.hostname}</div>} {systemData && systemData.hostname && <div className="text-xs opacity-75">{systemData.hostname}</div>}
@ -137,7 +141,7 @@ export default function Component({ service }) {
</Block> </Block>
)} )}
<Block position="bottom-3 right-3 w-[4rem]"> <Block position="bottom-3 right-2 w-[4rem]">
{chart && <CPU quicklookData={quicklookData} className="opacity-50" />} {chart && <CPU quicklookData={quicklookData} className="opacity-50" />}
{chart && <Mem quicklookData={quicklookData} className="opacity-50" />} {chart && <Mem quicklookData={quicklookData} className="opacity-50" />}

View File

@ -42,10 +42,16 @@ export default function Component({ service }) {
} }
data.splice(chart ? 5 : 1); data.splice(chart ? 5 : 1);
let headerYPosition = "top-4";
let listYPosition = "bottom-4";
if (chart) {
headerYPosition = "-top-6";
listYPosition = "-top-3";
}
return ( return (
<Container chart={chart}> <Container chart={chart}>
<Block position="top-4 right-3 left-3"> <Block position={`${headerYPosition} right-3 left-3`}>
<div className="flex items-center text-xs"> <div className="flex items-center text-xs">
<div className="grow" /> <div className="grow" />
<div className="w-14 text-right italic">{t("resources.cpu")}</div> <div className="w-14 text-right italic">{t("resources.cpu")}</div>
@ -53,7 +59,7 @@ export default function Component({ service }) {
</div> </div>
</Block> </Block>
<Block position="bottom-4 right-3 left-3"> <Block position={`${listYPosition} right-3 left-3`}>
<div className="pointer-events-none text-theme-900 dark:text-theme-200"> <div className="pointer-events-none text-theme-900 dark:text-theme-200">
{data.map((item) => ( {data.map((item) => (
<div key={item.pid} className="text-[0.75rem] h-[0.8rem]"> <div key={item.pid} className="text-[0.75rem] h-[0.8rem]">