Merge branch 'gethomepage:main' into main

pull/3286/head
brikim 3 months ago committed by GitHub
commit e6f61b956f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -42,17 +42,17 @@ jobs:
This issue has been automatically locked since there This issue has been automatically locked since there
has not been any recent activity after it was closed. has not been any recent activity after it was closed.
Please open a new discussion for related concerns. Please open a new discussion for related concerns.
See our [contributing guidelines](https://github.com/gethomepage/homepage/blob/main/CONTRIBUTING.md#automatic-respoistory-maintenance) for more details. See our [contributing guidelines](https://github.com/gethomepage/homepage/blob/main/CONTRIBUTING.md#automatic-repository-maintenance) for more details.
pr-comment: > pr-comment: >
This pull request has been automatically locked since there This pull request has been automatically locked since there
has not been any recent activity after it was closed. has not been any recent activity after it was closed.
Please open a new discussion for related concerns. Please open a new discussion for related concerns.
See our [contributing guidelines](https://github.com/gethomepage/homepage/blob/main/CONTRIBUTING.md#automatic-respoistory-maintenance) for more details. See our [contributing guidelines](https://github.com/gethomepage/homepage/blob/main/CONTRIBUTING.md#automatic-repository-maintenance) for more details.
discussion-comment: > discussion-comment: >
This discussion has been automatically locked since there This discussion has been automatically locked since there
has not been any recent activity after it was closed. has not been any recent activity after it was closed.
Please open a new discussion for related concerns. Please open a new discussion for related concerns.
See our [contributing guidelines](https://github.com/gethomepage/homepage/blob/main/CONTRIBUTING.md#automatic-respoistory-maintenance) for more details. See our [contributing guidelines](https://github.com/gethomepage/homepage/blob/main/CONTRIBUTING.md#automatic-repository-maintenance) for more details.
close-answered-discussions: close-answered-discussions:
name: 'Close Answered Discussions' name: 'Close Answered Discussions'
runs-on: ubuntu-latest runs-on: ubuntu-latest
@ -92,7 +92,7 @@ jobs:
}`; }`;
const commentVariables = { const commentVariables = {
discussion: discussion.id, discussion: discussion.id,
body: 'This discussion has been automatically closed because it was marked as answered. See our [contributing guidelines](https://github.com/gethomepage/homepage/blob/main/CONTRIBUTING.md#automatic-respoistory-maintenance) for more details.', body: 'This discussion has been automatically closed because it was marked as answered. See our [contributing guidelines](https://github.com/gethomepage/homepage/blob/main/CONTRIBUTING.md#automatic-repository-maintenance) for more details.',
} }
await github.graphql(addCommentMutation, commentVariables) await github.graphql(addCommentMutation, commentVariables)
@ -182,7 +182,7 @@ jobs:
}`; }`;
const commentVariables = { const commentVariables = {
discussion: discussion.id, discussion: discussion.id,
body: 'This discussion has been automatically closed due to inactivity. See our [contributing guidelines](https://github.com/gethomepage/homepage/blob/main/CONTRIBUTING.md#automatic-respoistory-maintenance) for more details.', body: 'This discussion has been automatically closed due to inactivity. See our [contributing guidelines](https://github.com/gethomepage/homepage/blob/main/CONTRIBUTING.md#automatic-repository-maintenance) for more details.',
} }
await github.graphql(addCommentMutation, commentVariables); await github.graphql(addCommentMutation, commentVariables);
@ -260,7 +260,7 @@ jobs:
}`; }`;
const commentVariables = { const commentVariables = {
discussion: discussion.id, discussion: discussion.id,
body: 'This discussion has been automatically closed due to lack of community support. See our [contributing guidelines](https://github.com/gethomepage/homepage/blob/main/CONTRIBUTING.md#automatic-respoistory-maintenance) for more details.', body: 'This discussion has been automatically closed due to lack of community support. See our [contributing guidelines](https://github.com/gethomepage/homepage/blob/main/CONTRIBUTING.md#automatic-repository-maintenance) for more details.',
} }
await github.graphql(addCommentMutation, commentVariables); await github.graphql(addCommentMutation, commentVariables);

