Merge branch 'dev'

This commit is contained in:
shamoon 2025-04-28 08:21:29 -07:00
commit 63e521ae93
No known key found for this signature in database
304 changed files with 1291 additions and 988 deletions

View File

@ -16,11 +16,11 @@
**/compose*
**/Dockerfile*
**/node_modules
!.next/standalone/node_modules
**/npm-debug.log
**/obj
**/secrets.dev.yaml
**/values.dev.yaml
**/.next
README.md
config/
k3d/

View File

@ -1,9 +1,4 @@
name: Docker
# This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by
# separate terms of service, privacy policy, and support
# documentation.
name: Docker CI
on:
schedule:
@ -13,7 +8,6 @@ on:
- main
- feature/**
- dev
# Publish semver tags as releases.
tags: [ 'v*.*.*' ]
paths-ignore:
- 'docs/**'
@ -26,89 +20,56 @@ on:
merge_group:
env:
# github.repository as <account>/<repo>
IMAGE_NAME: ${{ github.repository }}
jobs:
pre-commit:
name: Linting Checks
runs-on: ubuntu-22.04
steps:
-
name: Checkout repository
- name: Checkout repository
uses: actions/checkout@v4
-
name: Install python
- name: Install python
uses: actions/setup-python@v5
with:
python-version: 3.x
-
name: Check files
- name: Check files
uses: pre-commit/action@v3.0.1
-
name: Install pnpm
- name: Install pnpm
uses: pnpm/action-setup@v4
with:
version: 10
run_install: false
-
name: Install Node.js
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: 'pnpm'
-
name: Install dependencies
- name: Install dependencies
run: pnpm install
-
name: Lint frontend
- name: Lint frontend
run: pnpm run lint
build:
name: Docker Build & Push
if: github.repository == 'gethomepage/homepage'
runs-on: self-hosted
needs:
- pre-commit
needs: [ pre-commit ]
permissions:
contents: read
packages: write
# This is used to complete the identity challenge
# with sigstore/fulcio when running outside of PRs.
id-token: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
# Login to Docker Registry
# https://github.com/docker/login-action
- name: Log into registry ${{ env.REGISTRY }}
if: github.event_name != 'pull_request'
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Login to Docker Hub
if: github.event_name != 'pull_request'
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
# Setup QEMU
# https://github.com/marketplace/actions/docker-setup-buildx#with-qemu
- name: Setup QEMU
uses: docker/setup-qemu-action@v3.6.0
# Workaround: https://github.com/docker/build-push-action/issues/461
- name: Setup Docker buildx
uses: docker/setup-buildx-action@v3
# Extract metadata (tags, labels) for Docker
# https://github.com/docker/metadata-action
- name: Extract Docker metadata
id: meta
uses: docker/metadata-action@v5
@ -116,11 +77,69 @@ jobs:
images: |
${{ env.IMAGE_NAME }}
ghcr.io/${{ env.IMAGE_NAME }}
tags: |
# Default tags
type=schedule,pattern=nightly
type=ref,event=branch
type=ref,event=tag
# Versioning tags
type=semver,pattern=v{{version}}
type=semver,pattern=v{{major}}.{{minor}}
type=semver,pattern=v{{major}}
flavor: |
latest=auto
# Build and push Docker image with Buildx (don't push on PR)
# https://github.com/docker/build-push-action
- name: Next.js build cache
uses: actions/cache@v4
with:
path: .next/cache
key: nextjs-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}-${{ hashFiles('**/*.js', '**/*.jsx') }}
restore-keys: |
nextjs-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
- name: Install pnpm
uses: pnpm/action-setup@v4
with:
version: 10
run_install: false
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: 'pnpm'
- name: Install dependencies
run: pnpm install
- name: Build app
run: |
NEXT_PUBLIC_BUILDTIME="${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.created'] }}" \
NEXT_PUBLIC_VERSION="${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.version'] }}" \
NEXT_PUBLIC_REVISION="${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.revision'] }}" \
pnpm run build
- name: Log into registry ${{ env.REGISTRY }}
if: github.event_name != 'pull_request'
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Login to Docker Hub
if: github.event_name != 'pull_request'
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Setup QEMU
uses: docker/setup-qemu-action@v3.6.0
- name: Setup Docker buildx
uses: docker/setup-buildx-action@v3
- name: Build and push Docker image
id: build-and-push
uses: docker/build-push-action@v6
@ -130,18 +149,15 @@ jobs:
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
CI=true
BUILDTIME=${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.created'] }}
VERSION=${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.version'] }}
REVISION=${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.revision'] }}
# https://github.com/docker/setup-qemu-action#about
# platforms: linux/amd64,linux/arm64,linux/riscv64,linux/ppc64le,linux/s390x,linux/386,linux/mips64le,linux/mips64,linux/arm/v7,linux/arm/v6
platforms: linux/amd64,linux/arm64
cache-from: type=local,src=/tmp/.buildx-cache
cache-to: type=local,dest=/tmp/.buildx-cache-new,mode=max
# Temp fix
# https://github.com/docker/build-push-action/issues/252
# https://github.com/moby/buildkit/issues/1896
# https://github.com/docker/build-push-action/issues/252 / https://github.com/moby/buildkit/issues/1896
- name: Move cache
run: |
rm -rf /tmp/.buildx-cache

View File

@ -9,11 +9,14 @@ repos:
- id: check-yaml
exclude: "(^mkdocs\\.yml$)"
- id: check-added-large-files
- repo: https://github.com/pre-commit/mirrors-prettier
rev: 'v3.0.3'
- repo: https://github.com/rbubley/mirrors-prettier
rev: 'v3.3.3'
hooks:
- id: prettier
types_or:
- javascript
- markdown
- jsx
additional_dependencies:
- prettier@3.3.3
- 'prettier-plugin-organize-imports@4.1.0'

View File

@ -1 +0,0 @@
{}

5
.prettierrc.js Normal file
View File

@ -0,0 +1,5 @@
const config = {
plugins: [require("prettier-plugin-organize-imports")],
};
module.exports = config;

View File

@ -1,67 +1,63 @@
# Install dependencies only when needed
FROM docker.io/node:22-alpine AS deps
WORKDIR /app
COPY --link package.json pnpm-lock.yaml* ./
SHELL ["/bin/ash", "-xeo", "pipefail", "-c"]
RUN apk add --no-cache libc6-compat \
&& apk add --no-cache --virtual .gyp python3 make g++ \
&& npm install -g pnpm
RUN --mount=type=cache,id=pnpm-store,target=/root/.local/share/pnpm/store pnpm fetch | grep -v "cross-device link not permitted\|Falling back to copying packages from store"
RUN --mount=type=cache,id=pnpm-store,target=/root/.local/share/pnpm/store pnpm install -r --offline
# Rebuild the source code only when needed
FROM docker.io/node:22-alpine AS builder
# =========================
# Builder Stage
# =========================
FROM node:22-slim AS builder
WORKDIR /app
# Setup
RUN mkdir config
COPY . .
ARG CI
ARG BUILDTIME
ARG VERSION
ARG REVISION
ENV CI=$CI
COPY --link --from=deps /app/node_modules ./node_modules/
COPY . .
# Install and build only outside CI
RUN if [ "$CI" != "true" ]; then \
corepack enable && corepack prepare pnpm@latest --activate && \
pnpm install --frozen-lockfile --prefer-offline && \
NEXT_TELEMETRY_DISABLED=1 \
NEXT_PUBLIC_BUILDTIME=$BUILDTIME \
NEXT_PUBLIC_VERSION=$VERSION \
NEXT_PUBLIC_REVISION=$REVISION \
pnpm run build; \
else \
echo "✅ Using prebuilt app from CI context"; \
fi
SHELL ["/bin/ash", "-xeo", "pipefail", "-c"]
RUN npm install -g pnpm \
&& pnpm run telemetry \
&& NEXT_PUBLIC_BUILDTIME=$BUILDTIME NEXT_PUBLIC_VERSION=$VERSION NEXT_PUBLIC_REVISION=$REVISION pnpm run build
# Production image, copy all the files and run next
FROM docker.io/node:22-alpine AS runner
LABEL org.opencontainers.image.title "Homepage"
LABEL org.opencontainers.image.description "A self-hosted services landing page, with docker and service integrations."
# =========================
# Runtime Stage
# =========================
FROM node:22-alpine AS runner
LABEL org.opencontainers.image.title="Homepage"
LABEL org.opencontainers.image.description="A self-hosted services landing page, with docker and service integrations."
LABEL org.opencontainers.image.url="https://github.com/gethomepage/homepage"
LABEL org.opencontainers.image.documentation='https://github.com/gethomepage/homepage/wiki'
LABEL org.opencontainers.image.source='https://github.com/gethomepage/homepage'
LABEL org.opencontainers.image.licenses='Apache-2.0'
ENV NODE_ENV=production
# Setup
WORKDIR /app
# Copy files from context (this allows the files to copy before the builder stage is done).
COPY --link --chown=1000:1000 package.json next.config.js ./
# Copy some files from context
COPY --link --chown=1000:1000 /public ./public/
# Copy files from builder
COPY --link --from=builder --chown=1000:1000 /app/.next/standalone ./
COPY --link --from=builder --chown=1000:1000 /app/.next/static/ ./.next/static/
COPY --link --chmod=755 docker-entrypoint.sh /usr/local/bin/
RUN apk add --no-cache su-exec
# Copy only necessary files from the build stage
COPY --link --from=builder --chown=1000:1000 /app/.next/standalone/ ./
COPY --link --from=builder --chown=1000:1000 /app/.next/static/ ./.next/static
RUN apk add --no-cache su-exec iputils-ping
ENV NODE_ENV=production
ENV HOSTNAME=0.0.0.0
ENV PORT=3000
EXPOSE $PORT
HEALTHCHECK --interval=10s --timeout=3s --start-period=20s \
CMD wget --no-verbose --tries=1 --spider --no-check-certificate http://127.0.0.1:$PORT/api/healthcheck || exit 1
CMD wget --no-verbose --tries=1 --spider http://127.0.0.1:$PORT/api/healthcheck || exit 1
ENTRYPOINT ["docker-entrypoint.sh"]
CMD ["node", "server.js"]

View File

@ -189,6 +189,7 @@ widget:
name: id # required, field in each item to use as the item name (left side)
label: ip_address # required, field in each item to use as the item label (right side)
limit: 5 # optional, limit the number of items to display
format: text # optional - format of the label field
target: https://example.com/server/{id} # optional, makes items clickable with template support
```

View File

@ -1,17 +0,0 @@
---
title: Hoarder
description: Hoarder Widget Configuration
---
Learn more about [Hoarder](https://hoarder.app).
Generate an API key for your user at `User Settings > API Keys`.
Allowed fields: `["bookmarks", "favorites", "archived", "highlights", "lists", "tags"]` (maximum of 4).
```yaml
widget:
type: hoarder
url: http[s]://hoarder.host.or.ip[:port]
key: hoarderapikey
```

View File

@ -51,7 +51,7 @@ You can also find a list of all available service widgets in the sidebar navigat
- [HDHomeRun](hdhomerun.md)
- [Headscale](headscale.md)
- [Healthchecks](healthchecks.md)
- [Hoarder](hoarder.md)
- [Karakeep](karakeep.md)
- [Home Assistant](homeassistant.md)
- [HomeBox](homebox.md)
- [Homebridge](homebridge.md)

View File

@ -0,0 +1,17 @@
---
title: Karakeep
description: Karakeep Widget Configuration
---
Learn more about [Karakeep](https://karakeep.app) (formerly known as Hoarder).
Generate an API key for your user at `User Settings > API Keys`.
Allowed fields: `["bookmarks", "favorites", "archived", "highlights", "lists", "tags"]` (maximum of 4).
```yaml
widget:
type: karakeep
url: http[s]://karakeep.host.or.ip[:port]
key: karakeep_api_key
```

View File

@ -74,7 +74,7 @@ nav:
- widgets/services/hdhomerun.md
- widgets/services/headscale.md
- widgets/services/healthchecks.md
- widgets/services/hoarder.md
- widgets/services/karakeep.md
- widgets/services/homeassistant.md
- widgets/services/homebox.md
- widgets/services/homebridge.md

View File

@ -1,6 +1,6 @@
{
"name": "homepage",
"version": "1.1.1",
"version": "1.1.2",
"private": true,
"scripts": {
"preinstall": "npx only-allow pnpm",
@ -19,13 +19,13 @@
"dockerode": "^4.0.4",
"follow-redirects": "^1.15.9",
"gamedig": "^5.2.0",
"i18next": "^21.10.0",
"i18next": "^24.2.3",
"js-yaml": "^4.1.0",
"json-rpc-2.0": "^1.7.0",
"luxon": "^3.5.0",
"memory-cache": "^0.2.0",
"minecraftstatuspinger": "^1.2.2",
"next": "^15.2.3",
"next": "^15.2.4",
"next-i18next": "^12.1.0",
"ping": "^0.4.4",
"pretty-bytes": "^6.1.1",
@ -36,7 +36,7 @@
"react-icons": "^5.4.0",
"recharts": "^2.15.1",
"rrule": "^2.8.1",
"swr": "^1.3.0",
"swr": "^2.3.3",
"systeminformation": "^5.25.11",
"tough-cookie": "^5.1.2",
"urbackup-server-api": "^0.8.9",
@ -47,15 +47,16 @@
"@tailwindcss/forms": "^0.5.10",
"@tailwindcss/postcss": "^4.0.9",
"eslint": "^9.21.0",
"eslint-config-next": "^15.1.7",
"eslint-config-prettier": "^10.0.2",
"eslint-config-next": "^15.2.4",
"eslint-config-prettier": "^10.1.1",
"eslint-plugin-import": "^2.31.0",
"eslint-plugin-jsx-a11y": "^6.10.2",
"eslint-plugin-prettier": "^5.2.3",
"eslint-plugin-react": "^7.37.4",
"eslint-plugin-react-hooks": "^5.1.0",
"postcss": "^8.5.2",
"postcss": "^8.5.3",
"prettier": "^3.5.2",
"prettier-plugin-organize-imports": "^4.1.0",
"tailwind-scrollbar": "^4.0.1",
"tailwindcss": "^4.0.9",
"typescript": "^5.7.3"

628
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@ -1024,7 +1024,7 @@
"bcharge":"Battery Charge",
"timeleft":"Time Left"
},
"hoarder": {
"karakeep": {
"bookmarks": "Bookmarks",
"favorites": "Favorites",
"archived": "Archived",

View File

@ -1,10 +1,10 @@
import { useRef, useEffect } from "react";
import classNames from "classnames";
import { Disclosure, Transition } from "@headlessui/react";
import { MdKeyboardArrowDown } from "react-icons/md";
import ErrorBoundary from "components/errorboundry";
import classNames from "classnames";
import List from "components/bookmarks/list";
import ErrorBoundary from "components/errorboundry";
import ResolvedIcon from "components/resolvedicon";
import { useEffect, useRef } from "react";
import { MdKeyboardArrowDown } from "react-icons/md";
export default function BookmarksGroup({
bookmarks,

View File

@ -1,7 +1,7 @@
import { useContext } from "react";
import classNames from "classnames";
import { SettingsContext } from "utils/contexts/settings";
import ResolvedIcon from "components/resolvedicon";
import { useContext } from "react";
import { SettingsContext } from "utils/contexts/settings";
export default function Item({ bookmark, iconOnly = false }) {
const description = bookmark.description ?? new URL(bookmark.href).hostname;

View File

@ -1,6 +1,6 @@
/* eslint-disable @next/next/no-img-element */
/* eslint-disable jsx-a11y/alt-text */
import { useRef, useEffect, useContext } from "react";
import { useContext, useEffect, useRef } from "react";
import { ColorContext } from "utils/contexts/color";
import themes from "utils/styles/themes";

