diff --git a/.github/workflows/repo-maintenance.yml b/.github/workflows/repo-maintenance.yml index d1f7e4fd..7cf47c51 100644 --- a/.github/workflows/repo-maintenance.yml +++ b/.github/workflows/repo-maintenance.yml @@ -42,17 +42,17 @@ jobs: This issue has been automatically locked since there has not been any recent activity after it was closed. 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: > This pull request has been automatically locked since there has not been any recent activity after it was closed. 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: > This discussion has been automatically locked since there has not been any recent activity after it was closed. 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: name: 'Close Answered Discussions' runs-on: ubuntu-latest @@ -92,7 +92,7 @@ jobs: }`; const commentVariables = { 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) @@ -182,7 +182,7 @@ jobs: }`; const commentVariables = { 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); @@ -260,7 +260,7 @@ jobs: }`; const commentVariables = { 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); diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7dfb6a6d..48f2818d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -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) -# 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: diff --git a/docs/widgets/services/openwrt.md b/docs/widgets/services/openwrt.md index c1c3ee94..3759d2b0 100644 --- a/docs/widgets/services/openwrt.md +++ b/docs/widgets/services/openwrt.md @@ -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: -``` +```json { - "homepage": { - "description": "Homepage widget", - "read": { - "ubus": { - "network.interface.wan": ["status"], - "network.interface.lan": ["status"], - "network.device": ["status"] - "system": ["info"] - } - }, - } + "homepage": { + "description": "Homepage widget", + "read": { + "ubus": { + "network.interface.wan": ["status"], + "network.interface.lan": ["status"], + "network.device": ["status"], + "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: -```config login +```sh +uhttpd -m "" +``` + +Then add a user that will use the ACL and hashed password in `/etc/config/rpcd`: + +``` +config login option username 'homepage' - option password '' + option password '' list read homepage - list write '*' ``` This username and password will be used in Homepage's services.yaml to grant access. diff --git a/src/components/services/status.jsx b/src/components/services/status.jsx index e0f74210..3a6f3b33 100644 --- a/src/components/services/status.jsx +++ b/src/components/services/status.jsx @@ -7,33 +7,31 @@ export default function Status({ service, style }) { const { data, error } = useSWR(`/api/docker/status/${service.container}/${service.server || ""}`); 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 colorClass = "text-black/20 dark:text-white/40 "; if (error) { - statusTitle = t("docker.error"); + statusLabel = t("docker.error"); colorClass = "text-rose-500/80"; } else if (data) { if (data.status?.includes("running")) { - if (data.health === "starting") { - 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"; - } + colorClass = "text-emerald-500/80"; if (!data.health) { statusLabel = data.status.replace("running", t("docker.running")); } else { statusLabel = data.health === "healthy" ? t("docker.healthy") : data.health; - } - statusTitle = statusLabel; - colorClass = "text-emerald-500/80"; + if (data.health === "starting") { + 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")) { @@ -47,13 +45,14 @@ export default function Status({ service, style }) { if (style === "dot") { colorClass = colorClass.replace(/text-/g, "bg-").replace(/\/\d\d/g, ""); backgroundClass = "p-4 hover:bg-theme-500/10 dark:hover:bg-theme-900/20"; - statusTitle = statusLabel; } return (
{style !== "dot" ? (
{statusLabel}
diff --git a/src/components/widgets/widget/container.jsx b/src/components/widgets/widget/container.jsx index 442aa084..c9240dd3 100644 --- a/src/components/widgets/widget/container.jsx +++ b/src/components/widgets/widget/container.jsx @@ -16,7 +16,7 @@ export function getAllClasses(options, additionalClassNames = "") { } 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", 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"; 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); diff --git a/src/pages/api/config/[path].js b/src/pages/api/config/[path].js index 7f3b6a07..6cb04698 100644 --- a/src/pages/api/config/[path].js +++ b/src/pages/api/config/[path].js @@ -28,7 +28,7 @@ export default async function handler(req, res) { res.setHeader("Content-Type", mimeType); return res.status(200).send(fileContent); } catch (error) { - logger.error(error); + if (error) logger.error(error); return res.status(500).end("Internal Server Error"); } } diff --git a/src/pages/api/docker/stats/[...service].js b/src/pages/api/docker/stats/[...service].js index 715e5188..e92bad7c 100644 --- a/src/pages/api/docker/stats/[...service].js +++ b/src/pages/api/docker/stats/[...service].js @@ -80,7 +80,7 @@ export default async function handler(req, res) { error: "not found", }); } catch (e) { - logger.error(e); + if (e) logger.error(e); return res.status(500).send({ error: { message: e?.message ?? "Unknown error" }, }); diff --git a/src/pages/api/docker/status/[...service].js b/src/pages/api/docker/status/[...service].js index 96c6bea6..f9dc640b 100644 --- a/src/pages/api/docker/status/[...service].js +++ b/src/pages/api/docker/status/[...service].js @@ -108,7 +108,7 @@ export default async function handler(req, res) { status: "not found", }); } catch (e) { - logger.error(e); + if (e) logger.error(e); return res.status(500).send({ error: { message: e?.message ?? "Unknown error" }, }); diff --git a/src/pages/api/kubernetes/stats/[...service].js b/src/pages/api/kubernetes/stats/[...service].js index 90a67bec..b1bf8345 100644 --- a/src/pages/api/kubernetes/stats/[...service].js +++ b/src/pages/api/kubernetes/stats/[...service].js @@ -106,7 +106,7 @@ export default async function handler(req, res) { stats, }); } catch (e) { - logger.error(e); + if (e) logger.error(e); res.status(500).send({ error: "unknown error", }); diff --git a/src/pages/api/kubernetes/status/[...service].js b/src/pages/api/kubernetes/status/[...service].js index 1ca19126..f771d69d 100644 --- a/src/pages/api/kubernetes/status/[...service].js +++ b/src/pages/api/kubernetes/status/[...service].js @@ -59,7 +59,7 @@ export default async function handler(req, res) { status, }); } catch (e) { - logger.error(e); + if (e) logger.error(e); res.status(500).send({ error: "unknown error", }); diff --git a/src/pages/api/services/proxy.js b/src/pages/api/services/proxy.js index 80856419..be4a96a6 100644 --- a/src/pages/api/services/proxy.js +++ b/src/pages/api/services/proxy.js @@ -71,8 +71,8 @@ export default async function handler(req, res) { logger.debug("Unknown proxy service type: %s", type); return res.status(403).json({ error: "Unkown proxy service type" }); - } catch (ex) { - logger.error(ex); + } catch (e) { + if (e) logger.error(e); return res.status(500).send({ error: "Unexpected error" }); } } diff --git a/src/pages/api/widgets/kubernetes.js b/src/pages/api/widgets/kubernetes.js index b55b02d7..0859212f 100644 --- a/src/pages/api/widgets/kubernetes.js +++ b/src/pages/api/widgets/kubernetes.js @@ -94,7 +94,7 @@ export default async function handler(req, res) { nodes: Object.entries(nodeMap).map(([name, node]) => ({ name, ...node })), }); } catch (e) { - logger.error("exception %s", e); + if (e) logger.error(e); return res.status(500).send({ error: "unknown error", }); diff --git a/src/pages/index.jsx b/src/pages/index.jsx index 39ac6cf2..10b2f6d5 100644 --- a/src/pages/index.jsx +++ b/src/pages/index.jsx @@ -65,7 +65,7 @@ export async function getStaticProps() { }, }; } catch (e) { - if (logger) { + if (logger && e) { logger.error(e); } return { @@ -161,10 +161,10 @@ function Index({ initialSettings, fallback }) { const headerStyles = { 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", - underlined: "m-6 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", - boxedWidgets: "m-6 mb-0 sm:m-9 sm:mb-0 sm:mt-1", + "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-5 mb-0 sm:m-9 sm:mb-1 border-b-2 pb-4 border-theme-800 dark:border-theme-200/50", + clean: "m-5 mb-0 sm:m-9 sm:mb-0", + boxedWidgets: "m-5 mb-0 sm:m-9 sm:mb-0 sm:mt-1", }; function Home({ initialSettings }) { @@ -225,7 +225,7 @@ function Home({ initialSettings }) { if (e.target.tagName === "BODY" || e.target.id === "inner_wrapper") { if ( (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.key.match(/([à-ü]|[À-Ü])/g) || // accented characters may require modifier keys (e.key === "v" && (e.ctrlKey || e.metaKey)) @@ -282,7 +282,7 @@ function Home({ initialSettings }) { return ( <> {tabs.length > 0 && ( -
+
    -
    +
    {widgets && ( <> {widgets @@ -436,7 +432,7 @@ function Home({ initialSettings }) { id="information-widgets-right" className={classNames( "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 diff --git a/src/utils/config/service-helpers.js b/src/utils/config/service-helpers.js index 9f997915..77c9a673 100644 --- a/src/utils/config/service-helpers.js +++ b/src/utils/config/service-helpers.js @@ -325,7 +325,7 @@ export async function servicesFromKubernetes() { return mappedServiceGroups; } catch (e) { - logger.error(e); + if (e) logger.error(e); throw e; } } diff --git a/src/utils/proxy/http.js b/src/utils/proxy/http.js index 1755dd93..ff34ce0d 100644 --- a/src/utils/proxy/http.js +++ b/src/utils/proxy/http.js @@ -44,7 +44,7 @@ function handleRequest(requestor, url, params) { // zlib errors responseContent.on("error", (e) => { - logger.error(e); + if (e) logger.error(e); responseContent = response; // fallback }); response.pipe(responseContent); @@ -112,7 +112,7 @@ export async function httpProxy(url, params = {}) { constructedUrl.port ? `:${constructedUrl.port}` : "", constructedUrl.pathname, ); - logger.error(err); + if (err) logger.error(err); return [500, "application/json", { error: { message: err?.message ?? "Unknown error", url, rawError: err } }, null]; } } diff --git a/src/widgets/audiobookshelf/proxy.js b/src/widgets/audiobookshelf/proxy.js index c4dba5cd..9701c1fe 100644 --- a/src/widgets/audiobookshelf/proxy.js +++ b/src/widgets/audiobookshelf/proxy.js @@ -63,7 +63,7 @@ export default async function audiobookshelfProxyHandler(req, res) { return res.status(200).send(libraryStats); } catch (e) { - logger.error(e.message); + if (e) logger.error(e); return res.status(500).send({ error: { message: e.message } }); } } diff --git a/src/widgets/gamedig/proxy.js b/src/widgets/gamedig/proxy.js index 0029834c..8a7e55c5 100644 --- a/src/widgets/gamedig/proxy.js +++ b/src/widgets/gamedig/proxy.js @@ -28,7 +28,7 @@ export default async function gamedigProxyHandler(req, res) { ping: serverData.ping, }); } catch (e) { - logger.error(e); + if (e) logger.error(e); res.status(200).send({ online: false, diff --git a/src/widgets/minecraft/proxy.js b/src/widgets/minecraft/proxy.js index 7aeedfb9..f7bac9d4 100644 --- a/src/widgets/minecraft/proxy.js +++ b/src/widgets/minecraft/proxy.js @@ -18,7 +18,7 @@ export default async function minecraftProxyHandler(req, res) { players: pingResponse.players, }); } catch (e) { - logger.error(e); + if (e) logger.error(e); res.status(200).send({ version: undefined, online: false, diff --git a/src/widgets/pyload/proxy.js b/src/widgets/pyload/proxy.js index 802a67c6..4d7cd116 100644 --- a/src/widgets/pyload/proxy.js +++ b/src/widgets/pyload/proxy.js @@ -103,7 +103,7 @@ export default async function pyloadProxyHandler(req, res) { } } } catch (e) { - logger.error(e); + if (e) logger.error(e); return res.status(500).send({ error: { message: `Error communicating with Pyload API: ${e.toString()}` } }); }