@ -52,7 +52,7 @@ By contributing, you agree that your contributions will be licensed under its GN
This document was adapted from the open-source contribution guidelines for [Facebook's Draft](https://github.com/facebook/draft-js/blob/main/CONTRIBUTING.md) This document was adapted from the open-source contribution guidelines for [Facebook's Draft](https://github.com/facebook/draft-js/blob/main/CONTRIBUTING.md)
# Automatic Respoistory Maintenance # Automatic Respository Maintenance
The homepage team appreciates all effort and interest from the community in filing bug reports, creating feature requests, sharing ideas and helping other community members. That said, in an effort to keep the repository organized and managebale the project uses automatic handling of certain areas: The homepage team appreciates all effort and interest from the community in filing bug reports, creating feature requests, sharing ideas and helping other community members. That said, in an effort to keep the repository organized and managebale the project uses automatic handling of certain areas:

@ -26,29 +26,35 @@ In order for homepage to access the OpenWRT RPC endpoints you will need to [crea
Create an ACL named `homepage.json` in `/usr/share/rpcd/acl.d/`, the following permissions will suffice: Create an ACL named `homepage.json` in `/usr/share/rpcd/acl.d/`, the following permissions will suffice:
``` ```json
{ {
"homepage": { "homepage": {
"description": "Homepage widget", "description": "Homepage widget",
"read": { "read": {
"ubus": { "ubus": {
"network.interface.wan": ["status"], "network.interface.wan": ["status"],
"network.interface.lan": ["status"], "network.interface.lan": ["status"],
"network.device": ["status"] "network.device": ["status"],
"system": ["info"] "system": ["info"]
} }
}, }
} }
} }
``` ```
Then add a user that will use that ACL in `/etc/config/rpc`: Create a `crypt(5)` password hash using the following command in the OpenWRT shell:
```sh
uhttpd -m "<somepassphrase>"
```
```config login Then add a user that will use the ACL and hashed password in `/etc/config/rpcd`:
```
config login
option username 'homepage' option username 'homepage'
option password '<password>' option password '<hashedpassword>'
list read homepage list read homepage
list write '*'
``` ```
This username and password will be used in Homepage's services.yaml to grant access. This username and password will be used in Homepage's services.yaml to grant access.

@ -7,33 +7,31 @@ export default function Status({ service, style }) {
const { data, error } = useSWR(`/api/docker/status/${service.container}/${service.server || ""}`); const { data, error } = useSWR(`/api/docker/status/${service.container}/${service.server || ""}`);
let statusLabel = t("docker.unknown"); let statusLabel = t("docker.unknown");
let statusTitle = "";
let backgroundClass = "px-1.5 py-0.5 bg-theme-500/10 dark:bg-theme-900/50"; let backgroundClass = "px-1.5 py-0.5 bg-theme-500/10 dark:bg-theme-900/50";
let colorClass = "text-black/20 dark:text-white/40 "; let colorClass = "text-black/20 dark:text-white/40 ";
if (error) { if (error) {
statusTitle = t("docker.error"); statusLabel = t("docker.error");
colorClass = "text-rose-500/80"; colorClass = "text-rose-500/80";
} else if (data) { } else if (data) {
if (data.status?.includes("running")) { if (data.status?.includes("running")) {
if (data.health === "starting") { colorClass = "text-emerald-500/80";
statusTitle = t("docker.starting");
colorClass = "text-blue-500/80";
}
if (data.health === "unhealthy") {
statusTitle = t("docker.unhealthy");
colorClass = "text-orange-400/50 dark:text-orange-400/80";
}
if (!data.health) { if (!data.health) {
statusLabel = data.status.replace("running", t("docker.running")); statusLabel = data.status.replace("running", t("docker.running"));
} else { } else {
statusLabel = data.health === "healthy" ? t("docker.healthy") : data.health; statusLabel = data.health === "healthy" ? t("docker.healthy") : data.health;
}
statusTitle = statusLabel; if (data.health === "starting") {
colorClass = "text-emerald-500/80"; statusLabel = t("docker.starting");
colorClass = "text-blue-500/80";
}
if (data.health === "unhealthy") {
statusLabel = t("docker.unhealthy");
colorClass = "text-orange-400/50 dark:text-orange-400/80";
}
}
} }
if (data.status === "not found" || data.status === "exited" || data.status?.startsWith("partial")) { if (data.status === "not found" || data.status === "exited" || data.status?.startsWith("partial")) {
@ -47,13 +45,14 @@ export default function Status({ service, style }) {
if (style === "dot") { if (style === "dot") {
colorClass = colorClass.replace(/text-/g, "bg-").replace(/\/\d\d/g, ""); colorClass = colorClass.replace(/text-/g, "bg-").replace(/\/\d\d/g, "");
backgroundClass = "p-4 hover:bg-theme-500/10 dark:hover:bg-theme-900/20"; backgroundClass = "p-4 hover:bg-theme-500/10 dark:hover:bg-theme-900/20";
statusTitle = statusLabel;
} }
return ( return (
<div <div
className={`w-auto text-center overflow-hidden ${backgroundClass} rounded-b-[3px] docker-status`} className={`w-auto text-center overflow-hidden ${backgroundClass} rounded-b-[3px] docker-status docker-status-${statusLabel
title={statusTitle} .toLowerCase()
.replace(" ", "-")}`}
title={statusLabel}
> >
{style !== "dot" ? ( {style !== "dot" ? (
<div className={`text-[8px] font-bold ${colorClass} uppercase`}>{statusLabel}</div> <div className={`text-[8px] font-bold ${colorClass} uppercase`}>{statusLabel}</div>

@ -16,7 +16,7 @@ export function getAllClasses(options, additionalClassNames = "") {
} }
return classNames( return classNames(
"flex flex-col justify-center ml-2 mr-2", "flex flex-col justify-center",
"mt-2 m:mb-0 rounded-md shadow-md shadow-theme-900/10 dark:shadow-theme-900/20 bg-theme-100/20 dark:bg-white/5 p-2 pl-3 pr-3", "mt-2 m:mb-0 rounded-md shadow-md shadow-theme-900/10 dark:shadow-theme-900/20 bg-theme-100/20 dark:bg-white/5 p-2 pl-3 pr-3",
additionalClassNames, additionalClassNames,
); );
@ -24,7 +24,7 @@ export function getAllClasses(options, additionalClassNames = "") {
let widgetAlignedClasses = "flex flex-col max-w:full sm:basis-auto self-center grow-0 flex-wrap"; let widgetAlignedClasses = "flex flex-col max-w:full sm:basis-auto self-center grow-0 flex-wrap";
if (options?.style?.isRightAligned) { if (options?.style?.isRightAligned) {
widgetAlignedClasses = "flex flex-col justify-center first:ml-auto ml-2 mr-2 "; widgetAlignedClasses = "flex flex-col justify-center";
} }
return classNames(widgetAlignedClasses, additionalClassNames); return classNames(widgetAlignedClasses, additionalClassNames);

@ -28,7 +28,7 @@ export default async function handler(req, res) {
res.setHeader("Content-Type", mimeType); res.setHeader("Content-Type", mimeType);
return res.status(200).send(fileContent); return res.status(200).send(fileContent);
} catch (error) { } catch (error) {
logger.error(error); if (error) logger.error(error);
return res.status(500).end("Internal Server Error"); return res.status(500).end("Internal Server Error");
} }
} }

@ -80,7 +80,7 @@ export default async function handler(req, res) {
error: "not found", error: "not found",
}); });
} catch (e) { } catch (e) {
logger.error(e); if (e) logger.error(e);
return res.status(500).send({ return res.status(500).send({
error: { message: e?.message ?? "Unknown error" }, error: { message: e?.message ?? "Unknown error" },
}); });

@ -108,7 +108,7 @@ export default async function handler(req, res) {
status: "not found", status: "not found",
}); });
} catch (e) { } catch (e) {
logger.error(e); if (e) logger.error(e);
return res.status(500).send({ return res.status(500).send({
error: { message: e?.message ?? "Unknown error" }, error: { message: e?.message ?? "Unknown error" },
}); });

@ -106,7 +106,7 @@ export default async function handler(req, res) {
stats, stats,
}); });
} catch (e) { } catch (e) {
logger.error(e); if (e) logger.error(e);
res.status(500).send({ res.status(500).send({
error: "unknown error", error: "unknown error",
}); });

@ -59,7 +59,7 @@ export default async function handler(req, res) {
status, status,
}); });
} catch (e) { } catch (e) {
logger.error(e); if (e) logger.error(e);
res.status(500).send({ res.status(500).send({
error: "unknown error", error: "unknown error",
}); });

@ -71,8 +71,8 @@ export default async function handler(req, res) {
logger.debug("Unknown proxy service type: %s", type); logger.debug("Unknown proxy service type: %s", type);
return res.status(403).json({ error: "Unkown proxy service type" }); return res.status(403).json({ error: "Unkown proxy service type" });
} catch (ex) { } catch (e) {
logger.error(ex); if (e) logger.error(e);
return res.status(500).send({ error: "Unexpected error" }); return res.status(500).send({ error: "Unexpected error" });
} }
} }

