Compare commits

..

20 Commits

Author SHA1 Message Date
shamoon
794ec127cd Enhancement: quicklaunch fill search suggestion on arrowright (#4256)
Some checks failed
Docker / Linting Checks (push) Has been cancelled
Docker / Docker Build & Push (push) Has been cancelled
2024-11-06 10:24:09 -08:00
shamoon
912ae0adfc Feature: Beszel service widget (#4251)
Some checks are pending
Docker / Linting Checks (push) Waiting to run
Docker / Docker Build & Push (push) Blocked by required conditions
2024-11-05 12:48:43 -08:00
shamoon
7c3dcf20ef Create reaction-comments.yml 2024-11-05 11:11:01 -08:00
erelender
c12a5c01f6 Feature: Headscale Service Widget (#4247) 2024-11-05 09:02:33 -08:00
dependabot[bot]
6fd2b6b6dc Chore(deps-dev): Bump eslint-plugin-import from 2.30.0 to 2.31.0 (#4236)
Some checks failed
Docker / Linting Checks (push) Has been cancelled
Docker / Docker Build & Push (push) Has been cancelled
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-01 09:38:19 -07:00
dependabot[bot]
bf0a766302 Chore(deps-dev): Bump typescript from 5.6.2 to 5.6.3 (#4234)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-01 09:28:10 -07:00
dependabot[bot]
be4da9d010 Chore(deps): Bump urbackup-server-api from 0.52.0 to 0.52.1 (#4233)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-01 09:25:47 -07:00
dependabot[bot]
b7ca6244dd Chore(deps-dev): Bump tailwindcss from 3.4.13 to 3.4.14 (#4232)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-01 09:25:25 -07:00
shamoon
e6cf86ed4a Enhancement: use duration for audiobookshelf tottal, refactor uptime (#4229)
Some checks are pending
Docker / Linting Checks (push) Waiting to run
Docker / Docker Build & Push (push) Blocked by required conditions
2024-10-31 22:09:23 -07:00
shamoon
3736c1fcab Fix: use same unit default for openmeteo widget and api (#4227)
Some checks are pending
Docker / Linting Checks (push) Waiting to run
Docker / Docker Build & Push (push) Blocked by required conditions
2024-10-31 12:20:08 -07:00
Yordis Prieto
3af86ffebb Fix: text overflowing in bookmarks (#4217)
Some checks failed
Docker / Linting Checks (push) Has been cancelled
Docker / Docker Build & Push (push) Has been cancelled
Co-Authored-By: shamoon <4887959+shamoon@users.noreply.github.com>
2024-10-29 21:18:28 -07:00
shamoon
0aea6a6c3f Fix: pyload widget - encode proxy params (#4210)
Some checks are pending
Docker / Linting Checks (push) Waiting to run
Docker / Docker Build & Push (push) Blocked by required conditions
2024-10-28 15:37:18 -07:00
shamoon
261c907f52 Documentation: add correct pihole v6 password info 2024-10-28 12:27:11 -07:00
Konrad Jasiński
2a6debbc79 Documentation: Typo in LubeLogger widget documentation (#4205) 2024-10-28 07:58:24 -07:00
shamoon
e9a31bafab Update PR guidelines 2024-10-27 20:16:32 -07:00
Mark
bf2efce74d Chore: filter Radarr movie response (#4199)
Some checks failed
Docker / Linting Checks (push) Has been cancelled
Docker / Docker Build & Push (push) Has been cancelled
Co-authored-by: shamoon <4887959+shamoon@users.noreply.github.com>
2024-10-26 20:24:46 -07:00
Niklas Schäffer
7cbba1ff90 Fix: remove deprecated meta tag (#4191)
Some checks failed
Docker / Linting Checks (push) Has been cancelled
Docker / Docker Build & Push (push) Has been cancelled
2024-10-25 03:08:39 -07:00
shamoon
c347677402 Remove a random commented out line
Some checks failed
Docker / Linting Checks (push) Has been cancelled
Docker / Docker Build & Push (push) Has been cancelled
2024-10-16 16:14:17 -07:00
shamoon
fd75f22e16 Merge branch 'main' into dev
Some checks are pending
Docker / Linting Checks (push) Waiting to run
Docker / Docker Build & Push (push) Blocked by required conditions
2024-10-16 07:58:21 -07:00
shamoon
aac573a48d Enhancement: npm widget support ≥ v2.12 (#4140) 2024-10-16 07:57:35 -07:00
41 changed files with 502 additions and 141 deletions

20
.github/workflows/reaction-comments.yml vendored Normal file
View File

@@ -0,0 +1,20 @@
name: 'Reaction Comments'
on:
issue_comment:
types: [created, edited]
pull_request_review_comment:
types: [created, edited]
schedule:
- cron: '0 0 * * *'
permissions:
actions: write
issues: write
pull-requests: write
jobs:
action:
runs-on: ubuntu-latest
steps:
- uses: dessant/reaction-comments@v4

View File

@@ -48,15 +48,14 @@ self-hosted / open-source alternative, we ask that any widgets, etc. are develop
## New Feature Guidelines
- New features should be linked to an existing feature request with at least 10 'up-votes'. The purpose of this requirement is to avoid the addition (and maintenance) of features that might only benefit a small number of users.
- If you have ideas for a larger feature, please open a discussion first.
- Please note that though it is a requirement, a discussion with 10 'up-votes' in no way guarantees that a PR will be merged.
- New features should usually be linked to an existing feature request. The purpose of this requirement is to avoid the addition (and maintenance) of features that might only benefit a small number of users.
- If you have ideas for a larger feature you may want to open a discussion first.
## Service Widget Guidelines
To ensure cohesiveness of various widgets, the following should be used as a guide for developing new widgets:
- Please only submit widgets that have been requested and have at least 10 'up-votes'. The purpose of this requirement is to avoid the addition (and maintenance) of service widgets that might only benefit a small number of users.
- Please only submit widgets that target a feature request discussion with at least 10 'up-votes'. The purpose of this requirement is to avoid the addition (and maintenance) of service widgets that might only benefit a small number of users.
- Note that we reserve the right to decline widgets for projects that are very young (eg < ~1y) or those with a small reach (eg low GitHub stars). Again, this is in an effort to keep overall widget maintenance under control.
- Widgets should be only one row of blocks
- Widgets should be no more than 4 blocks wide and generally conform to the styling / design choices of other widgets

View File

@@ -71,7 +71,7 @@ Homepage provides a set of common translations that you can use in your widgets.
| `common.ms` | `1,000 ms` | Format a number in milliseconds. |
| `common.date` | `2024-01-01` | Format a date. |
| `common.relativeDate` | `1 day ago` | Format a relative date. |
| `common.uptime` | `1 day, 1 hour` | Format an uptime. |
| `common.duration` | `1 day, 1 hour` | Format an duration. |
### Text

View File

@@ -0,0 +1,20 @@
---
title: Beszel
description: Beszel Widget Configuration
---
Learn more about [Beszel]()
The widget has two modes, a single system with detailed info if `systemId` is provided, or an overview of all systems if `systemId` is not provided.
Allowed fields for 'overview' mode: `["systems", "up"]`
Allowed fields for a single system: `["name", "status", "updated", "cpu", "memory", "disk", "network"]`
```yaml
widget:
type: beszel
url: http://beszel.host.or.ip
username: username # email
password: password
systemId: systemId # optional
```

View File

@@ -0,0 +1,19 @@
---
title: Headscale
description: Headscale Widget Configuration
---
Learn more about [Headscale](https://headscale.net/).
You will need to generate an API access token from the [command line](https://headscale.net/ref/remote-cli/#create-an-api-key) using `headscale apikeys create` command.
To find your node ID, you can use `headscale nodes list` command.
Allowed fields: `["name", "address", "last_seen", "status"]`.
```yaml
widget:
type: headscale
nodeId: nodeid
key: headscaleapiaccesstoken
```

View File

@@ -14,6 +14,7 @@ You can also find a list of all available service widgets in the sidebar navigat
- [Autobrr](autobrr.md)
- [Azure DevOps](azuredevops.md)
- [Bazarr](bazarr.md)
- [Beszel](beszel.md)
- [Caddy](caddy.md)
- [Calendar](calendar.md)
- [Calibre-Web](calibre-web.md)
@@ -44,6 +45,7 @@ You can also find a list of all available service widgets in the sidebar navigat
- [Gotify](gotify.md)
- [Grafana](grafana.md)
- [HDHomeRun](hdhomerun.md)
- [Headscale](headscale.md)
- [Healthchecks](healthchecks.md)
- [Home Assistant](homeassistant.md)
- [HomeBox](homebox.md)

View File

@@ -8,7 +8,7 @@ Learn more about [LubeLogger](https://github.com/hargata/lubelog) (v1.3.7 or hig
The widget comes in two 'flavors', one shows data for all vehicles or for just a specific vehicle with the `vehicleID` parameter.
Allowed fields: `["vehicles", "serviceRecords", "reminders"]`.
For the single-vehicle version: `["vehicle", "serviceRecords", "reminders", "nextReminder"]
For the single-vehicle version: `["vehicle", "serviceRecords", "reminders", "nextReminder"]`.
```yaml
widget:

View File

@@ -14,5 +14,5 @@ widget:
type: pihole
url: http://pi.hole.or.ip
version: 6 # required if running v6 or higher, defaults to 5
key: yourpiholeapikey # optional
key: yourpiholeapikey # optional, in v6 can be your password or app password
```

View File

@@ -37,6 +37,7 @@ nav:
- widgets/services/autobrr.md
- widgets/services/azuredevops.md
- widgets/services/bazarr.md
- widgets/services/beszel.md
- widgets/services/caddy.md
- widgets/services/calendar.md
- widgets/services/calibre-web.md
@@ -67,6 +68,7 @@ nav:
- widgets/services/gotify.md
- widgets/services/grafana.md
- widgets/services/hdhomerun.md
- widgets/services/headscale.md
- widgets/services/healthchecks.md
- widgets/services/homeassistant.md
- widgets/services/homebox.md

View File

@@ -84,12 +84,12 @@ function prettyBytes(number, options) {
return `${prefix + numberString} ${unit}`;
}
function uptime(uptimeInSeconds, i18next) {
const mo = Math.floor(uptimeInSeconds / (3600 * 24 * 31));
const d = Math.floor((uptimeInSeconds % (3600 * 24 * 31)) / (3600 * 24));
const h = Math.floor((uptimeInSeconds % (3600 * 24)) / 3600);
const m = Math.floor((uptimeInSeconds % 3600) / 60);
const s = Math.floor(uptimeInSeconds % 60);
function duration(durationInSeconds, i18next) {
const mo = Math.floor(durationInSeconds / (3600 * 24 * 31));
const d = Math.floor((durationInSeconds % (3600 * 24 * 31)) / (3600 * 24));
const h = Math.floor((durationInSeconds % (3600 * 24)) / 3600);
const m = Math.floor((durationInSeconds % 3600) / 60);
const s = Math.floor(durationInSeconds % 60);
const moDisplay = mo > 0 ? mo + i18next.t("common.months") : "";
const dDisplay = d > 0 ? d + i18next.t("common.days") : "";
@@ -156,7 +156,7 @@ module.exports = {
i18next.services.formatter.add("relativeDate", (value, lng, options) =>
relativeDate(new Date(value), new Intl.RelativeTimeFormat(lng, { ...options })),
);
i18next.services.formatter.add("uptime", (value, lng) => uptime(value, i18next));
i18next.services.formatter.add("duration", (value, lng) => duration(value, i18next));
},
type: "3rdParty",
},

46
package-lock.json generated
View File

@@ -36,7 +36,7 @@
"swr": "^1.3.0",
"systeminformation": "^5.23.2",
"tough-cookie": "^4.1.3",
"urbackup-server-api": "^0.52.0",
"urbackup-server-api": "^0.52.1",
"winston": "^3.11.0",
"xml-js": "^1.6.11"
},
@@ -47,7 +47,7 @@
"eslint-config-airbnb": "^19.0.4",
"eslint-config-next": "^14.2.3",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-import": "^2.29.1",
"eslint-plugin-import": "^2.31.0",
"eslint-plugin-jsx-a11y": "^6.8.0",
"eslint-plugin-prettier": "^5.2.1",
"eslint-plugin-react": "^7.37.1",
@@ -55,8 +55,8 @@
"postcss": "^8.4.47",
"prettier": "^3.2.5",
"tailwind-scrollbar": "^3.0.5",
"tailwindcss": "^3.4.13",
"typescript": "^5.6.2"
"tailwindcss": "^3.4.14",
"typescript": "^5.6.3"
},
"optionalDependencies": {
"osx-temperature-sensor": "^1.0.8"
@@ -3135,11 +3135,10 @@
}
},
"node_modules/eslint-module-utils": {
"version": "2.9.0",
"resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.9.0.tgz",
"integrity": "sha512-McVbYmwA3NEKwRQY5g4aWMdcZE5xZxV8i8l7CqJSrameuGSQJtSWaL/LxTEzSKKaCcOhlpDR8XEfYXWPrdo/ZQ==",
"version": "2.12.0",
"resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.12.0.tgz",
"integrity": "sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg==",
"dev": true,
"license": "MIT",
"dependencies": {
"debug": "^3.2.7"
},
@@ -3163,11 +3162,10 @@
}
},
"node_modules/eslint-plugin-import": {
"version": "2.30.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.30.0.tgz",
"integrity": "sha512-/mHNE9jINJfiD2EKkg1BKyPyUk4zdnT54YgbOgfjSakWT5oyX/qQLVNTkehyfpcMxZXMy1zyonZ2v7hZTX43Yw==",
"version": "2.31.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.31.0.tgz",
"integrity": "sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A==",
"dev": true,
"license": "MIT",
"dependencies": {
"@rtsao/scc": "^1.1.0",
"array-includes": "^3.1.8",
@@ -3177,7 +3175,7 @@
"debug": "^3.2.7",
"doctrine": "^2.1.0",
"eslint-import-resolver-node": "^0.3.9",
"eslint-module-utils": "^2.9.0",
"eslint-module-utils": "^2.12.0",
"hasown": "^2.0.2",
"is-core-module": "^2.15.1",
"is-glob": "^4.0.3",
@@ -3186,13 +3184,14 @@
"object.groupby": "^1.0.3",
"object.values": "^1.2.0",
"semver": "^6.3.1",
"string.prototype.trimend": "^1.0.8",
"tsconfig-paths": "^3.15.0"
},
"engines": {
"node": ">=4"
},
"peerDependencies": {
"eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8"
"eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9"
}
},
"node_modules/eslint-plugin-import/node_modules/debug": {
@@ -7713,9 +7712,9 @@
}
},
"node_modules/tailwindcss": {
"version": "3.4.13",
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.13.tgz",
"integrity": "sha512-KqjHOJKogOUt5Bs752ykCeiwvi0fKVkr5oqsFNt/8px/tA8scFPIlkygsf6jXrfCqGHz7VflA6+yytWuM+XhFw==",
"version": "3.4.14",
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.14.tgz",
"integrity": "sha512-IcSvOcTRcUtQQ7ILQL5quRDg7Xs93PdJEk1ZLbhhvJc7uj/OAhYOnruEiwnGgBvUtaUAJ8/mhSw1o8L2jCiENA==",
"dev": true,
"dependencies": {
"@alloc/quick-lru": "^5.2.0",
@@ -8102,9 +8101,9 @@
}
},
"node_modules/typescript": {
"version": "5.6.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.2.tgz",
"integrity": "sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw==",
"version": "5.6.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz",
"integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==",
"dev": true,
"bin": {
"tsc": "bin/tsc",
@@ -8186,10 +8185,9 @@
}
},
"node_modules/urbackup-server-api": {
"version": "0.52.0",
"resolved": "https://registry.npmjs.org/urbackup-server-api/-/urbackup-server-api-0.52.0.tgz",
"integrity": "sha512-KfroCFZEWCuCkWye1F1JwI2fkO1za/Mf1a8TNGTujzxU0ZGzDqhA1zCOcvV97q7nH1TKFNpw5tMZ06fSCKv2UA==",
"license": "MIT",
"version": "0.52.1",
"resolved": "https://registry.npmjs.org/urbackup-server-api/-/urbackup-server-api-0.52.1.tgz",
"integrity": "sha512-gAxF9MdXxnceqUr/1Uj2LuGZQb/bvZ3Ply9zH/UTSWGkwKL5C0qMPrBvKRyTHbPMG/NBuHF6BzavkF7GNvOLew==",
"dependencies": {
"async-mutex": "^0.5.0",
"node-fetch": "^2.7.0"

View File

@@ -38,7 +38,7 @@
"swr": "^1.3.0",
"systeminformation": "^5.23.2",
"tough-cookie": "^4.1.3",
"urbackup-server-api": "^0.52.0",
"urbackup-server-api": "^0.52.1",
"winston": "^3.11.0",
"xml-js": "^1.6.11"
},
@@ -49,7 +49,7 @@
"eslint-config-airbnb": "^19.0.4",
"eslint-config-next": "^14.2.3",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-import": "^2.29.1",
"eslint-plugin-import": "^2.31.0",
"eslint-plugin-jsx-a11y": "^6.8.0",
"eslint-plugin-prettier": "^5.2.1",
"eslint-plugin-react": "^7.37.1",
@@ -57,8 +57,8 @@
"postcss": "^8.4.47",
"prettier": "^3.2.5",
"tailwind-scrollbar": "^3.0.5",
"tailwindcss": "^3.4.13",
"typescript": "^5.6.2"
"tailwindcss": "^3.4.14",
"typescript": "^5.6.3"
},
"optionalDependencies": {
"osx-temperature-sensor": "^1.0.8"

172
pnpm-lock.yaml generated
View File

@@ -93,8 +93,8 @@ importers:
specifier: ^4.1.3
version: 4.1.4
urbackup-server-api:
specifier: ^0.52.0
version: 0.52.0
specifier: ^0.52.1
version: 0.52.1
winston:
specifier: ^3.11.0
version: 3.14.2
@@ -108,7 +108,7 @@ importers:
devDependencies:
'@tailwindcss/forms':
specifier: ^0.5.8
version: 0.5.9(tailwindcss@3.4.13)
version: 0.5.9(tailwindcss@3.4.14)
autoprefixer:
specifier: ^10.4.20
version: 10.4.20(postcss@8.4.47)
@@ -117,16 +117,16 @@ importers:
version: 8.57.1
eslint-config-airbnb:
specifier: ^19.0.4
version: 19.0.4(eslint-plugin-import@2.30.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.2))(eslint@8.57.1))(eslint-plugin-jsx-a11y@6.10.0(eslint@8.57.1))(eslint-plugin-react-hooks@4.6.2(eslint@8.57.1))(eslint-plugin-react@7.37.1(eslint@8.57.1))(eslint@8.57.1)
version: 19.0.4(eslint-plugin-import@2.31.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1))(eslint-plugin-jsx-a11y@6.10.0(eslint@8.57.1))(eslint-plugin-react-hooks@4.6.2(eslint@8.57.1))(eslint-plugin-react@7.37.1(eslint@8.57.1))(eslint@8.57.1)
eslint-config-next:
specifier: ^14.2.3
version: 14.2.8(eslint@8.57.1)(typescript@5.6.2)
version: 14.2.8(eslint@8.57.1)(typescript@5.6.3)
eslint-config-prettier:
specifier: ^9.1.0
version: 9.1.0(eslint@8.57.1)
eslint-plugin-import:
specifier: ^2.29.1
version: 2.30.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1)
specifier: ^2.31.0
version: 2.31.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1)
eslint-plugin-jsx-a11y:
specifier: ^6.8.0
version: 6.10.0(eslint@8.57.1)
@@ -147,13 +147,13 @@ importers:
version: 3.3.3
tailwind-scrollbar:
specifier: ^3.0.5
version: 3.1.0(tailwindcss@3.4.13)
version: 3.1.0(tailwindcss@3.4.14)
tailwindcss:
specifier: ^3.4.13
version: 3.4.13
specifier: ^3.4.14
version: 3.4.14
typescript:
specifier: ^5.6.2
version: 5.6.2
specifier: ^5.6.3
version: 5.6.3
packages:
@@ -1077,6 +1077,27 @@ packages:
eslint-plugin-import-x:
optional: true
eslint-module-utils@2.12.0:
resolution: {integrity: sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg==}
engines: {node: '>=4'}
peerDependencies:
'@typescript-eslint/parser': '*'
eslint: '*'
eslint-import-resolver-node: '*'
eslint-import-resolver-typescript: '*'
eslint-import-resolver-webpack: '*'
peerDependenciesMeta:
'@typescript-eslint/parser':
optional: true
eslint:
optional: true
eslint-import-resolver-node:
optional: true
eslint-import-resolver-typescript:
optional: true
eslint-import-resolver-webpack:
optional: true
eslint-module-utils@2.9.0:
resolution: {integrity: sha512-McVbYmwA3NEKwRQY5g4aWMdcZE5xZxV8i8l7CqJSrameuGSQJtSWaL/LxTEzSKKaCcOhlpDR8XEfYXWPrdo/ZQ==}
engines: {node: '>=4'}
@@ -1098,12 +1119,12 @@ packages:
eslint-import-resolver-webpack:
optional: true
eslint-plugin-import@2.30.0:
resolution: {integrity: sha512-/mHNE9jINJfiD2EKkg1BKyPyUk4zdnT54YgbOgfjSakWT5oyX/qQLVNTkehyfpcMxZXMy1zyonZ2v7hZTX43Yw==}
eslint-plugin-import@2.31.0:
resolution: {integrity: sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A==}
engines: {node: '>=4'}
peerDependencies:
'@typescript-eslint/parser': '*'
eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8
eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9
peerDependenciesMeta:
'@typescript-eslint/parser':
optional: true
@@ -1151,6 +1172,7 @@ packages:
eslint@8.57.1:
resolution: {integrity: sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options.
hasBin: true
espree@9.6.1:
@@ -2510,8 +2532,8 @@ packages:
peerDependencies:
tailwindcss: 3.x
tailwindcss@3.4.13:
resolution: {integrity: sha512-KqjHOJKogOUt5Bs752ykCeiwvi0fKVkr5oqsFNt/8px/tA8scFPIlkygsf6jXrfCqGHz7VflA6+yytWuM+XhFw==}
tailwindcss@3.4.14:
resolution: {integrity: sha512-IcSvOcTRcUtQQ7ILQL5quRDg7Xs93PdJEk1ZLbhhvJc7uj/OAhYOnruEiwnGgBvUtaUAJ8/mhSw1o8L2jCiENA==}
engines: {node: '>=14.0.0'}
hasBin: true
@@ -2624,8 +2646,8 @@ packages:
resolution: {integrity: sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==}
engines: {node: '>= 0.4'}
typescript@5.6.2:
resolution: {integrity: sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw==}
typescript@5.6.3:
resolution: {integrity: sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==}
engines: {node: '>=14.17'}
hasBin: true
@@ -2649,8 +2671,8 @@ packages:
peerDependencies:
browserslist: '>= 4.21.0'
urbackup-server-api@0.52.0:
resolution: {integrity: sha512-KfroCFZEWCuCkWye1F1JwI2fkO1za/Mf1a8TNGTujzxU0ZGzDqhA1zCOcvV97q7nH1TKFNpw5tMZ06fSCKv2UA==}
urbackup-server-api@0.52.1:
resolution: {integrity: sha512-gAxF9MdXxnceqUr/1Uj2LuGZQb/bvZ3Ply9zH/UTSWGkwKL5C0qMPrBvKRyTHbPMG/NBuHF6BzavkF7GNvOLew==}
uri-js@4.4.1:
resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
@@ -2956,10 +2978,10 @@ snapshots:
dependencies:
defer-to-connect: 2.0.1
'@tailwindcss/forms@0.5.9(tailwindcss@3.4.13)':
'@tailwindcss/forms@0.5.9(tailwindcss@3.4.14)':
dependencies:
mini-svg-data-uri: 1.4.4
tailwindcss: 3.4.13
tailwindcss: 3.4.14
'@tanstack/react-virtual@3.10.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies:
@@ -3015,13 +3037,13 @@ snapshots:
'@types/triple-beam@1.3.5': {}
'@typescript-eslint/eslint-plugin@7.2.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.2))(eslint@8.57.1)(typescript@5.6.2)':
'@typescript-eslint/eslint-plugin@7.2.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1)(typescript@5.6.3)':
dependencies:
'@eslint-community/regexpp': 4.11.0
'@typescript-eslint/parser': 7.2.0(eslint@8.57.1)(typescript@5.6.2)
'@typescript-eslint/parser': 7.2.0(eslint@8.57.1)(typescript@5.6.3)
'@typescript-eslint/scope-manager': 7.2.0
'@typescript-eslint/type-utils': 7.2.0(eslint@8.57.1)(typescript@5.6.2)
'@typescript-eslint/utils': 7.2.0(eslint@8.57.1)(typescript@5.6.2)
'@typescript-eslint/type-utils': 7.2.0(eslint@8.57.1)(typescript@5.6.3)
'@typescript-eslint/utils': 7.2.0(eslint@8.57.1)(typescript@5.6.3)
'@typescript-eslint/visitor-keys': 7.2.0
debug: 4.3.6
eslint: 8.57.1
@@ -3029,22 +3051,22 @@ snapshots:
ignore: 5.3.2
natural-compare: 1.4.0
semver: 7.6.3
ts-api-utils: 1.3.0(typescript@5.6.2)
ts-api-utils: 1.3.0(typescript@5.6.3)
optionalDependencies:
typescript: 5.6.2
typescript: 5.6.3
transitivePeerDependencies:
- supports-color
'@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.2)':
'@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.3)':
dependencies:
'@typescript-eslint/scope-manager': 7.2.0
'@typescript-eslint/types': 7.2.0
'@typescript-eslint/typescript-estree': 7.2.0(typescript@5.6.2)
'@typescript-eslint/typescript-estree': 7.2.0(typescript@5.6.3)
'@typescript-eslint/visitor-keys': 7.2.0
debug: 4.3.6
eslint: 8.57.1
optionalDependencies:
typescript: 5.6.2
typescript: 5.6.3
transitivePeerDependencies:
- supports-color
@@ -3053,21 +3075,21 @@ snapshots:
'@typescript-eslint/types': 7.2.0
'@typescript-eslint/visitor-keys': 7.2.0
'@typescript-eslint/type-utils@7.2.0(eslint@8.57.1)(typescript@5.6.2)':
'@typescript-eslint/type-utils@7.2.0(eslint@8.57.1)(typescript@5.6.3)':
dependencies:
'@typescript-eslint/typescript-estree': 7.2.0(typescript@5.6.2)
'@typescript-eslint/utils': 7.2.0(eslint@8.57.1)(typescript@5.6.2)
'@typescript-eslint/typescript-estree': 7.2.0(typescript@5.6.3)
'@typescript-eslint/utils': 7.2.0(eslint@8.57.1)(typescript@5.6.3)
debug: 4.3.6
eslint: 8.57.1
ts-api-utils: 1.3.0(typescript@5.6.2)
ts-api-utils: 1.3.0(typescript@5.6.3)
optionalDependencies:
typescript: 5.6.2
typescript: 5.6.3
transitivePeerDependencies:
- supports-color
'@typescript-eslint/types@7.2.0': {}
'@typescript-eslint/typescript-estree@7.2.0(typescript@5.6.2)':
'@typescript-eslint/typescript-estree@7.2.0(typescript@5.6.3)':
dependencies:
'@typescript-eslint/types': 7.2.0
'@typescript-eslint/visitor-keys': 7.2.0
@@ -3076,20 +3098,20 @@ snapshots:
is-glob: 4.0.3
minimatch: 9.0.3
semver: 7.6.3
ts-api-utils: 1.3.0(typescript@5.6.2)
ts-api-utils: 1.3.0(typescript@5.6.3)
optionalDependencies:
typescript: 5.6.2
typescript: 5.6.3
transitivePeerDependencies:
- supports-color
'@typescript-eslint/utils@7.2.0(eslint@8.57.1)(typescript@5.6.2)':
'@typescript-eslint/utils@7.2.0(eslint@8.57.1)(typescript@5.6.3)':
dependencies:
'@eslint-community/eslint-utils': 4.4.0(eslint@8.57.1)
'@types/json-schema': 7.0.15
'@types/semver': 7.5.8
'@typescript-eslint/scope-manager': 7.2.0
'@typescript-eslint/types': 7.2.0
'@typescript-eslint/typescript-estree': 7.2.0(typescript@5.6.2)
'@typescript-eslint/typescript-estree': 7.2.0(typescript@5.6.3)
eslint: 8.57.1
semver: 7.6.3
transitivePeerDependencies:
@@ -3759,41 +3781,41 @@ snapshots:
escape-string-regexp@4.0.0: {}
eslint-config-airbnb-base@15.0.0(eslint-plugin-import@2.30.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.2))(eslint@8.57.1))(eslint@8.57.1):
eslint-config-airbnb-base@15.0.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1))(eslint@8.57.1):
dependencies:
confusing-browser-globals: 1.0.11
eslint: 8.57.1
eslint-plugin-import: 2.30.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1)
eslint-plugin-import: 2.31.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1)
object.assign: 4.1.5
object.entries: 1.1.8
semver: 6.3.1
eslint-config-airbnb@19.0.4(eslint-plugin-import@2.30.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.2))(eslint@8.57.1))(eslint-plugin-jsx-a11y@6.10.0(eslint@8.57.1))(eslint-plugin-react-hooks@4.6.2(eslint@8.57.1))(eslint-plugin-react@7.37.1(eslint@8.57.1))(eslint@8.57.1):
eslint-config-airbnb@19.0.4(eslint-plugin-import@2.31.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1))(eslint-plugin-jsx-a11y@6.10.0(eslint@8.57.1))(eslint-plugin-react-hooks@4.6.2(eslint@8.57.1))(eslint-plugin-react@7.37.1(eslint@8.57.1))(eslint@8.57.1):
dependencies:
eslint: 8.57.1
eslint-config-airbnb-base: 15.0.0(eslint-plugin-import@2.30.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.2))(eslint@8.57.1))(eslint@8.57.1)
eslint-plugin-import: 2.30.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1)
eslint-config-airbnb-base: 15.0.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1))(eslint@8.57.1)
eslint-plugin-import: 2.31.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1)
eslint-plugin-jsx-a11y: 6.10.0(eslint@8.57.1)
eslint-plugin-react: 7.37.1(eslint@8.57.1)
eslint-plugin-react-hooks: 4.6.2(eslint@8.57.1)
object.assign: 4.1.5
object.entries: 1.1.8
eslint-config-next@14.2.8(eslint@8.57.1)(typescript@5.6.2):
eslint-config-next@14.2.8(eslint@8.57.1)(typescript@5.6.3):
dependencies:
'@next/eslint-plugin-next': 14.2.8
'@rushstack/eslint-patch': 1.10.4
'@typescript-eslint/eslint-plugin': 7.2.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.2))(eslint@8.57.1)(typescript@5.6.2)
'@typescript-eslint/parser': 7.2.0(eslint@8.57.1)(typescript@5.6.2)
'@typescript-eslint/eslint-plugin': 7.2.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1)(typescript@5.6.3)
'@typescript-eslint/parser': 7.2.0(eslint@8.57.1)(typescript@5.6.3)
eslint: 8.57.1
eslint-import-resolver-node: 0.3.9
eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.30.0)(eslint@8.57.1)
eslint-plugin-import: 2.30.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1)
eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@8.57.1)
eslint-plugin-import: 2.31.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1)
eslint-plugin-jsx-a11y: 6.10.0(eslint@8.57.1)
eslint-plugin-react: 7.37.1(eslint@8.57.1)
eslint-plugin-react-hooks: 4.6.2(eslint@8.57.1)
optionalDependencies:
typescript: 5.6.2
typescript: 5.6.3
transitivePeerDependencies:
- eslint-import-resolver-webpack
- eslint-plugin-import-x
@@ -3811,37 +3833,48 @@ snapshots:
transitivePeerDependencies:
- supports-color
eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.30.0)(eslint@8.57.1):
eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@8.57.1):
dependencies:
'@nolyfill/is-core-module': 1.0.39
debug: 4.3.6
enhanced-resolve: 5.17.1
eslint: 8.57.1
eslint-module-utils: 2.9.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.30.0)(eslint@8.57.1))(eslint@8.57.1)
eslint-module-utils: 2.9.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@8.57.1))(eslint@8.57.1)
fast-glob: 3.3.2
get-tsconfig: 4.8.0
is-bun-module: 1.1.0
is-glob: 4.0.3
optionalDependencies:
eslint-plugin-import: 2.30.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1)
eslint-plugin-import: 2.31.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1)
transitivePeerDependencies:
- '@typescript-eslint/parser'
- eslint-import-resolver-node
- eslint-import-resolver-webpack
- supports-color
eslint-module-utils@2.9.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.30.0)(eslint@8.57.1))(eslint@8.57.1):
eslint-module-utils@2.12.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@8.57.1))(eslint@8.57.1):
dependencies:
debug: 3.2.7
optionalDependencies:
'@typescript-eslint/parser': 7.2.0(eslint@8.57.1)(typescript@5.6.2)
'@typescript-eslint/parser': 7.2.0(eslint@8.57.1)(typescript@5.6.3)
eslint: 8.57.1
eslint-import-resolver-node: 0.3.9
eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.30.0)(eslint@8.57.1)
eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@8.57.1)
transitivePeerDependencies:
- supports-color
eslint-plugin-import@2.30.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1):
eslint-module-utils@2.9.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@8.57.1))(eslint@8.57.1):
dependencies:
debug: 3.2.7
optionalDependencies:
'@typescript-eslint/parser': 7.2.0(eslint@8.57.1)(typescript@5.6.3)
eslint: 8.57.1
eslint-import-resolver-node: 0.3.9
eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@8.57.1)
transitivePeerDependencies:
- supports-color
eslint-plugin-import@2.31.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1):
dependencies:
'@rtsao/scc': 1.1.0
array-includes: 3.1.8
@@ -3852,7 +3885,7 @@ snapshots:
doctrine: 2.1.0
eslint: 8.57.1
eslint-import-resolver-node: 0.3.9
eslint-module-utils: 2.9.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.30.0)(eslint@8.57.1))(eslint@8.57.1)
eslint-module-utils: 2.12.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@8.57.1))(eslint@8.57.1)
hasown: 2.0.2
is-core-module: 2.15.1
is-glob: 4.0.3
@@ -3861,9 +3894,10 @@ snapshots:
object.groupby: 1.0.3
object.values: 1.2.0
semver: 6.3.1
string.prototype.trimend: 1.0.8
tsconfig-paths: 3.15.0
optionalDependencies:
'@typescript-eslint/parser': 7.2.0(eslint@8.57.1)(typescript@5.6.2)
'@typescript-eslint/parser': 7.2.0(eslint@8.57.1)(typescript@5.6.3)
transitivePeerDependencies:
- eslint-import-resolver-typescript
- eslint-import-resolver-webpack
@@ -5355,11 +5389,11 @@ snapshots:
systeminformation@5.23.5: {}
tailwind-scrollbar@3.1.0(tailwindcss@3.4.13):
tailwind-scrollbar@3.1.0(tailwindcss@3.4.14):
dependencies:
tailwindcss: 3.4.13
tailwindcss: 3.4.14
tailwindcss@3.4.13:
tailwindcss@3.4.14:
dependencies:
'@alloc/quick-lru': 5.2.0
arg: 5.0.2
@@ -5454,9 +5488,9 @@ snapshots:
triple-beam@1.4.1: {}
ts-api-utils@1.3.0(typescript@5.6.2):
ts-api-utils@1.3.0(typescript@5.6.3):
dependencies:
typescript: 5.6.2
typescript: 5.6.3
ts-interface-checker@0.1.13: {}
@@ -5515,7 +5549,7 @@ snapshots:
is-typed-array: 1.1.13
possible-typed-array-names: 1.0.0
typescript@5.6.2: {}
typescript@5.6.3: {}
unbox-primitive@1.0.2:
dependencies:
@@ -5536,7 +5570,7 @@ snapshots:
escalade: 3.2.0
picocolors: 1.1.0
urbackup-server-api@0.52.0:
urbackup-server-api@0.52.1:
dependencies:
async-mutex: 0.5.0
node-fetch: 2.7.0

View File

@@ -13,7 +13,7 @@
"ms": "{{value, number}}",
"date": "{{value, date}}",
"relativeDate": "{{value, relativeDate}}",
"uptime": "{{value, uptime}}",
"duration": "{{value, duration}}",
"months": "mo",
"days": "d",
"hours": "h",
@@ -959,5 +959,24 @@
"tasks7d": "Tasks Due This Week",
"tasksOverdue": "Overdue Tasks",
"tasksInProgress": "Tasks In Progress"
},
"headscale": {
"name": "Name",
"address": "Address",
"last_seen": "Last Seen",
"status": "Status",
"online": "Online",
"offline": "Offline"
},
"beszel": {
"name": "Name",
"systems": "Systems",
"up": "Up",
"status": "Status",
"updated": "Updated",
"cpu": "CPU",
"memory": "MEM",
"disk": "Disk",
"network": "NET"
}
}

View File

@@ -20,7 +20,7 @@ export default function BookmarksGroup({ bookmarks, layout, disableCollapse, gro
className={classNames(
"bookmark-group",
layout?.style === "row" ? "basis-full" : "basis-full md:basis-1/4 lg:basis-1/5 xl:basis-1/6",
layout?.header === false ? "flex-1 px-1 -my-1" : "flex-1 p-1",
layout?.header === false ? "flex-1 px-1 -my-1 overflow-hidden" : "flex-1 p-1 overflow-hidden",
)}
>
<Disclosure defaultOpen={!(layout?.initiallyCollapsed ?? groupsInitiallyCollapsed) ?? true}>

View File

@@ -29,9 +29,9 @@ export default function Item({ bookmark }) {
)}
{!bookmark.icon && bookmark.abbr}
</div>
<div className="flex-1 flex items-center justify-between rounded-r-md bookmark-text">
<div className="flex-1 grow pl-3 py-2 text-xs bookmark-name">{bookmark.name}</div>
<div className="px-2 py-2 truncate text-theme-500 dark:text-theme-300 text-xs bookmark-description">
<div className="flex-1 overflow-hidden flex items-center justify-between rounded-r-md bookmark-text">
<div className="pl-3 py-2 text-xs bookmark-name">{bookmark.name}</div>
<div className="shrink truncate px-2 py-2 text-theme-500 dark:text-theme-300 text-xs bookmark-description">
{description}
</div>
</div>

View File

@@ -98,6 +98,12 @@ export default function QuickLaunch({ servicesAndBookmarks, searchString, setSea
} else if (event.key === "ArrowUp" && currentItemIndex > 0) {
setCurrentItemIndex(currentItemIndex - 1);
event.preventDefault();
} else if (
event.key === "ArrowRight" &&
results[currentItemIndex] &&
results[currentItemIndex].type === "searchSuggestion"
) {
setSearchString(results[currentItemIndex].name);
}
}

View File

@@ -25,7 +25,7 @@ export default function Uptime({ refresh = 1500 }) {
return (
<Resource
icon={FaRegClock}
value={t("common.uptime", { value: data.uptime })}
value={t("common.duration", { value: data.uptime })}
label={t("resources.uptime")}
percentage={percent}
/>

View File

@@ -8,7 +8,7 @@ export default function Document() {
name="description"
content="A highly customizable homepage (or startpage / application dashboard) with Docker and service API integrations."
/>
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="mobile-web-app-capable" content="yes" />
<link rel="manifest" href="/site.webmanifest?v=4" crossOrigin="use-credentials" />
</Head>
<body>

View File

@@ -2,7 +2,7 @@ import cachedFetch from "utils/proxy/cached-fetch";
export default async function handler(req, res) {
const { latitude, longitude, units, cache, timezone } = req.query;
const degrees = units === "imperial" ? "fahrenheit" : "celsius";
const degrees = units === "metric" ? "celsius" : "fahrenheit";
const timezeone = timezone ?? "auto";
const apiUrl = `https://api.open-meteo.com/v1/forecast?latitude=${latitude}&longitude=${longitude}&daily=sunrise,sunset&current_weather=true&temperature_unit=${degrees}&timezone=${timezeone}`;
return res.send(await cachedFetch(apiUrl, cache));

View File

@@ -368,6 +368,9 @@ export function cleanServiceGroups(groups) {
repositoryId,
userEmail,
// beszel
systemId,
// calendar
firstDayInWeek,
integrations,
@@ -511,6 +514,10 @@ export function cleanServiceGroups(groups) {
if (repositoryId) cleanedService.widget.repositoryId = repositoryId;
}
if (type === "beszel") {
if (systemId) cleanedService.widget.systemId = systemId;
}
if (type === "coinmarketcap") {
if (currency) cleanedService.widget.currency = currency;
if (symbols) cleanedService.widget.symbols = symbols;

View File

@@ -39,6 +39,7 @@ export default async function credentialedProxyHandler(req, res, map) {
"authentik",
"cloudflared",
"ghostfolio",
"headscale",
"linkwarden",
"mealie",
"netalertx",

View File

@@ -39,11 +39,8 @@ export default function Component({ service }) {
<Block label="audiobookshelf.podcasts" value={t("common.number", { value: totalPodcasts })} />
<Block
label="audiobookshelf.podcastsDuration"
value={t("common.number", {
value: totalPodcastsDuration / 60,
maximumFractionDigits: 0,
style: "unit",
unit: "minute",
value={t("common.duration", {
value: totalPodcastsDuration,
})}
/>
<Block label="audiobookshelf.books" value={t("common.number", { value: totalBooks })} />

View File

@@ -0,0 +1,60 @@
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 { systemId } = widget;
const { data: systems, error: systemsError } = useWidgetAPI(widget, "systems");
const MAX_ALLOWED_FIELDS = 4;
if (!widget.fields?.length > 0) {
widget.fields = systemId ? ["name", "status", "cpu", "memory"] : ["systems", "up"];
}
if (widget.fields?.length > MAX_ALLOWED_FIELDS) {
widget.fields = widget.fields.slice(0, MAX_ALLOWED_FIELDS);
}
if (systemsError) {
return <Container service={service} error={systemsError} />;
}
if (!systems) {
return (
<Container service={service}>
<Block label="beszel.systems" />
<Block label="beszel.up" />
</Container>
);
}
if (systemId) {
const system = systems.items.find((item) => item.id === systemId);
return (
<Container service={service}>
<Block label="beszel.name" value={system.name} />
<Block label="beszel.status" value={t(`beszel.${system.status}`)} />
<Block label="beszel.updated" value={t("common.relativeDate", { value: system.updated })} />
<Block label="beszel.cpu" value={t("common.percent", { value: system.info.cpu, maximumFractionDigits: 2 })} />
<Block label="beszel.memory" value={t("common.percent", { value: system.info.mp, maximumFractionDigits: 2 })} />
<Block label="beszel.disk" value={t("common.percent", { value: system.info.dp, maximumFractionDigits: 2 })} />
<Block label="beszel.network" value={t("common.percent", { value: system.info.b, maximumFractionDigits: 2 })} />
</Container>
);
}
const upTotal = systems.items.filter((item) => item.status === "up").length;
return (
<Container service={service}>
<Block label="beszel.systems" value={systems.totalItems} />
<Block label="beszel.up" value={`${upTotal} / ${systems.totalItems}`} />
</Container>
);
}

View File

@@ -0,0 +1,99 @@
import cache from "memory-cache";
import getServiceWidget from "utils/config/service-helpers";
import { formatApiCall } from "utils/proxy/api-helpers";
import { httpProxy } from "utils/proxy/http";
import widgets from "widgets/widgets";
import createLogger from "utils/logger";
const proxyName = "beszelProxyHandler";
const tokenCacheKey = `${proxyName}__token`;
const logger = createLogger(proxyName);
async function login(loginUrl, username, password, service) {
const authResponse = await httpProxy(loginUrl, {
method: "POST",
body: JSON.stringify({ identity: username, password }),
headers: {
"Content-Type": "application/json",
},
});
const status = authResponse[0];
let data = authResponse[2];
try {
data = JSON.parse(Buffer.from(authResponse[2]).toString());
if (status === 200) {
cache.put(`${tokenCacheKey}.${service}`, data.token);
}
} catch (e) {
logger.error(`Error ${status} logging into beszel`, JSON.stringify(authResponse[2]));
}
return [status, data.token ?? data];
}
export default async function beszelProxyHandler(req, res) {
const { group, service, endpoint } = req.query;
if (group && service) {
const widget = await getServiceWidget(group, service);
if (!widgets?.[widget.type]?.api) {
return res.status(403).json({ error: "Service does not support API calls" });
}
if (widget) {
const url = new URL(formatApiCall(widgets[widget.type].api, { endpoint, ...widget }));
const loginUrl = formatApiCall(widgets[widget.type].api, { endpoint: "admins/auth-with-password", ...widget });
let status;
let data;
let token = cache.get(`${tokenCacheKey}.${service}`);
if (!token) {
[status, token] = await login(loginUrl, widget.username, widget.password, service);
if (status !== 200) {
logger.debug(`HTTTP ${status} logging into npm api: ${token}`);
return res.status(status).send(token);
}
}
[status, , data] = await httpProxy(url, {
method: "GET",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${token}`,
},
});
if (status === 403) {
logger.debug(`HTTTP ${status} retrieving data from npm api, logging in and trying again.`);
cache.del(`${tokenCacheKey}.${service}`);
[status, token] = await login(loginUrl, widget.username, widget.password, service);
if (status !== 200) {
logger.debug(`HTTTP ${status} logging into npm api: ${data}`);
return res.status(status).send(data);
}
// eslint-disable-next-line no-unused-vars
[status, , data] = await httpProxy(url, {
method: "GET",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${token}`,
},
});
}
if (status !== 200) {
return res.status(status).send(data);
}
return res.send(data);
}
}
return res.status(400).json({ error: "Invalid proxy service type" });
}

View File

@@ -0,0 +1,14 @@
import beszelProxyHandler from "./proxy";
const widget = {
api: "{url}/api/{endpoint}",
proxyHandler: beszelProxyHandler,
mappings: {
systems: {
endpoint: "collections/systems/records?page=1&perPage=500&sort=%2Bcreated",
},
},
};
export default widget;

View File

@@ -8,6 +8,7 @@ const components = {
autobrr: dynamic(() => import("./autobrr/component")),
azuredevops: dynamic(() => import("./azuredevops/component")),
bazarr: dynamic(() => import("./bazarr/component")),
beszel: dynamic(() => import("./beszel/component")),
caddy: dynamic(() => import("./caddy/component")),
calendar: dynamic(() => import("./calendar/component")),
calibreweb: dynamic(() => import("./calibreweb/component")),
@@ -41,6 +42,7 @@ const components = {
gotify: dynamic(() => import("./gotify/component")),
grafana: dynamic(() => import("./grafana/component")),
hdhomerun: dynamic(() => import("./hdhomerun/component")),
headscale: dynamic(() => import("./headscale/component")),
peanut: dynamic(() => import("./peanut/component")),
homeassistant: dynamic(() => import("./homeassistant/component")),
homebox: dynamic(() => import("./homebox/component")),

View File

@@ -40,7 +40,7 @@ export default function Component({ service }) {
/>
<Block
label="frigate.uptime"
value={t("common.uptime", {
value={t("common.duration", {
value: data.uptime,
})}
/>

View File

@@ -44,7 +44,7 @@ export default function Component({ service }) {
return (
<Container service={service}>
<Block label="fritzbox.connectionStatus" value={t(`fritzbox.connectionStatus${fritzboxData.connectionStatus}`)} />
<Block label="fritzbox.uptime" value={t("common.uptime", { value: fritzboxData.uptime })} />
<Block label="fritzbox.uptime" value={t("common.duration", { value: fritzboxData.uptime })} />
<Block label="fritzbox.maxDown" value={t("common.byterate", { value: fritzboxData.maxDown / 8, decimals: 1 })} />
<Block label="fritzbox.maxUp" value={t("common.byterate", { value: fritzboxData.maxUp / 8, decimals: 1 })} />
<Block label="fritzbox.down" value={t("common.byterate", { value: fritzboxData.down, decimals: 1 })} />

View File

@@ -0,0 +1,43 @@
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: nodeData, error: nodeError } = useWidgetAPI(widget, "node");
if (nodeError) {
return <Container service={service} error={nodeError} />;
}
if (!nodeData) {
return (
<Container service={service}>
<Block label="headscale.name" />
<Block label="headscale.address" />
<Block label="headscale.last_seen" />
<Block label="headscale.status" />
</Container>
);
}
const {
givenName,
ipAddresses: [address],
lastSeen,
online,
} = nodeData.node;
return (
<Container service={service}>
<Block label="headscale.name" value={givenName} />
<Block label="headscale.address" value={address} />
<Block label="headscale.last_seen" value={t("common.relativeDate", { value: lastSeen })} />
<Block label="headscale.status" value={t(online ? "headscale.online" : "headscale.offline")} />
</Container>
);
}

View File

@@ -0,0 +1,14 @@
import credentialedProxyHandler from "utils/proxy/handlers/credentialed";
const widget = {
api: "{url}/api/v1/{endpoint}/{nodeId}",
proxyHandler: credentialedProxyHandler,
mappings: {
node: {
endpoint: "node",
},
},
};
export default widget;

View File

@@ -21,8 +21,8 @@ export default function Component({ service }) {
);
}
const enabled = infoData.filter((c) => c.enabled === 1).length;
const disabled = infoData.filter((c) => c.enabled === 0).length;
const enabled = infoData.filter((c) => !!c.enabled).length;
const disabled = infoData.filter((c) => !c.enabled).length;
const total = infoData.length;
return (

View File

@@ -30,7 +30,7 @@ async function login(loginUrl, username, password, service) {
cache.put(`${tokenCacheKey}.${service}`, data.token, expiration - 5 * 60 * 1000); // expiration -5 minutes
}
} catch (e) {
logger.error(`Error ${status} logging into npm`, authResponse[2]);
logger.error(`Error ${status} logging into npm`, JSON.stringify(authResponse[2]));
}
return [status, data.token ?? data];
}
@@ -50,7 +50,6 @@ export default async function npmProxyHandler(req, res) {
const loginUrl = `${widget.url}/api/tokens`;
let status;
let contentType;
let data;
let token = cache.get(`${tokenCacheKey}.${service}`);
@@ -62,7 +61,7 @@ export default async function npmProxyHandler(req, res) {
}
}
[status, contentType, data] = await httpProxy(url, {
[status, , data] = await httpProxy(url, {
method: "GET",
headers: {
"Content-Type": "application/json",
@@ -81,7 +80,7 @@ export default async function npmProxyHandler(req, res) {
}
// eslint-disable-next-line no-unused-vars
[status, contentType, data] = await httpProxy(url, {
[status, , data] = await httpProxy(url, {
method: "GET",
headers: {
"Content-Type": "application/json",

View File

@@ -20,7 +20,7 @@ export default function Component({ service }) {
return (
<Container service={service}>
<Block label="openwrt.uptime" value={t("common.uptime", { value: uptime })} />
<Block label="openwrt.uptime" value={t("common.duration", { value: uptime })} />
<Block label="openwrt.cpuLoad" value={cpuLoad} />
</Container>
);

View File

@@ -15,7 +15,7 @@ async function fetchFromPyloadAPI(url, sessionId, params, service) {
const options = {
body: params
? Object.keys(params)
.map((prop) => `${prop}=${params[prop]}`)
.map((prop) => `${prop}=${encodeURIComponent(params[prop])}`)
.join("&")
: `session=${sessionId}`,
method: "POST",

View File

@@ -12,7 +12,10 @@ const widget = {
wanted: jsonArrayFilter(data, (item) => item.monitored && !item.hasFile && item.isAvailable).length,
have: jsonArrayFilter(data, (item) => item.hasFile).length,
missing: jsonArrayFilter(data, (item) => item.monitored && !item.hasFile).length,
all: asJson(data),
all: asJson(data).map((entry) => ({
title: entry.title,
id: entry.id,
})),
}),
},
"queue/status": {

View File

@@ -46,12 +46,12 @@ export default function Component({ service }) {
<Block label="stash.scenes" value={t("common.number", { value: stats.scene_count })} />
<Block label="stash.scenesPlayed" value={t("common.number", { value: stats.scenes_played })} />
<Block label="stash.playCount" value={t("common.number", { value: stats.total_play_count })} />
<Block label="stash.playDuration" value={t("common.uptime", { value: stats.total_play_duration })} />
<Block label="stash.playDuration" value={t("common.duration", { value: stats.total_play_duration })} />
<Block
label="stash.sceneSize"
value={t("common.bbytes", { value: stats.scenes_size, maximumFractionDigits: 1 })}
/>
<Block label="stash.sceneDuration" value={t("common.uptime", { value: stats.scenes_duration })} />
<Block label="stash.sceneDuration" value={t("common.duration", { value: stats.scenes_duration })} />
<Block label="stash.images" value={t("common.number", { value: stats.image_count })} />
<Block

View File

@@ -35,7 +35,7 @@ export default function Component({ service }) {
<>
<Container service={service}>
<Block label="truenas.load" value={t("common.number", { value: statusData.loadavg[0] })} />
<Block label="truenas.uptime" value={t("common.uptime", { value: statusData.uptime_seconds })} />
<Block label="truenas.uptime" value={t("common.duration", { value: statusData.uptime_seconds })} />
<Block label="truenas.alerts" value={t("common.number", { value: alertData.pending })} />
</Container>
{enablePools &&

View File

@@ -1,4 +1,3 @@
// import credentialedProxyHandler from "utils/proxy/handlers/credentialed";
import genericProxyHandler from "utils/proxy/handlers/generic";
const widget = {

View File

@@ -58,7 +58,7 @@ export default function Component({ service }) {
break;
case 2:
status = t("uptimerobot.up");
uptime = t("common.uptime", { value: monitor.logs[0].duration });
uptime = t("common.duration", { value: monitor.logs[0].duration });
logIndex = 1;
break;
case 8:
@@ -73,7 +73,7 @@ export default function Component({ service }) {
}
const lastDown = new Date(monitor.logs[logIndex].datetime * 1000).toLocaleString();
const downDuration = t("common.uptime", { value: monitor.logs[logIndex].duration });
const downDuration = t("common.duration", { value: monitor.logs[logIndex].duration });
const hideDown = logIndex === 1 && monitor.logs[logIndex].type !== 1;
return (

View File

@@ -5,6 +5,7 @@ import authentik from "./authentik/widget";
import autobrr from "./autobrr/widget";
import azuredevops from "./azuredevops/widget";
import bazarr from "./bazarr/widget";
import beszel from "./beszel/widget";
import caddy from "./caddy/widget";
import calendar from "./calendar/widget";
import calibreweb from "./calibreweb/widget";
@@ -35,6 +36,7 @@ import gluetun from "./gluetun/widget";
import gotify from "./gotify/widget";
import grafana from "./grafana/widget";
import hdhomerun from "./hdhomerun/widget";
import headscale from "./headscale/widget";
import homeassistant from "./homeassistant/widget";
import homebox from "./homebox/widget";
import homebridge from "./homebridge/widget";
@@ -132,6 +134,7 @@ const widgets = {
autobrr,
azuredevops,
bazarr,
beszel,
caddy,
calibreweb,
changedetectionio,
@@ -161,6 +164,7 @@ const widgets = {
gotify,
grafana,
hdhomerun,
headscale,
homeassistant,
homebox,
homebridge,