View File

@ -1,6 +1,6 @@
import { useTranslation } from "react-i18next";
import { useEffect, useState, useRef, useCallback, useContext } from "react";
import classNames from "classnames";
import { useTranslation } from "next-i18next";
import { useCallback, useContext, useEffect, useRef, useState } from "react";
import useSWR from "swr";
import { SettingsContext } from "utils/contexts/settings";
@ -53,7 +53,7 @@ export default function QuickLaunch({ servicesAndBookmarks, searchString, setSea
const result = results[currentItemIndex];
window.open(
result.href,
newWindow ? "_blank" : result.target ?? searchProvider?.target ?? settings.target ?? "_blank",
newWindow ? "_blank" : (result.target ?? searchProvider?.target ?? settings.target ?? "_blank"),
"noreferrer",
);
}
@ -204,7 +204,8 @@ export default function QuickLaunch({ servicesAndBookmarks, searchString, setSea
return () => {
abortController.abort();
};
}, [searchString, servicesAndBookmarks, searchDescriptions, hideVisitURL, searchSuggestions, searchProvider, url, t]);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [searchString, servicesAndBookmarks, searchDescriptions, hideVisitURL, searchSuggestions, searchProvider, url]);
const [hidden, setHidden] = useState(true);
useEffect(() => {

View File

@ -1,5 +1,5 @@
import { useContext } from "react";
import Image from "next/image";
import { useContext } from "react";
import { SettingsContext } from "utils/contexts/settings";
import { ThemeContext } from "utils/contexts/theme";

View File

@ -1,7 +1,7 @@
import { Fragment } from "react";
import { Menu, Transition } from "@headlessui/react";
import { BiCog } from "react-icons/bi";
import classNames from "classnames";
import { Fragment } from "react";
import { BiCog } from "react-icons/bi";
export default function Dropdown({ options, value, setValue }) {
return (

View File

@ -1,9 +1,9 @@
import { useRef, useEffect } from "react";
import classNames from "classnames";
import { Disclosure, Transition } from "@headlessui/react";
import { MdKeyboardArrowDown } from "react-icons/md";
import List from "components/services/list";
import classNames from "classnames";
import ResolvedIcon from "components/resolvedicon";
import List from "components/services/list";
import { useEffect, useRef } from "react";
import { MdKeyboardArrowDown } from "react-icons/md";
import { columnMap } from "../../utils/layout/columns";

View File

@ -1,15 +1,15 @@
import classNames from "classnames";
import ResolvedIcon from "components/resolvedicon";
import { useContext, useState } from "react";
import { SettingsContext } from "utils/contexts/settings";
import Docker from "widgets/docker/component";
import Kubernetes from "widgets/kubernetes/component";
import { SettingsContext } from "utils/contexts/settings";
import ResolvedIcon from "components/resolvedicon";
import Status from "./status";
import Widget from "./widget";
import KubernetesStatus from "./kubernetes-status";
import Ping from "./ping";
import SiteMonitor from "./site-monitor";
import KubernetesStatus from "./kubernetes-status";
import Status from "./status";
import Widget from "./widget";
export default function Item({ service, groupName, useEqualHeights }) {
const hasLink = service.href && service.href !== "#";

View File

@ -1,5 +1,5 @@
import useSWR from "swr";
import { t } from "i18next";
import useSWR from "swr";
export default function KubernetesStatus({ service, style }) {
const podSelectorString = service.podSelector !== undefined ? `podSelector=${service.podSelector}` : "";

View File

@ -1,4 +1,4 @@
import { useTranslation } from "react-i18next";
import { useTranslation } from "next-i18next";
import useSWR from "swr";
export default function Ping({ groupName, serviceName, style }) {

View File

@ -1,4 +1,4 @@
import { useTranslation } from "react-i18next";
import { useTranslation } from "next-i18next";
import useSWR from "swr";
export default function SiteMonitor({ groupName, serviceName, style }) {

View File

@ -1,4 +1,4 @@
import { useTranslation } from "react-i18next";
import { useTranslation } from "next-i18next";
import useSWR from "swr";
export default function Status({ service, style }) {

View File

@ -1,5 +1,5 @@
import { useTranslation } from "next-i18next";
import ErrorBoundary from "components/errorboundry";
import { useTranslation } from "next-i18next";
import components from "widgets/components";

View File

@ -1,5 +1,5 @@
import { useTranslation } from "next-i18next";
import classNames from "classnames";
import { useTranslation } from "next-i18next";
export default function Block({ value, label }) {
const { t } = useTranslation();

View File

@ -3,6 +3,11 @@ import { SettingsContext } from "utils/contexts/settings";
import Error from "./error";
const ALIASED_WIDGETS = {
pialert: "netalertx",
hoarder: "karakeep",
};
export default function Container({ error = false, children, service }) {
const { settings } = useContext(SettingsContext);
@ -32,7 +37,17 @@ export default function Container({ error = false, children, service }) {
if (!field.includes(".")) {
fullField = `${type}.${field}`;
}
return fullField === child?.props?.label;
let matches = fullField === child?.props?.label;
// check if the field is an 'alias'
if (matches) {
return true;
} else if (ALIASED_WIDGETS[type]) {
matches = fullField.replace(type, ALIASED_WIDGETS[type]) === child?.props?.label;
return matches;
}
// no match
return false;
}),
);
}

View File

@ -1,4 +1,4 @@
import { useTranslation } from "react-i18next";
import { useTranslation } from "next-i18next";
import { IoAlertCircle } from "react-icons/io5";
function displayError(error) {

View File

@ -1,5 +1,5 @@
import { useContext } from "react";
import classNames from "classnames";
import { useContext } from "react";
import { TabContext } from "utils/contexts/tab";
function slugify(tabName) {

View File

@ -1,7 +1,7 @@
import { useContext, Fragment } from "react";
import { IoColorPalette } from "react-icons/io5";
import { Popover, Transition } from "@headlessui/react";
import classNames from "classnames";
import { Fragment, useContext } from "react";
import { IoColorPalette } from "react-icons/io5";
import { ColorContext } from "utils/contexts/color";
const colors = [

View File

@ -1,8 +1,8 @@
import { compareVersions, validate } from "compare-versions";
import cache from "memory-cache";
import { useTranslation } from "next-i18next";
import useSWR from "swr";
import { compareVersions, validate } from "compare-versions";
import { MdNewReleases } from "react-icons/md";
import useSWR from "swr";
const LATEST_RELEASE_CACHE_KEY = "latestRelease";

View File

@ -1,5 +1,5 @@
import { useState, useEffect } from "react";
import { useTranslation } from "next-i18next";
import { useEffect, useState } from "react";
import Container from "../widget/container";
import Raw from "../widget/raw";

View File

@ -1,9 +1,9 @@
import useSWR from "swr";
import classNames from "classnames";
import { useTranslation } from "next-i18next";
import { useContext } from "react";
import { FaMemory, FaRegClock, FaThermometerHalf } from "react-icons/fa";
import { FiCpu, FiHardDrive } from "react-icons/fi";
import { useTranslation } from "next-i18next";
import classNames from "classnames";
import useSWR from "swr";
import { SettingsContext } from "utils/contexts/settings";
import Error from "../widget/error";

View File

@ -1,8 +1,8 @@
import useSWR from "swr";
import { useTranslation } from "next-i18next";
import useSWR from "swr";
import Error from "../widget/error";
import Container from "../widget/container";
import Error from "../widget/error";
import Raw from "../widget/raw";
import Node from "./node";

View File

@ -1,7 +1,7 @@
import { useTranslation } from "next-i18next";
import { FaMemory } from "react-icons/fa";
import { FiAlertTriangle, FiCpu, FiServer } from "react-icons/fi";
import { SiKubernetes } from "react-icons/si";
import { useTranslation } from "next-i18next";
import UsageBar from "../resources/usage-bar";

View File

@ -1,7 +1,7 @@
import useSWR from "swr";
import Error from "../widget/error";
import Container from "../widget/container";
import Error from "../widget/error";
import Raw from "../widget/raw";
import Node from "./node";
@ -32,8 +32,8 @@ export default function Longhorn({ options }) {
<div className="flex flex-row self-center flex-wrap justify-between">
{data.nodes
.filter((node) => {
if (node.id === "total" && total) {
return true;
if (node.id === "total") {
return total;
}
if (!nodes) {
return false;

View File

@ -1,16 +1,16 @@
import useSWR from "swr";
import { useState } from "react";
import { WiCloudDown } from "react-icons/wi";
import { MdLocationDisabled, MdLocationSearching } from "react-icons/md";
import { useTranslation } from "next-i18next";
import { useState } from "react";
import { MdLocationDisabled, MdLocationSearching } from "react-icons/md";
import { WiCloudDown } from "react-icons/wi";
import useSWR from "swr";
import Error from "../widget/error";
import mapIcon from "../../../utils/weather/openmeteo-condition-map";
import Container from "../widget/container";
import ContainerButton from "../widget/container_button";
import WidgetIcon from "../widget/widget_icon";
import Error from "../widget/error";
import PrimaryText from "../widget/primary_text";
import SecondaryText from "../widget/secondary_text";
import mapIcon from "../../../utils/weather/openmeteo-condition-map";
import WidgetIcon from "../widget/widget_icon";
function Widget({ options }) {
const { t } = useTranslation();

View File

@ -1,16 +1,16 @@
import useSWR from "swr";
import { useState } from "react";
import { WiCloudDown } from "react-icons/wi";
import { MdLocationDisabled, MdLocationSearching } from "react-icons/md";
import { useTranslation } from "next-i18next";
import { useState } from "react";
import { MdLocationDisabled, MdLocationSearching } from "react-icons/md";
import { WiCloudDown } from "react-icons/wi";
import useSWR from "swr";
import Error from "../widget/error";
import mapIcon from "../../../utils/weather/owm-condition-map";
import Container from "../widget/container";
import ContainerButton from "../widget/container_button";
import Error from "../widget/error";
import PrimaryText from "../widget/primary_text";
import SecondaryText from "../widget/secondary_text";
import WidgetIcon from "../widget/widget_icon";
import mapIcon from "../../../utils/weather/owm-condition-map";
function Widget({ options }) {
const { t, i18n } = useTranslation();

View File

@ -1,9 +1,9 @@
import useSWR from "swr";
import { FiCpu } from "react-icons/fi";
import { useTranslation } from "next-i18next";
import { FiCpu } from "react-icons/fi";
import useSWR from "swr";
import Resource from "../widget/resource";
import Error from "../widget/error";
import Resource from "../widget/resource";
export default function Cpu({ expanded, refresh = 1500 }) {
const { t } = useTranslation();

View File

@ -1,9 +1,9 @@
import useSWR from "swr";
import { FaThermometerHalf } from "react-icons/fa";
import { useTranslation } from "next-i18next";
import { FaThermometerHalf } from "react-icons/fa";
import useSWR from "swr";
import Resource from "../widget/resource";
import Error from "../widget/error";
import Resource from "../widget/resource";
function convertToFahrenheit(t) {
return (t * 9) / 5 + 32;

View File

@ -1,9 +1,9 @@
import useSWR from "swr";
import { FiHardDrive } from "react-icons/fi";
import { useTranslation } from "next-i18next";
import { FiHardDrive } from "react-icons/fi";
import useSWR from "swr";
import Resource from "../widget/resource";
import Error from "../widget/error";
import Resource from "../widget/resource";
export default function Disk({ options, expanded, diskUnits, refresh = 1500 }) {
const { t } = useTranslation();

View File

@ -1,9 +1,9 @@
import useSWR from "swr";
import { FaMemory } from "react-icons/fa";
import { useTranslation } from "next-i18next";
import { FaMemory } from "react-icons/fa";
import useSWR from "swr";
import Resource from "../widget/resource";
import Error from "../widget/error";
import Resource from "../widget/resource";
export default function Memory({ expanded, refresh = 1500 }) {
const { t } = useTranslation();

View File

@ -1,9 +1,9 @@
import useSWR from "swr";
import { FaNetworkWired } from "react-icons/fa";
import { useTranslation } from "next-i18next";
import { FaNetworkWired } from "react-icons/fa";
import useSWR from "swr";
import Resource from "../widget/resource";
import Error from "../widget/error";
import Resource from "../widget/resource";
export default function Network({ options, refresh = 1500 }) {
const { t } = useTranslation();

View File

@ -1,12 +1,12 @@
import Container from "../widget/container";
import Raw from "../widget/raw";
import Disk from "./disk";
import Cpu from "./cpu";
import Memory from "./memory";
import CpuTemp from "./cputemp";
import Uptime from "./uptime";
import Disk from "./disk";
import Memory from "./memory";
import Network from "./network";
import Uptime from "./uptime";
export default function Resources({ options }) {
const { expanded, units, diskUnits, tempmin, tempmax } = options;

View File

@ -1,9 +1,9 @@
import useSWR from "swr";
import { FaRegClock } from "react-icons/fa";
import { useTranslation } from "next-i18next";
import { FaRegClock } from "react-icons/fa";
import useSWR from "swr";
import Resource from "../widget/resource";
import Error from "../widget/error";
import Resource from "../widget/resource";
export default function Uptime({ refresh = 1500 }) {
const { t } = useTranslation();

View File

@ -1,10 +1,10 @@
import { useState, useEffect, Fragment } from "react";
import { useTranslation } from "next-i18next";
import { FiSearch } from "react-icons/fi";
import { SiDuckduckgo, SiGoogle, SiBaidu, SiBrave } from "react-icons/si";
import { BiLogoBing } from "react-icons/bi";
import { Listbox, Transition, Combobox } from "@headlessui/react";
import { Combobox, Listbox, Transition } from "@headlessui/react";
import classNames from "classnames";
import { useTranslation } from "next-i18next";
import { Fragment, useEffect, useState } from "react";
import { BiLogoBing } from "react-icons/bi";
import { FiSearch } from "react-icons/fi";
import { SiBaidu, SiBrave, SiDuckduckgo, SiGoogle } from "react-icons/si";
import ContainerForm from "../widget/container_form";
import Raw from "../widget/raw";

View File

@ -1,13 +1,13 @@
import useSWR from "swr";
import { useState } from "react";
import { useTranslation } from "next-i18next";
import { useState } from "react";
import { FaChartLine } from "react-icons/fa6";
import useSWR from "swr";
import Error from "../widget/error";
import Container from "../widget/container";
import Error from "../widget/error";
import PrimaryText from "../widget/primary_text";
import WidgetIcon from "../widget/widget_icon";
import Raw from "../widget/raw";
import WidgetIcon from "../widget/widget_icon";
export default function Widget({ options }) {
const { t, i18n } = useTranslation();

View File

@ -1,13 +1,13 @@
import { BiError, BiWifi, BiCheckCircle, BiXCircle, BiNetworkChart } from "react-icons/bi";
import { MdSettingsEthernet } from "react-icons/md";
import { useTranslation } from "next-i18next";
import { BiCheckCircle, BiError, BiNetworkChart, BiWifi, BiXCircle } from "react-icons/bi";
import { MdSettingsEthernet } from "react-icons/md";
import { SiUbiquiti } from "react-icons/si";
import Error from "../widget/error";
import Container from "../widget/container";
import Error from "../widget/error";
import PrimaryText from "../widget/primary_text";
import Raw from "../widget/raw";
import WidgetIcon from "../widget/widget_icon";
import PrimaryText from "../widget/primary_text";
import useWidgetAPI from "utils/proxy/use-widget-api";

View File

@ -1,16 +1,16 @@
import useSWR from "swr";
import { useState } from "react";
import { WiCloudDown } from "react-icons/wi";
import { MdLocationDisabled, MdLocationSearching } from "react-icons/md";
import { useTranslation } from "next-i18next";
import { useState } from "react";
import { MdLocationDisabled, MdLocationSearching } from "react-icons/md";
import { WiCloudDown } from "react-icons/wi";
import useSWR from "swr";
import Error from "../widget/error";
import mapIcon from "../../../utils/weather/condition-map";
import Container from "../widget/container";
import ContainerButton from "../widget/container_button";
import Error from "../widget/error";
import PrimaryText from "../widget/primary_text";
import SecondaryText from "../widget/secondary_text";
import WidgetIcon from "../widget/widget_icon";
import ContainerButton from "../widget/container_button";
import mapIcon from "../../../utils/weather/condition-map";
function Widget({ options }) {
const { t, i18n } = useTranslation();

View File

@ -1,5 +1,5 @@
import dynamic from "next/dynamic";
import ErrorBoundary from "components/errorboundry";
import dynamic from "next/dynamic";
const widgetMappings = {
weatherapi: dynamic(() => import("components/widgets/weather/weather")),

View File

@ -2,10 +2,10 @@ import classNames from "classnames";
import { useContext } from "react";
import { SettingsContext } from "utils/contexts/settings";
import WidgetIcon from "./widget_icon";
import PrimaryText from "./primary_text";
import SecondaryText from "./secondary_text";
import Raw from "./raw";
import SecondaryText from "./secondary_text";
import WidgetIcon from "./widget_icon";
export function getAllClasses(options, additionalClassNames = "") {
if (options?.style?.header === "boxedWidgets") {

View File

@ -1,4 +1,4 @@
import { getAllClasses, getInnerBlock, getBottomBlock } from "./container";
import { getAllClasses, getBottomBlock, getInnerBlock } from "./container";
export default function ContainerButton({ children = [], options, additionalClassNames = "", callback }) {
return (

View File

@ -1,4 +1,4 @@
import { getAllClasses, getInnerBlock, getBottomBlock } from "./container";
import { getAllClasses, getBottomBlock, getInnerBlock } from "./container";
export default function ContainerForm({ children = [], options, additionalClassNames = "", callback }) {
return (

View File

@ -1,4 +1,4 @@
import { getAllClasses, getInnerBlock, getBottomBlock } from "./container";
import { getAllClasses, getBottomBlock, getInnerBlock } from "./container";
export default function ContainerLink({ children = [], options, additionalClassNames = "", target }) {
return (

View File

@ -1,4 +1,4 @@
import { useTranslation } from "react-i18next";
import { useTranslation } from "next-i18next";
import { BiError } from "react-icons/bi";
import Container from "./container";

View File

@ -1,8 +1,8 @@
import classNames from "classnames";
import ContainerLink from "./container_link";
import Resource from "./resource";
import Raw from "./raw";
import Resource from "./resource";
import WidgetLabel from "./widget_label";
export default function Resources({ options, children, target, additionalClassNames }) {

View File

@ -1,14 +1,14 @@
/* eslint-disable react/jsx-props-no-spreading */
import { SWRConfig } from "swr";
import { appWithTranslation } from "next-i18next";
import Head from "next/head";
import "styles/globals.css";
import "styles/theme.css";
import "styles/manrope.css";
import "styles/theme.css";
import { SWRConfig } from "swr";
import { ColorProvider } from "utils/contexts/color";
import { ThemeProvider } from "utils/contexts/theme";
import { SettingsProvider } from "utils/contexts/settings";
import { TabProvider } from "utils/contexts/tab";
import { ThemeProvider } from "utils/contexts/theme";
import nextI18nextConfig from "../../next-i18next.config";

View File

@ -1,4 +1,4 @@
import { Html, Head, Main, NextScript } from "next/document";
import { Head, Html, Main, NextScript } from "next/document";
export default function Document() {
return (

View File

@ -1,5 +1,5 @@
import path from "path";
import fs from "fs";
import path from "path";
import { CONF_DIR } from "utils/config/config";
import createLogger from "utils/logger";

View File

@ -1,6 +1,6 @@
import { join } from "path";
import { createHash } from "crypto";
import { readFileSync } from "fs";
import { join } from "path";
import checkAndCopyConfig, { CONF_DIR } from "utils/config/config";

View File

@ -53,9 +53,11 @@ export default async function handler(req, res) {
return;
}
const podNames = new Set();
let cpuLimit = 0;
let memLimit = 0;
pods.forEach((pod) => {
podNames.add(pod.metadata.name);
pod.spec.containers.forEach((container) => {
if (container?.resources?.limits?.cpu) {
cpuLimit += parseCpu(container?.resources?.limits?.cpu);
@ -66,12 +68,8 @@ export default async function handler(req, res) {
});
});
const podStatsList = await Promise.all(
pods.map(async (pod) => {
let depMem = 0;
let depCpu = 0;
const podMetrics = await metricsApi
.getPodMetrics(namespace, pod.items)
const namespaceMetrics = await metricsApi
.getPodMetrics(namespace)
.then((response) => response.items)
.catch((err) => {
// 404 generally means that the metrics have not been populated yet
@ -80,28 +78,22 @@ export default async function handler(req, res) {
}
return null;
});
if (podMetrics) {
podMetrics.forEach((metrics) => {
metrics.containers.forEach((container) => {
depMem += parseMemory(container.usage.memory);
depCpu += parseCpu(container.usage.cpu);
});
});
}
return {
mem: depMem,
cpu: depCpu,
};
}),
);
const stats = {
mem: 0,
cpu: 0,
};
podStatsList.forEach((podStat) => {
stats.mem += podStat.mem;
stats.cpu += podStat.cpu;
if (namespaceMetrics) {
const podMetrics = namespaceMetrics.filter((item) => podNames.has(item.metadata.name));
podMetrics.forEach((metrics) => {
metrics.containers.forEach((container) => {
stats.mem += parseMemory(container.usage.memory);
stats.cpu += parseCpu(container.usage.cpu);
});
});
}
stats.cpuLimit = cpuLimit;
stats.memLimit = memLimit;
stats.cpuUsage = cpuLimit ? 100 * (stats.cpu / cpuLimit) : 0;

View File

@ -1,5 +1,5 @@
import { cachedRequest } from "utils/proxy/http";
import createLogger from "utils/logger";
import { cachedRequest } from "utils/proxy/http";
const logger = createLogger("releases");

View File

@ -1,8 +1,8 @@
import { searchProviders } from "components/widgets/search/search";
import { getSettings } from "utils/config/config";
import { cachedRequest } from "utils/proxy/http";
import { widgetsFromConfig } from "utils/config/widget-helpers";
import { cachedRequest } from "utils/proxy/http";
export default async function handler(req, res) {
const { query, providerName } = req.query;

View File

@ -1,9 +1,9 @@
import { formatApiCall } from "utils/proxy/api-helpers";
import createLogger from "utils/logger";
import genericProxyHandler from "utils/proxy/handlers/generic";
import widgets from "widgets/widgets";
import calendarProxyHandler from "widgets/calendar/proxy";
import getServiceWidget from "utils/config/service-helpers";
import createLogger from "utils/logger";
import { formatApiCall } from "utils/proxy/api-helpers";
import genericProxyHandler from "utils/proxy/handlers/generic";
import calendarProxyHandler from "widgets/calendar/proxy";
import widgets from "widgets/widgets";
const logger = createLogger("servicesProxy");

View File

@ -1,6 +1,6 @@
import { httpProxy } from "utils/proxy/http";
import createLogger from "utils/logger";
import { getPrivateWidgetOptions } from "utils/config/widget-helpers";
import createLogger from "utils/logger";
import { httpProxy } from "utils/proxy/http";
const logger = createLogger("glances");

View File

@ -1,6 +1,6 @@
import { httpProxy } from "../../../utils/proxy/http";
import createLogger from "../../../utils/logger";
import { getSettings } from "../../../utils/config/config";
import createLogger from "../../../utils/logger";
import { httpProxy } from "../../../utils/proxy/http";
const logger = createLogger("longhorn");

View File

@ -1,6 +1,6 @@
import { cachedRequest } from "utils/proxy/http";
import { getSettings } from "utils/config/config";
import { getPrivateWidgetOptions } from "utils/config/widget-helpers";
import { cachedRequest } from "utils/proxy/http";
export default async function handler(req, res) {
const { latitude, longitude, units, provider, cache, lang, index } = req.query;

View File

@ -1,6 +1,6 @@
import { cachedRequest } from "utils/proxy/http";
import { getSettings } from "utils/config/config";
import createLogger from "utils/logger";
import { cachedRequest } from "utils/proxy/http";
const logger = createLogger("stocks");

View File

@ -1,6 +1,6 @@
import { cachedRequest } from "utils/proxy/http";
import { getSettings } from "utils/config/config";
import { getPrivateWidgetOptions } from "utils/config/widget-helpers";
import { cachedRequest } from "utils/proxy/http";
export default async function handler(req, res) {
const { latitude, longitude, provider, cache, lang, index } = req.query;

View File

@ -1,31 +1,31 @@
/* eslint-disable react/no-array-index-key */
import useSWR, { SWRConfig } from "swr";
import Head from "next/head";
import Script from "next/script";
import dynamic from "next/dynamic";
import classNames from "classnames";
import { useTranslation } from "next-i18next";
import { useEffect, useContext, useState, useMemo } from "react";
import { BiError } from "react-icons/bi";
import { serverSideTranslations } from "next-i18next/serverSideTranslations";
import { useRouter } from "next/router";
import Tab, { slugifyAndEncode } from "components/tab";
import ServicesGroup from "components/services/group";
import BookmarksGroup from "components/bookmarks/group";
import Widget from "components/widgets/widget";
import Revalidate from "components/toggles/revalidate";
import { ColorContext } from "utils/contexts/color";
import { ThemeContext } from "utils/contexts/theme";
import { SettingsContext } from "utils/contexts/settings";
import { TabContext } from "utils/contexts/tab";
import ErrorBoundary from "components/errorboundry";
import QuickLaunch from "components/quicklaunch";
import ServicesGroup from "components/services/group";
import Tab, { slugifyAndEncode } from "components/tab";
import Revalidate from "components/toggles/revalidate";
import Widget from "components/widgets/widget";
import { useTranslation } from "next-i18next";
import { serverSideTranslations } from "next-i18next/serverSideTranslations";
import dynamic from "next/dynamic";
import Head from "next/head";
import { useRouter } from "next/router";
import Script from "next/script";
import { useContext, useEffect, useMemo, useState } from "react";
import { BiError } from "react-icons/bi";
import useSWR, { SWRConfig } from "swr";
import { ColorContext } from "utils/contexts/color";
import { SettingsContext } from "utils/contexts/settings";
import { TabContext } from "utils/contexts/tab";
import { ThemeContext } from "utils/contexts/theme";
import { bookmarksResponse, servicesResponse, widgetsResponse } from "utils/config/api-response";
import themes from "utils/styles/themes";
import { getSettings } from "utils/config/config";
import useWindowFocus from "utils/hooks/window-focus";
import createLogger from "utils/logger";
import themes from "utils/styles/themes";
const ThemeToggle = dynamic(() => import("components/toggles/theme"), {
ssr: false,

View File

@ -4,13 +4,13 @@ import path from "path";
import yaml from "js-yaml";
import checkAndCopyConfig, { getSettings, substituteEnvironmentVars, CONF_DIR } from "utils/config/config";
import checkAndCopyConfig, { CONF_DIR, getSettings, substituteEnvironmentVars } from "utils/config/config";
import {
cleanServiceGroups,
findGroupByName,
servicesFromConfig,
servicesFromDocker,
cleanServiceGroups,
servicesFromKubernetes,
findGroupByName,
} from "utils/config/service-helpers";
import { cleanWidgetGroups, widgetsFromConfig } from "utils/config/widget-helpers";

View File

@ -1,9 +1,9 @@
/* eslint-disable no-console */
import { join } from "path";
import { copyFileSync, existsSync, mkdirSync, readFileSync } from "fs";
import { join } from "path";
import cache from "memory-cache";
import yaml from "js-yaml";
import cache from "memory-cache";
const cacheKey = "homepageEnvironmentVariables";
const homepageVarPrefix = "HOMEPAGE_VAR_";

View File

@ -1,5 +1,5 @@
import path from "path";
import { readFileSync } from "fs";
import path from "path";
import yaml from "js-yaml";

View File

@ -1,8 +1,8 @@
import path from "path";
import { readFileSync } from "fs";
import path from "path";
import { ApiextensionsV1Api, KubeConfig } from "@kubernetes/client-node";
import yaml from "js-yaml";
import { KubeConfig, ApiextensionsV1Api } from "@kubernetes/client-node";
import checkAndCopyConfig, { CONF_DIR, substituteEnvironmentVars } from "utils/config/config";

View File

@ -1,15 +1,15 @@
import { promises as fs } from "fs";
import path from "path";
import yaml from "js-yaml";
import Docker from "dockerode";
import yaml from "js-yaml";
import createLogger from "utils/logger";
import checkAndCopyConfig, { CONF_DIR, getSettings, substituteEnvironmentVars } from "utils/config/config";
import getDockerArguments from "utils/config/docker";
import kubernetes from "utils/kubernetes/export";
import { getKubeConfig } from "utils/config/kubernetes";
import * as shvl from "utils/config/shvl";
import kubernetes from "utils/kubernetes/export";
import createLogger from "utils/logger";
const logger = createLogger("service-helpers");
@ -362,6 +362,9 @@ export function cleanServiceGroups(groups) {
// proxmox
node,
// proxmoxbackupserver
datastore,
// speedtest
bitratePrecision,
@ -437,6 +440,9 @@ export function cleanServiceGroups(groups) {
if (type === "proxmox") {
if (node) widget.node = node;
}
if (type === "proxmoxbackupserver") {
if (datastore) widget.datastore = datastore;
}
if (type === "kubernetes") {
if (namespace) widget.namespace = namespace;
if (app) widget.app = app;

View File

@ -1,4 +1,4 @@
import { createContext, useState, useEffect, useMemo } from "react";
import { createContext, useEffect, useMemo, useState } from "react";
let lastColor = false;

View File

@ -1,4 +1,4 @@
import { createContext, useState, useMemo } from "react";
import { createContext, useMemo, useState } from "react";
export const SettingsContext = createContext();

View File

@ -1,4 +1,4 @@
import { createContext, useState, useMemo } from "react";
import { createContext, useMemo, useState } from "react";
export const TabContext = createContext();

View File

@ -1,4 +1,4 @@
import { createContext, useState, useEffect, useMemo } from "react";
import { createContext, useEffect, useMemo, useState } from "react";
const getInitialTheme = () => {
if (typeof window !== "undefined" && window.localStorage) {

View File

@ -1,4 +1,4 @@
import { useState, useEffect } from "react";
import { useEffect, useState } from "react";
const hasFocus = () => typeof document !== "undefined" && document.hasFocus();

View File

@ -1,7 +1,7 @@
import listIngress from "utils/kubernetes/ingress-list";
import listTraefikIngress from "utils/kubernetes/traefik-list";
import listHttpRoute from "utils/kubernetes/httproute-list";
import { isDiscoverable, constructedServiceFromResource } from "utils/kubernetes/resource-helpers";
import listIngress from "utils/kubernetes/ingress-list";
import { constructedServiceFromResource, isDiscoverable } from "utils/kubernetes/resource-helpers";
import listTraefikIngress from "utils/kubernetes/traefik-list";
const kubernetes = {
listIngress,

View File

@ -1,6 +1,6 @@
import { NetworkingV1Api } from "@kubernetes/client-node";
import { getKubernetes, getKubeConfig } from "utils/config/kubernetes";
import { getKubeConfig, getKubernetes } from "utils/config/kubernetes";
import createLogger from "utils/logger";
const logger = createLogger("ingress-list");

View File

@ -1,15 +1,15 @@
import { CustomObjectsApi } from "@kubernetes/client-node";
import { substituteEnvironmentVars } from "utils/config/config";
import {
getKubeConfig,
ANNOTATION_BASE,
ANNOTATION_WIDGET_BASE,
getKubeConfig,
HTTPROUTE_API_GROUP,
HTTPROUTE_API_VERSION,
} from "utils/config/kubernetes";
import { substituteEnvironmentVars } from "utils/config/config";
import createLogger from "utils/logger";
import * as shvl from "utils/config/shvl";
import createLogger from "utils/logger";
const logger = createLogger("resource-helpers");
const kc = getKubeConfig();

View File

@ -1,6 +1,6 @@
import { CustomObjectsApi } from "@kubernetes/client-node";
import { getKubernetes, getKubeConfig, checkCRD, ANNOTATION_BASE } from "utils/config/kubernetes";
import { ANNOTATION_BASE, checkCRD, getKubeConfig, getKubernetes } from "utils/config/kubernetes";
import createLogger from "utils/logger";
const logger = createLogger("traefik-list");

View File

@ -1,9 +1,9 @@
import getServiceWidget from "utils/config/service-helpers";
import { formatApiCall, sanitizeErrorURL } from "utils/proxy/api-helpers";
import validateWidgetData from "utils/proxy/validate-widget-data";
import { httpProxy } from "utils/proxy/http";
import createLogger from "utils/logger";
import { getSettings } from "utils/config/config";
import getServiceWidget from "utils/config/service-helpers";
import createLogger from "utils/logger";
import { formatApiCall, sanitizeErrorURL } from "utils/proxy/api-helpers";
import { httpProxy } from "utils/proxy/http";
import validateWidgetData from "utils/proxy/validate-widget-data";
import widgets from "widgets/widgets";
const logger = createLogger("credentialedProxyHandler");
@ -42,6 +42,7 @@ export default async function credentialedProxyHandler(req, res, map) {
"ghostfolio",
"headscale",
"hoarder",
"karakeep",
"linkwarden",
"mealie",
"netalertx",

View File

@ -1,8 +1,8 @@
import getServiceWidget from "utils/config/service-helpers";
import { formatApiCall, sanitizeErrorURL } from "utils/proxy/api-helpers";
import validateWidgetData from "utils/proxy/validate-widget-data";
import { httpProxy } from "utils/proxy/http";
import createLogger from "utils/logger";
import { formatApiCall, sanitizeErrorURL } from "utils/proxy/api-helpers";
import { httpProxy } from "utils/proxy/http";
import validateWidgetData from "utils/proxy/validate-widget-data";
import widgets from "widgets/widgets";
const logger = createLogger("genericProxyHandler");

View File

@ -1,9 +1,9 @@
import { JSONRPCClient, JSONRPCErrorException } from "json-rpc-2.0";
import { formatApiCall } from "utils/proxy/api-helpers";
import { httpProxy } from "utils/proxy/http";
import getServiceWidget from "utils/config/service-helpers";
import createLogger from "utils/logger";
import { formatApiCall } from "utils/proxy/api-helpers";
import { httpProxy } from "utils/proxy/http";
import widgets from "widgets/widgets";
const logger = createLogger("jsonrpcProxyHandler");

View File

@ -1,9 +1,9 @@
import cache from "memory-cache";
import getServiceWidget from "utils/config/service-helpers";
import createLogger from "utils/logger";
import { asJson, formatApiCall } from "utils/proxy/api-helpers";
import { httpProxy } from "utils/proxy/http";
import createLogger from "utils/logger";
import widgets from "widgets/widgets";
const INFO_ENDPOINT = "{url}/webapi/query.cgi?api=SYNO.API.Info&version=1&method=query";

View File

@ -5,8 +5,8 @@ import { createUnzip, constants as zlibConstants } from "node:zlib";
import { http, https } from "follow-redirects";
import cache from "memory-cache";
import { addCookieToJar, setCookieHeader } from "./cookie-jar";
import { sanitizeErrorURL } from "./api-helpers";
import { addCookieToJar, setCookieHeader } from "./cookie-jar";
import createLogger from "utils/logger";

View File

@ -1,6 +1,6 @@
/* eslint-disable no-console */
import widgets from "widgets/widgets";
import createLogger from "utils/logger";
import widgets from "widgets/widgets";
const logger = createLogger("validateWidgetData");

View File

@ -1,6 +1,6 @@
import { useTranslation } from "next-i18next";
import Container from "components/services/widget/container";
import Block from "components/services/widget/block";
import Container from "components/services/widget/container";
import { useTranslation } from "next-i18next";
import useWidgetAPI from "utils/proxy/use-widget-api";

View File

@ -1,5 +1,5 @@
import Container from "components/services/widget/container";
import Block from "components/services/widget/block";
import Container from "components/services/widget/container";
import useWidgetAPI from "utils/proxy/use-widget-api";

View File

@ -1,5 +1,5 @@
import net from "node:net";
import { Buffer } from "node:buffer";
import net from "node:net";
import getServiceWidget from "utils/config/service-helpers";
import createLogger from "utils/logger";

View File

@ -1,5 +1,5 @@
import Container from "components/services/widget/container";
import Block from "components/services/widget/block";
import Container from "components/services/widget/container";
import useWidgetAPI from "utils/proxy/use-widget-api";

View File

@ -1,6 +1,6 @@
import { useTranslation } from "next-i18next";
import Container from "components/services/widget/container";
import Block from "components/services/widget/block";
import Container from "components/services/widget/container";
import { useTranslation } from "next-i18next";
import useWidgetAPI from "utils/proxy/use-widget-api";

View File

@ -1,6 +1,6 @@
import { useTranslation } from "next-i18next";
import Container from "components/services/widget/container";
import Block from "components/services/widget/block";
import Container from "components/services/widget/container";
import { useTranslation } from "next-i18next";
import useWidgetAPI from "utils/proxy/use-widget-api";

View File

@ -1,7 +1,7 @@
import { httpProxy } from "utils/proxy/http";
import { formatApiCall } from "utils/proxy/api-helpers";
import getServiceWidget from "utils/config/service-helpers";
import createLogger from "utils/logger";
import { formatApiCall } from "utils/proxy/api-helpers";
import { httpProxy } from "utils/proxy/http";
import widgets from "widgets/widgets";
const proxyName = "audiobookshelfProxyHandler";

View File

@ -1,6 +1,6 @@
import { useTranslation } from "next-i18next";
import Container from "components/services/widget/container";
import Block from "components/services/widget/block";
import Container from "components/services/widget/container";
import { useTranslation } from "next-i18next";
import useWidgetAPI from "utils/proxy/use-widget-api";

Some files were not shown because too many files have changed in this diff Show More