@ -94,7 +94,7 @@ export default async function handler(req, res) {
nodes: Object.entries(nodeMap).map(([name, node]) => ({ name, ...node })), nodes: Object.entries(nodeMap).map(([name, node]) => ({ name, ...node })),
}); });
} catch (e) { } catch (e) {
logger.error("exception %s", e); if (e) logger.error(e);
return res.status(500).send({ return res.status(500).send({
error: "unknown error", error: "unknown error",
}); });

@ -65,7 +65,7 @@ export async function getStaticProps() {
}, },
}; };
} catch (e) { } catch (e) {
if (logger) { if (logger && e) {
logger.error(e); logger.error(e);
} }
return { return {
@ -161,10 +161,10 @@ function Index({ initialSettings, fallback }) {
const headerStyles = { const headerStyles = {
boxed: boxed:
"m-6 mb-0 sm:m-9 sm:mb-0 rounded-md shadow-md shadow-theme-900/10 dark:shadow-theme-900/20 bg-theme-100/20 dark:bg-white/5 p-3", "m-5 mb-0 sm:m-9 sm:mb-0 rounded-md shadow-md shadow-theme-900/10 dark:shadow-theme-900/20 bg-theme-100/20 dark:bg-white/5 p-3",
underlined: "m-6 mb-0 sm:m-9 sm:mb-1 border-b-2 pb-4 border-theme-800 dark:border-theme-200/50", underlined: "m-5 mb-0 sm:m-9 sm:mb-1 border-b-2 pb-4 border-theme-800 dark:border-theme-200/50",
clean: "m-6 mb-0 sm:m-9 sm:mb-0", clean: "m-5 mb-0 sm:m-9 sm:mb-0",
boxedWidgets: "m-6 mb-0 sm:m-9 sm:mb-0 sm:mt-1", boxedWidgets: "m-5 mb-0 sm:m-9 sm:mb-0 sm:mt-1",
}; };
function Home({ initialSettings }) { function Home({ initialSettings }) {
@ -225,7 +225,7 @@ function Home({ initialSettings }) {
if (e.target.tagName === "BODY" || e.target.id === "inner_wrapper") { if (e.target.tagName === "BODY" || e.target.id === "inner_wrapper") {
if ( if (
(e.key.length === 1 && (e.key.length === 1 &&
e.key.match(/(\w|\s|[à-ü]|[À-Ü])/g) && e.key.match(/(\w|\s|[à-ü]|[À-Ü]|[\w\u0430-\u044f])/gi) &&
!(e.altKey || e.ctrlKey || e.metaKey || e.shiftKey)) || !(e.altKey || e.ctrlKey || e.metaKey || e.shiftKey)) ||
e.key.match(/([à-ü]|[À-Ü])/g) || // accented characters may require modifier keys e.key.match(/([à-ü]|[À-Ü])/g) || // accented characters may require modifier keys
(e.key === "v" && (e.ctrlKey || e.metaKey)) (e.key === "v" && (e.ctrlKey || e.metaKey))
@ -282,7 +282,7 @@ function Home({ initialSettings }) {
return ( return (
<> <>
{tabs.length > 0 && ( {tabs.length > 0 && (
<div key="tabs" id="tabs" className="m-6 sm:m-9 sm:mt-4 sm:mb-0"> <div key="tabs" id="tabs" className="m-5 sm:m-9 sm:mt-4 sm:mb-0">
<ul <ul
className={classNames( className={classNames(
"sm:flex rounded-md bg-theme-100/20 dark:bg-white/5", "sm:flex rounded-md bg-theme-100/20 dark:bg-white/5",
@ -415,11 +415,7 @@ function Home({ initialSettings }) {
`backdrop-blur${settings.cardBlur.length ? "-" : ""}${settings.cardBlur}`, `backdrop-blur${settings.cardBlur.length ? "-" : ""}${settings.cardBlur}`,
)} )}
> >
<div <div id="widgets-wrap" className={classNames("flex flex-row w-full flex-wrap justify-between gap-x-2")}>
id="widgets-wrap"
style={{ width: "calc(100% + 1rem)" }}
className={classNames("flex flex-row w-full flex-wrap justify-between -ml-2 -mr-2")}
>
{widgets && ( {widgets && (
<> <>
{widgets {widgets
@ -436,7 +432,7 @@ function Home({ initialSettings }) {
id="information-widgets-right" id="information-widgets-right"
className={classNames( className={classNames(
"m-auto flex flex-wrap grow sm:basis-auto justify-between md:justify-end", "m-auto flex flex-wrap grow sm:basis-auto justify-between md:justify-end",
headerStyle === "boxedWidgets" ? "sm:ml-4" : "sm:ml-2", "m-auto flex flex-wrap grow sm:basis-auto justify-between md:justify-end gap-x-2",
)} )}
> >
{widgets {widgets

@ -325,7 +325,7 @@ export async function servicesFromKubernetes() {
return mappedServiceGroups; return mappedServiceGroups;
} catch (e) { } catch (e) {
logger.error(e); if (e) logger.error(e);
throw e; throw e;
} }
} }

@ -44,7 +44,7 @@ function handleRequest(requestor, url, params) {
// zlib errors // zlib errors
responseContent.on("error", (e) => { responseContent.on("error", (e) => {
logger.error(e); if (e) logger.error(e);
responseContent = response; // fallback responseContent = response; // fallback
}); });
response.pipe(responseContent); response.pipe(responseContent);
@ -112,7 +112,7 @@ export async function httpProxy(url, params = {}) {
constructedUrl.port ? `:${constructedUrl.port}` : "", constructedUrl.port ? `:${constructedUrl.port}` : "",
constructedUrl.pathname, constructedUrl.pathname,
); );
logger.error(err); if (err) logger.error(err);
return [500, "application/json", { error: { message: err?.message ?? "Unknown error", url, rawError: err } }, null]; return [500, "application/json", { error: { message: err?.message ?? "Unknown error", url, rawError: err } }, null];
} }
} }

@ -63,7 +63,7 @@ export default async function audiobookshelfProxyHandler(req, res) {
return res.status(200).send(libraryStats); return res.status(200).send(libraryStats);
} catch (e) { } catch (e) {
logger.error(e.message); if (e) logger.error(e);
return res.status(500).send({ error: { message: e.message } }); return res.status(500).send({ error: { message: e.message } });
} }
} }

@ -28,7 +28,7 @@ export default async function gamedigProxyHandler(req, res) {
ping: serverData.ping, ping: serverData.ping,
}); });
} catch (e) { } catch (e) {
logger.error(e); if (e) logger.error(e);
res.status(200).send({ res.status(200).send({
online: false, online: false,

@ -18,7 +18,7 @@ export default async function minecraftProxyHandler(req, res) {
players: pingResponse.players, players: pingResponse.players,
}); });
} catch (e) { } catch (e) {
logger.error(e); if (e) logger.error(e);
res.status(200).send({ res.status(200).send({
version: undefined, version: undefined,
online: false, online: false,

@ -103,7 +103,7 @@ export default async function pyloadProxyHandler(req, res) {
} }
} }
} catch (e) { } catch (e) {
logger.error(e); if (e) logger.error(e);
return res.status(500).send({ error: { message: `Error communicating with Pyload API: ${e.toString()}` } }); return res.status(500).send({ error: { message: `Error communicating with Pyload API: ${e.toString()}` } });
} }

Loading…
Cancel
Save