mirror of
https://github.com/karl0ss/homepage.git
synced 2025-05-03 05:53:40 +01:00
Merge branch 'main' into pr-add-romm
This commit is contained in:
commit
8b28b9d13a
@ -16,6 +16,7 @@ widget:
|
|||||||
view: monthly # optional - possible values monthly, agenda
|
view: monthly # optional - possible values monthly, agenda
|
||||||
maxEvents: 10 # optional - defaults to 10
|
maxEvents: 10 # optional - defaults to 10
|
||||||
showTime: true # optional - show time for event happening today - defaults to false
|
showTime: true # optional - show time for event happening today - defaults to false
|
||||||
|
timezone: America/Los_Angeles # optional and only when timezone is not detected properly (slightly slower performance) - force timezone for ical events (if it's the same - no change, if missing or different in ical - will be converted to this timezone)
|
||||||
integrations: # optional
|
integrations: # optional
|
||||||
- type: sonarr # active widget type that is currently enabled on homepage - possible values: radarr, sonarr, lidarr, readarr, ical
|
- type: sonarr # active widget type that is currently enabled on homepage - possible values: radarr, sonarr, lidarr, readarr, ical
|
||||||
service_group: Media # group name where widget exists
|
service_group: Media # group name where widget exists
|
||||||
@ -27,7 +28,6 @@ widget:
|
|||||||
url: https://domain.url/with/link/to.ics # URL with calendar events
|
url: https://domain.url/with/link/to.ics # URL with calendar events
|
||||||
name: My Events # required - name for these calendar events
|
name: My Events # required - name for these calendar events
|
||||||
color: zinc # optional - defaults to pre-defined color for the service (zinc for ical)
|
color: zinc # optional - defaults to pre-defined color for the service (zinc for ical)
|
||||||
timezone: America/Los_Angeles # optional - force timezone for events (if it's the same - no change, if missing or different in ical - will be converted to this timezone)
|
|
||||||
params: # optional - additional params for the service
|
params: # optional - additional params for the service
|
||||||
showName: true # optional - show name before event title in event line - defaults to false
|
showName: true # optional - show name before event title in event line - defaults to false
|
||||||
```
|
```
|
||||||
|
12
docs/widgets/services/netdata.md
Normal file
12
docs/widgets/services/netdata.md
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
---
|
||||||
|
title: Netdata
|
||||||
|
description: Netdata Widget Configuration
|
||||||
|
---
|
||||||
|
|
||||||
|
Allowed fields: `["warnings", "criticals"]`.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
widget:
|
||||||
|
type: Netdata
|
||||||
|
url: http://netdata.host.or.ip
|
||||||
|
```
|
@ -84,6 +84,7 @@ nav:
|
|||||||
- widgets/services/moonraker.md
|
- widgets/services/moonraker.md
|
||||||
- widgets/services/mylar.md
|
- widgets/services/mylar.md
|
||||||
- widgets/services/navidrome.md
|
- widgets/services/navidrome.md
|
||||||
|
- widgets/services/netdata.md
|
||||||
- widgets/services/nextcloud.md
|
- widgets/services/nextcloud.md
|
||||||
- widgets/services/nextdns.md
|
- widgets/services/nextdns.md
|
||||||
- widgets/services/nginx-proxy-manager.md
|
- widgets/services/nginx-proxy-manager.md
|
||||||
|
@ -799,5 +799,9 @@
|
|||||||
"romm": {
|
"romm": {
|
||||||
"platforms": "Platforms",
|
"platforms": "Platforms",
|
||||||
"totalRoms": "Total ROMs"
|
"totalRoms": "Total ROMs"
|
||||||
|
},
|
||||||
|
"netdata": {
|
||||||
|
"warnings": "Warnings",
|
||||||
|
"criticals": "Criticals"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,7 @@ export default function DateTime({ options }) {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const dateFormat = new Intl.DateTimeFormat(dateLocale, { ...format });
|
const dateFormat = new Intl.DateTimeFormat(dateLocale, { ...format });
|
||||||
|
setDate(dateFormat.format(new Date()));
|
||||||
const interval = setInterval(() => {
|
const interval = setInterval(() => {
|
||||||
setDate(dateFormat.format(new Date()));
|
setDate(dateFormat.format(new Date()));
|
||||||
}, 1000);
|
}, 1000);
|
||||||
|
@ -368,6 +368,7 @@ export function cleanServiceGroups(groups) {
|
|||||||
showTime,
|
showTime,
|
||||||
previousDays,
|
previousDays,
|
||||||
view,
|
view,
|
||||||
|
timezone,
|
||||||
|
|
||||||
// coinmarketcap
|
// coinmarketcap
|
||||||
currency,
|
currency,
|
||||||
@ -538,6 +539,7 @@ export function cleanServiceGroups(groups) {
|
|||||||
if (maxEvents) cleanedService.widget.maxEvents = maxEvents;
|
if (maxEvents) cleanedService.widget.maxEvents = maxEvents;
|
||||||
if (previousDays) cleanedService.widget.previousDays = previousDays;
|
if (previousDays) cleanedService.widget.previousDays = previousDays;
|
||||||
if (showTime) cleanedService.widget.showTime = showTime;
|
if (showTime) cleanedService.widget.showTime = showTime;
|
||||||
|
if (timezone) cleanedService.widget.timezone = timezone;
|
||||||
}
|
}
|
||||||
if (type === "healthchecks") {
|
if (type === "healthchecks") {
|
||||||
if (uuid !== undefined) cleanedService.widget.uuid = uuid;
|
if (uuid !== undefined) cleanedService.widget.uuid = uuid;
|
||||||
|
@ -2,7 +2,7 @@ import { DateTime } from "luxon";
|
|||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
import { useTranslation } from "next-i18next";
|
import { useTranslation } from "next-i18next";
|
||||||
|
|
||||||
import Event, { compareDateTimezoneAware } from "./event";
|
import Event, { compareDateTimezone } from "./event";
|
||||||
|
|
||||||
export default function Agenda({ service, colorVariants, events, showDate }) {
|
export default function Agenda({ service, colorVariants, events, showDate }) {
|
||||||
const { widget } = service;
|
const { widget } = service;
|
||||||
@ -15,10 +15,8 @@ export default function Agenda({ service, colorVariants, events, showDate }) {
|
|||||||
const eventsArray = Object.keys(events)
|
const eventsArray = Object.keys(events)
|
||||||
.filter(
|
.filter(
|
||||||
(eventKey) =>
|
(eventKey) =>
|
||||||
showDate
|
showDate.minus({ days: widget?.previousDays ?? 0 }).startOf("day").ts <=
|
||||||
.setZone(events[eventKey].date.zoneName)
|
events[eventKey].date?.startOf("day").ts,
|
||||||
.minus({ days: widget?.previousDays ?? 0 })
|
|
||||||
.startOf("day").ts <= events[eventKey].date?.startOf("day").ts,
|
|
||||||
)
|
)
|
||||||
.map((eventKey) => events[eventKey])
|
.map((eventKey) => events[eventKey])
|
||||||
.sort((a, b) => a.date - b.date)
|
.sort((a, b) => a.date - b.date)
|
||||||
@ -58,7 +56,7 @@ export default function Agenda({ service, colorVariants, events, showDate }) {
|
|||||||
event={event}
|
event={event}
|
||||||
colorVariants={colorVariants}
|
colorVariants={colorVariants}
|
||||||
showDate={j === 0}
|
showDate={j === 0}
|
||||||
showTime={widget?.showTime && compareDateTimezoneAware(showDate, event)}
|
showTime={widget?.showTime && compareDateTimezone(showDate, event)}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
@ -41,7 +41,8 @@ export default function Component({ service }) {
|
|||||||
const { i18n } = useTranslation();
|
const { i18n } = useTranslation();
|
||||||
const [showDate, setShowDate] = useState(null);
|
const [showDate, setShowDate] = useState(null);
|
||||||
const [events, setEvents] = useState({});
|
const [events, setEvents] = useState({});
|
||||||
const currentDate = DateTime.now().setLocale(i18n.language).startOf("day");
|
const nowDate = DateTime.now().setLocale(i18n.language);
|
||||||
|
const currentDate = widget?.timezone ? nowDate.setZone(widget?.timezone).startOf("day") : nowDate;
|
||||||
const { settings } = useContext(SettingsContext);
|
const { settings } = useContext(SettingsContext);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -93,6 +94,7 @@ export default function Component({ service }) {
|
|||||||
params={params}
|
params={params}
|
||||||
setEvents={setEvents}
|
setEvents={setEvents}
|
||||||
hideErrors={settings.hideErrors}
|
hideErrors={settings.hideErrors}
|
||||||
|
timezone={widget?.timezone}
|
||||||
className="fixed bottom-0 left-0 bg-red-500 w-screen h-12"
|
className="fixed bottom-0 left-0 bg-red-500 w-screen h-12"
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
@ -106,6 +108,7 @@ export default function Component({ service }) {
|
|||||||
events={events}
|
events={events}
|
||||||
showDate={showDate}
|
showDate={showDate}
|
||||||
setShowDate={setShowDate}
|
setShowDate={setShowDate}
|
||||||
|
currentDate={currentDate}
|
||||||
className="flex"
|
className="flex"
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
@ -39,7 +39,4 @@ export default function Event({ event, colorVariants, showDate = false, showTime
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
export const compareDateTimezone = (date, event) => date.startOf("day").ts === event.date.startOf("day").ts;
|
||||||
export function compareDateTimezoneAware(date, event) {
|
|
||||||
return date.setZone(event.date.zoneName).startOf("day").valueOf() === event.date.startOf("day").valueOf();
|
|
||||||
}
|
|
||||||
|
@ -7,7 +7,7 @@ import { RRule } from "rrule";
|
|||||||
import useWidgetAPI from "../../../utils/proxy/use-widget-api";
|
import useWidgetAPI from "../../../utils/proxy/use-widget-api";
|
||||||
import Error from "../../../components/services/widget/error";
|
import Error from "../../../components/services/widget/error";
|
||||||
|
|
||||||
export default function Integration({ config, params, setEvents, hideErrors }) {
|
export default function Integration({ config, params, setEvents, hideErrors, timezone }) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { data: icalData, error: icalError } = useWidgetAPI(config, config.name, {
|
const { data: icalData, error: icalError } = useWidgetAPI(config, config.name, {
|
||||||
refreshInterval: 300000, // 5 minutes
|
refreshInterval: 300000, // 5 minutes
|
||||||
@ -23,9 +23,8 @@ export default function Integration({ config, params, setEvents, hideErrors }) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const zone = config?.timezone || null;
|
const startDate = DateTime.fromISO(params.start);
|
||||||
const startDate = DateTime.fromISO(params.start, { zone });
|
const endDate = DateTime.fromISO(params.end);
|
||||||
const endDate = DateTime.fromISO(params.end, { zone });
|
|
||||||
|
|
||||||
if (icalError || !parsedIcal || !startDate.isValid || !endDate.isValid) {
|
if (icalError || !parsedIcal || !startDate.isValid || !endDate.isValid) {
|
||||||
return;
|
return;
|
||||||
@ -33,6 +32,7 @@ export default function Integration({ config, params, setEvents, hideErrors }) {
|
|||||||
|
|
||||||
const eventsToAdd = {};
|
const eventsToAdd = {};
|
||||||
const events = parsedIcal?.getEventsBetweenDates(startDate.toJSDate(), endDate.toJSDate());
|
const events = parsedIcal?.getEventsBetweenDates(startDate.toJSDate(), endDate.toJSDate());
|
||||||
|
const now = timezone ? DateTime.now().setZone(timezone) : DateTime.now();
|
||||||
|
|
||||||
events?.forEach((event) => {
|
events?.forEach((event) => {
|
||||||
let title = `${event?.summary?.value}`;
|
let title = `${event?.summary?.value}`;
|
||||||
@ -44,8 +44,7 @@ export default function Integration({ config, params, setEvents, hideErrors }) {
|
|||||||
const duration = event.dtend.value - event.dtstart.value;
|
const duration = event.dtend.value - event.dtstart.value;
|
||||||
const days = duration / (1000 * 60 * 60 * 24);
|
const days = duration / (1000 * 60 * 60 * 24);
|
||||||
|
|
||||||
const now = DateTime.now().setZone(zone);
|
const eventDate = timezone ? DateTime.fromJSDate(date, { zone: timezone }) : DateTime.fromJSDate(date);
|
||||||
const eventDate = DateTime.fromJSDate(date, { zone });
|
|
||||||
|
|
||||||
for (let j = 0; j < days; j += 1) {
|
for (let j = 0; j < days; j += 1) {
|
||||||
eventsToAdd[`${event?.uid?.value}${i}${j}${type}`] = {
|
eventsToAdd[`${event?.uid?.value}${i}${j}${type}`] = {
|
||||||
@ -72,7 +71,7 @@ export default function Integration({ config, params, setEvents, hideErrors }) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
setEvents((prevEvents) => ({ ...prevEvents, ...eventsToAdd }));
|
setEvents((prevEvents) => ({ ...prevEvents, ...eventsToAdd }));
|
||||||
}, [icalData, icalError, config, params, setEvents, t]);
|
}, [icalData, icalError, config, params, setEvents, timezone, t]);
|
||||||
|
|
||||||
const error = icalError ?? icalData?.error;
|
const error = icalError ?? icalData?.error;
|
||||||
return error && !hideErrors && <Error error={{ message: `${config.type}: ${error.message ?? error}` }} />;
|
return error && !hideErrors && <Error error={{ message: `${config.type}: ${error.message ?? error}` }} />;
|
||||||
|
@ -3,16 +3,14 @@ import { DateTime, Info } from "luxon";
|
|||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
import { useTranslation } from "next-i18next";
|
import { useTranslation } from "next-i18next";
|
||||||
|
|
||||||
import Event, { compareDateTimezoneAware } from "./event";
|
import Event, { compareDateTimezone } from "./event";
|
||||||
|
|
||||||
const cellStyle = "relative w-10 flex items-center justify-center flex-col";
|
const cellStyle = "relative w-10 flex items-center justify-center flex-col";
|
||||||
const monthButton = "pl-6 pr-6 ml-2 mr-2 hover:bg-theme-100/20 dark:hover:bg-white/5 rounded-md cursor-pointer";
|
const monthButton = "pl-6 pr-6 ml-2 mr-2 hover:bg-theme-100/20 dark:hover:bg-white/5 rounded-md cursor-pointer";
|
||||||
|
|
||||||
export function Day({ weekNumber, weekday, events, colorVariants, showDate, setShowDate }) {
|
export function Day({ weekNumber, weekday, events, colorVariants, showDate, setShowDate, currentDate }) {
|
||||||
const currentDate = DateTime.now();
|
|
||||||
|
|
||||||
const cellDate = showDate.set({ weekday, weekNumber }).startOf("day");
|
const cellDate = showDate.set({ weekday, weekNumber }).startOf("day");
|
||||||
const filteredEvents = events?.filter((event) => compareDateTimezoneAware(cellDate, event));
|
const filteredEvents = events?.filter((event) => compareDateTimezone(cellDate, event));
|
||||||
|
|
||||||
const dayStyles = (displayDate) => {
|
const dayStyles = (displayDate) => {
|
||||||
let style = "h-9 ";
|
let style = "h-9 ";
|
||||||
@ -77,10 +75,9 @@ const dayInWeekId = {
|
|||||||
sunday: 7,
|
sunday: 7,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function Monthly({ service, colorVariants, events, showDate, setShowDate }) {
|
export default function Monthly({ service, colorVariants, events, showDate, setShowDate, currentDate }) {
|
||||||
const { widget } = service;
|
const { widget } = service;
|
||||||
const { i18n } = useTranslation();
|
const { i18n } = useTranslation();
|
||||||
const currentDate = DateTime.now().setLocale(i18n.language).startOf("day");
|
|
||||||
|
|
||||||
const dayNames = Info.weekdays("short", { locale: i18n.language });
|
const dayNames = Info.weekdays("short", { locale: i18n.language });
|
||||||
|
|
||||||
@ -164,6 +161,7 @@ export default function Monthly({ service, colorVariants, events, showDate, setS
|
|||||||
colorVariants={colorVariants}
|
colorVariants={colorVariants}
|
||||||
showDate={showDate}
|
showDate={showDate}
|
||||||
setShowDate={setShowDate}
|
setShowDate={setShowDate}
|
||||||
|
currentDate={currentDate}
|
||||||
/>
|
/>
|
||||||
)),
|
)),
|
||||||
)}
|
)}
|
||||||
@ -171,7 +169,7 @@ export default function Monthly({ service, colorVariants, events, showDate, setS
|
|||||||
|
|
||||||
<div className="flex flex-col">
|
<div className="flex flex-col">
|
||||||
{eventsArray
|
{eventsArray
|
||||||
?.filter((event) => compareDateTimezoneAware(showDate, event))
|
?.filter((event) => compareDateTimezone(showDate, event))
|
||||||
.slice(0, widget?.maxEvents ?? 10)
|
.slice(0, widget?.maxEvents ?? 10)
|
||||||
.map((event) => (
|
.map((event) => (
|
||||||
<Event
|
<Event
|
||||||
@ -179,7 +177,7 @@ export default function Monthly({ service, colorVariants, events, showDate, setS
|
|||||||
event={event}
|
event={event}
|
||||||
colorVariants={colorVariants}
|
colorVariants={colorVariants}
|
||||||
showDateColumn={widget?.showTime ?? false}
|
showDateColumn={widget?.showTime ?? false}
|
||||||
showTime={widget?.showTime && compareDateTimezoneAware(showDate, event)}
|
showTime={widget?.showTime && compareDateTimezone(showDate, event)}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
@ -58,6 +58,7 @@ const components = {
|
|||||||
moonraker: dynamic(() => import("./moonraker/component")),
|
moonraker: dynamic(() => import("./moonraker/component")),
|
||||||
mylar: dynamic(() => import("./mylar/component")),
|
mylar: dynamic(() => import("./mylar/component")),
|
||||||
navidrome: dynamic(() => import("./navidrome/component")),
|
navidrome: dynamic(() => import("./navidrome/component")),
|
||||||
|
netdata: dynamic(() => import("./netdata/component")),
|
||||||
nextcloud: dynamic(() => import("./nextcloud/component")),
|
nextcloud: dynamic(() => import("./nextcloud/component")),
|
||||||
nextdns: dynamic(() => import("./nextdns/component")),
|
nextdns: dynamic(() => import("./nextdns/component")),
|
||||||
npm: dynamic(() => import("./npm/component")),
|
npm: dynamic(() => import("./npm/component")),
|
||||||
|
33
src/widgets/netdata/component.jsx
Normal file
33
src/widgets/netdata/component.jsx
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import { useTranslation } from "next-i18next";
|
||||||
|
|
||||||
|
import Container from "components/services/widget/container";
|
||||||
|
import Block from "components/services/widget/block";
|
||||||
|
import useWidgetAPI from "utils/proxy/use-widget-api";
|
||||||
|
|
||||||
|
export default function Component({ service }) {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
const { widget } = service;
|
||||||
|
|
||||||
|
const { data: netdataData, error: netdataError } = useWidgetAPI(widget, "info");
|
||||||
|
|
||||||
|
if (netdataError) {
|
||||||
|
return <Container service={service} error={netdataError} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!netdataData) {
|
||||||
|
return (
|
||||||
|
<Container service={service}>
|
||||||
|
<Block label="netdata.warnings" />
|
||||||
|
<Block label="netdata.criticals" />
|
||||||
|
</Container>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Container service={service}>
|
||||||
|
<Block label="netdata.warnings" value={t("common.number", { value: netdataData.alarms.warning })} />
|
||||||
|
<Block label="netdata.criticals" value={t("common.number", { value: netdataData.alarms.critical })} />
|
||||||
|
</Container>
|
||||||
|
);
|
||||||
|
}
|
14
src/widgets/netdata/widget.js
Normal file
14
src/widgets/netdata/widget.js
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import genericProxyHandler from "utils/proxy/handlers/generic";
|
||||||
|
|
||||||
|
const widget = {
|
||||||
|
api: "{url}/api/v1/{endpoint}",
|
||||||
|
proxyHandler: genericProxyHandler,
|
||||||
|
|
||||||
|
mappings: {
|
||||||
|
info: {
|
||||||
|
endpoint: "info",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default widget;
|
@ -50,6 +50,7 @@ import mjpeg from "./mjpeg/widget";
|
|||||||
import moonraker from "./moonraker/widget";
|
import moonraker from "./moonraker/widget";
|
||||||
import mylar from "./mylar/widget";
|
import mylar from "./mylar/widget";
|
||||||
import navidrome from "./navidrome/widget";
|
import navidrome from "./navidrome/widget";
|
||||||
|
import netdata from "./netdata/widget";
|
||||||
import nextcloud from "./nextcloud/widget";
|
import nextcloud from "./nextcloud/widget";
|
||||||
import nextdns from "./nextdns/widget";
|
import nextdns from "./nextdns/widget";
|
||||||
import npm from "./npm/widget";
|
import npm from "./npm/widget";
|
||||||
@ -156,6 +157,7 @@ const widgets = {
|
|||||||
moonraker,
|
moonraker,
|
||||||
mylar,
|
mylar,
|
||||||
navidrome,
|
navidrome,
|
||||||
|
netdata,
|
||||||
nextcloud,
|
nextcloud,
|
||||||
nextdns,
|
nextdns,
|
||||||
npm,
|
npm,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user