mirror of
https://github.com/karl0ss/homepage.git
synced 2025-04-29 12:03:41 +01:00
linting and cleanup
This commit is contained in:
parent
7f041e8303
commit
f74e8b9d32
@ -1,3 +1,19 @@
|
|||||||
{
|
{
|
||||||
"extends": "next/core-web-vitals"
|
"extends": ["airbnb", "next/core-web-vitals", "prettier"],
|
||||||
|
"plugins": ["prettier"],
|
||||||
|
"rules": {
|
||||||
|
"import/order": [
|
||||||
|
"error",
|
||||||
|
{
|
||||||
|
"newlines-between": "always"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"settings": {
|
||||||
|
"import/resolver": {
|
||||||
|
"node": {
|
||||||
|
"paths": ["src"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@headlessui/react": "^1.6.6",
|
"@headlessui/react": "^1.6.6",
|
||||||
"@tailwindcss/forms": "^0.5.3",
|
"@tailwindcss/forms": "^0.5.3",
|
||||||
|
"classnames": "^2.3.1",
|
||||||
"dockerode": "^3.3.4",
|
"dockerode": "^3.3.4",
|
||||||
"js-yaml": "^4.1.0",
|
"js-yaml": "^4.1.0",
|
||||||
"json-rpc-2.0": "^1.4.1",
|
"json-rpc-2.0": "^1.4.1",
|
||||||
@ -27,8 +28,16 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"autoprefixer": "^10.4.8",
|
"autoprefixer": "^10.4.8",
|
||||||
"eslint": "8.22.0",
|
"eslint": "8.22.0",
|
||||||
|
"eslint-config-airbnb": "^19.0.4",
|
||||||
"eslint-config-next": "12.2.5",
|
"eslint-config-next": "12.2.5",
|
||||||
|
"eslint-config-prettier": "^8.5.0",
|
||||||
|
"eslint-plugin-import": "^2.26.0",
|
||||||
|
"eslint-plugin-jsx-a11y": "^6.6.1",
|
||||||
|
"eslint-plugin-prettier": "^4.2.1",
|
||||||
|
"eslint-plugin-react": "^7.30.1",
|
||||||
|
"eslint-plugin-react-hooks": "^4.6.0",
|
||||||
"postcss": "^8.4.16",
|
"postcss": "^8.4.16",
|
||||||
|
"prettier": "^2.7.1",
|
||||||
"tailwindcss": "^3.1.8",
|
"tailwindcss": "^3.1.8",
|
||||||
"typescript": "^4.8.2"
|
"typescript": "^4.8.2"
|
||||||
}
|
}
|
||||||
|
162
pnpm-lock.yaml
generated
162
pnpm-lock.yaml
generated
@ -4,15 +4,24 @@ specifiers:
|
|||||||
'@headlessui/react': ^1.6.6
|
'@headlessui/react': ^1.6.6
|
||||||
'@tailwindcss/forms': ^0.5.3
|
'@tailwindcss/forms': ^0.5.3
|
||||||
autoprefixer: ^10.4.8
|
autoprefixer: ^10.4.8
|
||||||
|
classnames: ^2.3.1
|
||||||
dockerode: ^3.3.4
|
dockerode: ^3.3.4
|
||||||
eslint: 8.22.0
|
eslint: 8.22.0
|
||||||
|
eslint-config-airbnb: ^19.0.4
|
||||||
eslint-config-next: 12.2.5
|
eslint-config-next: 12.2.5
|
||||||
|
eslint-config-prettier: ^8.5.0
|
||||||
|
eslint-plugin-import: ^2.26.0
|
||||||
|
eslint-plugin-jsx-a11y: ^6.6.1
|
||||||
|
eslint-plugin-prettier: ^4.2.1
|
||||||
|
eslint-plugin-react: ^7.30.1
|
||||||
|
eslint-plugin-react-hooks: ^4.6.0
|
||||||
js-yaml: ^4.1.0
|
js-yaml: ^4.1.0
|
||||||
json-rpc-2.0: ^1.4.1
|
json-rpc-2.0: ^1.4.1
|
||||||
memory-cache: ^0.2.0
|
memory-cache: ^0.2.0
|
||||||
next: 12.2.5
|
next: 12.2.5
|
||||||
node-os-utils: ^1.3.7
|
node-os-utils: ^1.3.7
|
||||||
postcss: ^8.4.16
|
postcss: ^8.4.16
|
||||||
|
prettier: ^2.7.1
|
||||||
raw-body: ^2.5.1
|
raw-body: ^2.5.1
|
||||||
react: 18.2.0
|
react: 18.2.0
|
||||||
react-dom: 18.2.0
|
react-dom: 18.2.0
|
||||||
@ -25,6 +34,7 @@ specifiers:
|
|||||||
dependencies:
|
dependencies:
|
||||||
'@headlessui/react': 1.6.6_biqbaboplfbrettd7655fr4n2y
|
'@headlessui/react': 1.6.6_biqbaboplfbrettd7655fr4n2y
|
||||||
'@tailwindcss/forms': 0.5.3_tailwindcss@3.1.8
|
'@tailwindcss/forms': 0.5.3_tailwindcss@3.1.8
|
||||||
|
classnames: 2.3.1
|
||||||
dockerode: 3.3.4
|
dockerode: 3.3.4
|
||||||
js-yaml: 4.1.0
|
js-yaml: 4.1.0
|
||||||
json-rpc-2.0: 1.4.1
|
json-rpc-2.0: 1.4.1
|
||||||
@ -41,8 +51,16 @@ dependencies:
|
|||||||
devDependencies:
|
devDependencies:
|
||||||
autoprefixer: 10.4.8_postcss@8.4.16
|
autoprefixer: 10.4.8_postcss@8.4.16
|
||||||
eslint: 8.22.0
|
eslint: 8.22.0
|
||||||
|
eslint-config-airbnb: 19.0.4_ujj5bqj46ej3re666g22wkx75e
|
||||||
eslint-config-next: 12.2.5_shit3uhl6a7megkzgoz6xssnfa
|
eslint-config-next: 12.2.5_shit3uhl6a7megkzgoz6xssnfa
|
||||||
|
eslint-config-prettier: 8.5.0_eslint@8.22.0
|
||||||
|
eslint-plugin-import: 2.26.0_eslint@8.22.0
|
||||||
|
eslint-plugin-jsx-a11y: 6.6.1_eslint@8.22.0
|
||||||
|
eslint-plugin-prettier: 4.2.1_i2cojdczqdiurzgttlwdgf764e
|
||||||
|
eslint-plugin-react: 7.31.5_eslint@8.22.0
|
||||||
|
eslint-plugin-react-hooks: 4.6.0_eslint@8.22.0
|
||||||
postcss: 8.4.16
|
postcss: 8.4.16
|
||||||
|
prettier: 2.7.1
|
||||||
tailwindcss: 3.1.8_postcss@8.4.16
|
tailwindcss: 3.1.8_postcss@8.4.16
|
||||||
typescript: 4.8.2
|
typescript: 4.8.2
|
||||||
|
|
||||||
@ -604,6 +622,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==}
|
resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/classnames/2.3.1:
|
||||||
|
resolution: {integrity: sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/color-convert/2.0.1:
|
/color-convert/2.0.1:
|
||||||
resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
|
resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
|
||||||
engines: {node: '>=7.0.0'}
|
engines: {node: '>=7.0.0'}
|
||||||
@ -625,6 +647,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
|
resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/confusing-browser-globals/1.0.11:
|
||||||
|
resolution: {integrity: sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA==}
|
||||||
|
dev: true
|
||||||
|
|
||||||
/core-js-pure/3.25.0:
|
/core-js-pure/3.25.0:
|
||||||
resolution: {integrity: sha512-IeHpLwk3uoci37yoI2Laty59+YqH9x5uR65/yiA0ARAJrTrN4YU0rmauLWfvqOuk77SlNJXj2rM6oT/dBD87+A==}
|
resolution: {integrity: sha512-IeHpLwk3uoci37yoI2Laty59+YqH9x5uR65/yiA0ARAJrTrN4YU0rmauLWfvqOuk77SlNJXj2rM6oT/dBD87+A==}
|
||||||
requiresBuild: true
|
requiresBuild: true
|
||||||
@ -843,6 +869,41 @@ packages:
|
|||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/eslint-config-airbnb-base/15.0.0_2iahngt3u2tkbdlu6s4gkur3pu:
|
||||||
|
resolution: {integrity: sha512-xaX3z4ZZIcFLvh2oUNvcX5oEofXda7giYmuplVxoOg5A7EXJMrUyqRgR+mhDhPK8LZ4PttFOBvCYDbX3sUoUig==}
|
||||||
|
engines: {node: ^10.12.0 || >=12.0.0}
|
||||||
|
peerDependencies:
|
||||||
|
eslint: ^7.32.0 || ^8.2.0
|
||||||
|
eslint-plugin-import: ^2.25.2
|
||||||
|
dependencies:
|
||||||
|
confusing-browser-globals: 1.0.11
|
||||||
|
eslint: 8.22.0
|
||||||
|
eslint-plugin-import: 2.26.0_eslint@8.22.0
|
||||||
|
object.assign: 4.1.4
|
||||||
|
object.entries: 1.1.5
|
||||||
|
semver: 6.3.0
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/eslint-config-airbnb/19.0.4_ujj5bqj46ej3re666g22wkx75e:
|
||||||
|
resolution: {integrity: sha512-T75QYQVQX57jiNgpF9r1KegMICE94VYwoFQyMGhrvc+lB8YF2E/M/PYDaQe1AJcWaEgqLE+ErXV1Og/+6Vyzew==}
|
||||||
|
engines: {node: ^10.12.0 || ^12.22.0 || ^14.17.0 || >=16.0.0}
|
||||||
|
peerDependencies:
|
||||||
|
eslint: ^7.32.0 || ^8.2.0
|
||||||
|
eslint-plugin-import: ^2.25.3
|
||||||
|
eslint-plugin-jsx-a11y: ^6.5.1
|
||||||
|
eslint-plugin-react: ^7.28.0
|
||||||
|
eslint-plugin-react-hooks: ^4.3.0
|
||||||
|
dependencies:
|
||||||
|
eslint: 8.22.0
|
||||||
|
eslint-config-airbnb-base: 15.0.0_2iahngt3u2tkbdlu6s4gkur3pu
|
||||||
|
eslint-plugin-import: 2.26.0_eslint@8.22.0
|
||||||
|
eslint-plugin-jsx-a11y: 6.6.1_eslint@8.22.0
|
||||||
|
eslint-plugin-react: 7.31.5_eslint@8.22.0
|
||||||
|
eslint-plugin-react-hooks: 4.6.0_eslint@8.22.0
|
||||||
|
object.assign: 4.1.4
|
||||||
|
object.entries: 1.1.5
|
||||||
|
dev: true
|
||||||
|
|
||||||
/eslint-config-next/12.2.5_shit3uhl6a7megkzgoz6xssnfa:
|
/eslint-config-next/12.2.5_shit3uhl6a7megkzgoz6xssnfa:
|
||||||
resolution: {integrity: sha512-SOowilkqPzW6DxKp3a3SYlrfPi5Ajs9MIzp9gVfUDxxH9QFM5ElkR1hX5m/iICJuvCbWgQqFBiA3mCMozluniw==}
|
resolution: {integrity: sha512-SOowilkqPzW6DxKp3a3SYlrfPi5Ajs9MIzp9gVfUDxxH9QFM5ElkR1hX5m/iICJuvCbWgQqFBiA3mCMozluniw==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@ -868,6 +929,15 @@ packages:
|
|||||||
- supports-color
|
- supports-color
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/eslint-config-prettier/8.5.0_eslint@8.22.0:
|
||||||
|
resolution: {integrity: sha512-obmWKLUNCnhtQRKc+tmnYuQl0pFU1ibYJQ5BGhTVB08bHe9wC8qUeG7c08dj9XX+AuPj1YSGSQIHl1pnDHZR0Q==}
|
||||||
|
hasBin: true
|
||||||
|
peerDependencies:
|
||||||
|
eslint: '>=7.0.0'
|
||||||
|
dependencies:
|
||||||
|
eslint: 8.22.0
|
||||||
|
dev: true
|
||||||
|
|
||||||
/eslint-import-resolver-node/0.3.6:
|
/eslint-import-resolver-node/0.3.6:
|
||||||
resolution: {integrity: sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==}
|
resolution: {integrity: sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==}
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -925,6 +995,64 @@ packages:
|
|||||||
- supports-color
|
- supports-color
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/eslint-module-utils/2.7.4_7gfxlqsjhuntdifxknjgbjwpbu:
|
||||||
|
resolution: {integrity: sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==}
|
||||||
|
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
|
||||||
|
dependencies:
|
||||||
|
debug: 3.2.7
|
||||||
|
eslint: 8.22.0
|
||||||
|
eslint-import-resolver-node: 0.3.6
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- supports-color
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/eslint-plugin-import/2.26.0_eslint@8.22.0:
|
||||||
|
resolution: {integrity: sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==}
|
||||||
|
engines: {node: '>=4'}
|
||||||
|
peerDependencies:
|
||||||
|
'@typescript-eslint/parser': '*'
|
||||||
|
eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@typescript-eslint/parser':
|
||||||
|
optional: true
|
||||||
|
dependencies:
|
||||||
|
array-includes: 3.1.5
|
||||||
|
array.prototype.flat: 1.3.0
|
||||||
|
debug: 2.6.9
|
||||||
|
doctrine: 2.1.0
|
||||||
|
eslint: 8.22.0
|
||||||
|
eslint-import-resolver-node: 0.3.6
|
||||||
|
eslint-module-utils: 2.7.4_7gfxlqsjhuntdifxknjgbjwpbu
|
||||||
|
has: 1.0.3
|
||||||
|
is-core-module: 2.10.0
|
||||||
|
is-glob: 4.0.3
|
||||||
|
minimatch: 3.1.2
|
||||||
|
object.values: 1.1.5
|
||||||
|
resolve: 1.22.1
|
||||||
|
tsconfig-paths: 3.14.1
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- eslint-import-resolver-typescript
|
||||||
|
- eslint-import-resolver-webpack
|
||||||
|
- supports-color
|
||||||
|
dev: true
|
||||||
|
|
||||||
/eslint-plugin-import/2.26.0_oqagwj4pgbbpoeodu52b4a34xi:
|
/eslint-plugin-import/2.26.0_oqagwj4pgbbpoeodu52b4a34xi:
|
||||||
resolution: {integrity: sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==}
|
resolution: {integrity: sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==}
|
||||||
engines: {node: '>=4'}
|
engines: {node: '>=4'}
|
||||||
@ -978,6 +1106,23 @@ packages:
|
|||||||
semver: 6.3.0
|
semver: 6.3.0
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/eslint-plugin-prettier/4.2.1_i2cojdczqdiurzgttlwdgf764e:
|
||||||
|
resolution: {integrity: sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ==}
|
||||||
|
engines: {node: '>=12.0.0'}
|
||||||
|
peerDependencies:
|
||||||
|
eslint: '>=7.28.0'
|
||||||
|
eslint-config-prettier: '*'
|
||||||
|
prettier: '>=2.0.0'
|
||||||
|
peerDependenciesMeta:
|
||||||
|
eslint-config-prettier:
|
||||||
|
optional: true
|
||||||
|
dependencies:
|
||||||
|
eslint: 8.22.0
|
||||||
|
eslint-config-prettier: 8.5.0_eslint@8.22.0
|
||||||
|
prettier: 2.7.1
|
||||||
|
prettier-linter-helpers: 1.0.0
|
||||||
|
dev: true
|
||||||
|
|
||||||
/eslint-plugin-react-hooks/4.6.0_eslint@8.22.0:
|
/eslint-plugin-react-hooks/4.6.0_eslint@8.22.0:
|
||||||
resolution: {integrity: sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==}
|
resolution: {integrity: sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
@ -1123,6 +1268,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
|
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/fast-diff/1.2.0:
|
||||||
|
resolution: {integrity: sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==}
|
||||||
|
dev: true
|
||||||
|
|
||||||
/fast-glob/3.2.11:
|
/fast-glob/3.2.11:
|
||||||
resolution: {integrity: sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==}
|
resolution: {integrity: sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==}
|
||||||
engines: {node: '>=8.6.0'}
|
engines: {node: '>=8.6.0'}
|
||||||
@ -1931,6 +2080,19 @@ packages:
|
|||||||
engines: {node: '>= 0.8.0'}
|
engines: {node: '>= 0.8.0'}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/prettier-linter-helpers/1.0.0:
|
||||||
|
resolution: {integrity: sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==}
|
||||||
|
engines: {node: '>=6.0.0'}
|
||||||
|
dependencies:
|
||||||
|
fast-diff: 1.2.0
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/prettier/2.7.1:
|
||||||
|
resolution: {integrity: sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==}
|
||||||
|
engines: {node: '>=10.13.0'}
|
||||||
|
hasBin: true
|
||||||
|
dev: true
|
||||||
|
|
||||||
/prop-types/15.8.1:
|
/prop-types/15.8.1:
|
||||||
resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==}
|
resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==}
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -2,13 +2,13 @@ export default function Item({ bookmark }) {
|
|||||||
const { hostname } = new URL(bookmark.href);
|
const { hostname } = new URL(bookmark.href);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<li
|
<li key={bookmark.name}>
|
||||||
onClick={() => {
|
<button
|
||||||
window.open(bookmark.href, "_blank").focus();
|
type="button"
|
||||||
}}
|
onClick={() => window.open(bookmark.href, "_blank").focus()}
|
||||||
key={bookmark.name}
|
className="w-full text-left mb-3 cursor-pointer rounded-md font-medium text-theme-700 hover:text-theme-800 dark:text-theme-200 dark:hover:text-theme-300 shadow-md shadow-theme-900/10 dark:shadow-theme-900/50 bg-white/50 hover:bg-theme-300/10 dark:bg-white/5 dark:hover:bg-white/10"
|
||||||
className="mb-3 cursor-pointer flex rounded-md font-medium text-theme-700 hover:text-theme-800 dark:text-theme-200 dark:hover:text-theme-300 shadow-md shadow-theme-900/10 dark:shadow-theme-900/50 bg-white/50 hover:bg-theme-300/10 dark:bg-white/5 dark:hover:bg-white/10"
|
|
||||||
>
|
>
|
||||||
|
<div className="flex">
|
||||||
<div className="flex-shrink-0 flex items-center justify-center w-11 bg-theme-500/10 dark:bg-theme-900/50 text-theme-700 dark:text-theme-200 text-sm font-medium rounded-l-md">
|
<div className="flex-shrink-0 flex items-center justify-center w-11 bg-theme-500/10 dark:bg-theme-900/50 text-theme-700 dark:text-theme-200 text-sm font-medium rounded-l-md">
|
||||||
{bookmark.abbr}
|
{bookmark.abbr}
|
||||||
</div>
|
</div>
|
||||||
@ -16,6 +16,8 @@ export default function Item({ bookmark }) {
|
|||||||
<div className="flex-1 grow pl-3 py-2 text-xs">{bookmark.name}</div>
|
<div className="flex-1 grow pl-3 py-2 text-xs">{bookmark.name}</div>
|
||||||
<div className="px-2 py-2 truncate text-theme-500 dark:text-theme-400 opacity-50 text-xs">{hostname}</div>
|
<div className="px-2 py-2 truncate text-theme-500 dark:text-theme-400 opacity-50 text-xs">{hostname}</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
</li>
|
</li>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ import Item from "components/bookmarks/item";
|
|||||||
|
|
||||||
export default function List({ bookmarks }) {
|
export default function List({ bookmarks }) {
|
||||||
return (
|
return (
|
||||||
<ul role="list" className="mt-3 flex flex-col">
|
<ul className="mt-3 flex flex-col">
|
||||||
{bookmarks.map((bookmark) => (
|
{bookmarks.map((bookmark) => (
|
||||||
<Item key={bookmark.name} bookmark={bookmark} />
|
<Item key={bookmark.name} bookmark={bookmark} />
|
||||||
))}
|
))}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { useContext } from "react";
|
import { useContext, Fragment } from "react";
|
||||||
import { IoColorPalette } from "react-icons/io5";
|
import { IoColorPalette } from "react-icons/io5";
|
||||||
import { Popover, Transition } from "@headlessui/react";
|
import { Popover, Transition } from "@headlessui/react";
|
||||||
import { Fragment } from "react";
|
import classNames from "classnames";
|
||||||
|
|
||||||
import { ColorContext } from "utils/color-context";
|
import { ColorContext } from "utils/color-context";
|
||||||
|
|
||||||
@ -39,8 +39,6 @@ export default function ColorToggle() {
|
|||||||
return (
|
return (
|
||||||
<div className="w-full self-center">
|
<div className="w-full self-center">
|
||||||
<Popover className="relative flex items-center">
|
<Popover className="relative flex items-center">
|
||||||
{({ open }) => (
|
|
||||||
<>
|
|
||||||
<Popover.Button className="outline-none">
|
<Popover.Button className="outline-none">
|
||||||
<IoColorPalette
|
<IoColorPalette
|
||||||
className="h-5 w-5 text-theme-800 dark:text-theme-200 transition duration-150 ease-in-out"
|
className="h-5 w-5 text-theme-800 dark:text-theme-200 transition duration-150 ease-in-out"
|
||||||
@ -60,12 +58,12 @@ export default function ColorToggle() {
|
|||||||
<div className="rounded-md shadow-lg ring-1 ring-black ring-opacity-5">
|
<div className="rounded-md shadow-lg ring-1 ring-black ring-opacity-5">
|
||||||
<div className="relative grid gap-2 p-2 grid-cols-11 shadow-theme-900/10 dark:shadow-theme-900 rounded-md shadow-md">
|
<div className="relative grid gap-2 p-2 grid-cols-11 shadow-theme-900/10 dark:shadow-theme-900 rounded-md shadow-md">
|
||||||
{colors.map((color) => (
|
{colors.map((color) => (
|
||||||
<button role="button" onClick={() => setColor(color)} key={color}>
|
<button type="button" onClick={() => setColor(color)} key={color}>
|
||||||
<div
|
<div
|
||||||
className={
|
className={classNames(
|
||||||
(active == color ? "border-2" : "border-0") +
|
active === color ? "border-2" : "border-0",
|
||||||
` rounded-md w-5 h-5 border-black/50 dark:border-white/50 theme-${color} bg-theme-500`
|
`rounded-md w-5 h-5 border-black/50 dark:border-white/50 theme-${color} bg-theme-500`
|
||||||
}
|
)}
|
||||||
/>
|
/>
|
||||||
</button>
|
</button>
|
||||||
))}
|
))}
|
||||||
@ -73,8 +71,6 @@ export default function ColorToggle() {
|
|||||||
</div>
|
</div>
|
||||||
</Popover.Panel>
|
</Popover.Panel>
|
||||||
</Transition>
|
</Transition>
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</Popover>
|
</Popover>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
export default function Greeting() {
|
export default function Greeting() {
|
||||||
const name = process.env.NEXT_PUBLIC_DISPLAY_NAME;
|
|
||||||
const hour = new Date().getHours();
|
const hour = new Date().getHours();
|
||||||
|
|
||||||
let day = "day";
|
let day = "day";
|
||||||
@ -12,9 +11,5 @@ export default function Greeting() {
|
|||||||
day = "evening";
|
day = "evening";
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return <div className="self-end grow text-2xl font-thin text-theme-800 dark:text-theme-200">Good {day}</div>;
|
||||||
<div className="self-end grow text-2xl font-thin text-theme-800 dark:text-theme-200">
|
|
||||||
Good {day}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
@ -1,68 +0,0 @@
|
|||||||
import { Fragment, useRef, useState, Children } from "react";
|
|
||||||
import { Dialog, Transition } from "@headlessui/react";
|
|
||||||
|
|
||||||
function classNames(...classes) {
|
|
||||||
return classes.filter(Boolean).join(" ");
|
|
||||||
}
|
|
||||||
|
|
||||||
const Modal = ({ Toggle, Content }) => {
|
|
||||||
const [open, setOpen] = useState(false);
|
|
||||||
const cancelButtonRef = useRef(null);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Toggle open={open} setOpen={setOpen} />
|
|
||||||
<Transition.Root show={open} as={Fragment}>
|
|
||||||
<Dialog
|
|
||||||
as="div"
|
|
||||||
className="relative z-10"
|
|
||||||
initialFocus={cancelButtonRef}
|
|
||||||
onClose={setOpen}
|
|
||||||
>
|
|
||||||
<Transition.Child
|
|
||||||
as={Fragment}
|
|
||||||
enter="ease-out duration-300"
|
|
||||||
enterFrom="opacity-0"
|
|
||||||
enterTo="opacity-100"
|
|
||||||
leave="ease-in duration-200"
|
|
||||||
leaveFrom="opacity-100"
|
|
||||||
leaveTo="opacity-0"
|
|
||||||
>
|
|
||||||
<div className="fixed inset-0 bg-theme-900/90 transition-opacity" />
|
|
||||||
</Transition.Child>
|
|
||||||
|
|
||||||
<div className="fixed z-10 inset-0 overflow-y-auto">
|
|
||||||
<div className="flex items-center justify-center min-h-full">
|
|
||||||
<Transition.Child
|
|
||||||
as={Fragment}
|
|
||||||
enter="ease-out duration-300"
|
|
||||||
enterFrom="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
|
||||||
enterTo="opacity-100 translate-y-0 sm:scale-100"
|
|
||||||
leave="ease-in duration-200"
|
|
||||||
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
|
|
||||||
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
|
||||||
>
|
|
||||||
<Dialog.Panel className="relative rounded-lg shadow-xl transform transition-all my-8 max-w-lg w-full">
|
|
||||||
<Content open={open} setOpen={setOpen} />
|
|
||||||
</Dialog.Panel>
|
|
||||||
</Transition.Child>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</Dialog>
|
|
||||||
</Transition.Root>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const ModalToggle = ({ open, setOpen, children }) => (
|
|
||||||
<div onClick={() => setOpen(!open)}>{children}</div>
|
|
||||||
);
|
|
||||||
|
|
||||||
const ModalContent = ({ open, setOpen, children }) => (
|
|
||||||
<div className="body">{children}</div>
|
|
||||||
);
|
|
||||||
|
|
||||||
Modal.Toggle = ModalToggle;
|
|
||||||
Modal.Content = ModalContent;
|
|
||||||
|
|
||||||
export default Modal;
|
|
@ -8,28 +8,32 @@ import Docker from "./widgets/service/docker";
|
|||||||
function resolveIcon(icon) {
|
function resolveIcon(icon) {
|
||||||
if (icon.startsWith("http")) {
|
if (icon.startsWith("http")) {
|
||||||
return `/api/proxy?url=${encodeURIComponent(icon)}`;
|
return `/api/proxy?url=${encodeURIComponent(icon)}`;
|
||||||
} else if (icon.startsWith("/")) {
|
}
|
||||||
|
|
||||||
|
if (icon.startsWith("/")) {
|
||||||
return icon;
|
return icon;
|
||||||
} else {
|
}
|
||||||
|
|
||||||
if (icon.endsWith(".png")) {
|
if (icon.endsWith(".png")) {
|
||||||
return `https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons/png/${icon}`;
|
return `https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons/png/${icon}`;
|
||||||
} else {
|
}
|
||||||
|
|
||||||
return `https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons/png/${icon}.png`;
|
return `https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons/png/${icon}.png`;
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Item({ service }) {
|
export default function Item({ service }) {
|
||||||
return (
|
return (
|
||||||
<li key={service.name}>
|
<li key={service.name}>
|
||||||
<Disclosure>
|
<Disclosure>
|
||||||
<div className={
|
<div
|
||||||
(service.href && service.href !== "#" ? 'cursor-pointer ' : 'cursor-default ') +
|
className={`${
|
||||||
'transition-all h-15 overflow-hidden mb-3 p-1 rounded-md font-medium text-theme-700 hover:text-theme-800 dark:text-theme-200 dark:hover:text-theme-300 shadow-md shadow-theme-900/10 dark:shadow-theme-900/40 bg-white/50 hover:bg-theme-300/10 dark:bg-white/5 dark:hover:bg-white/10'
|
service.href && service.href !== "#" ? "cursor-pointer " : "cursor-default "
|
||||||
}>
|
}transition-all h-15 overflow-hidden mb-3 p-1 rounded-md font-medium text-theme-700 hover:text-theme-800 dark:text-theme-200 dark:hover:text-theme-300 shadow-md shadow-theme-900/10 dark:shadow-theme-900/40 bg-white/50 hover:bg-theme-300/10 dark:bg-white/5 dark:hover:bg-white/10`}
|
||||||
|
>
|
||||||
<div className="flex">
|
<div className="flex">
|
||||||
{service.icon && (
|
{service.icon && (
|
||||||
<div
|
<button
|
||||||
|
type="button"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (service.href && service.href !== "#") {
|
if (service.href && service.href !== "#") {
|
||||||
window.open(service.href, "_blank").focus();
|
window.open(service.href, "_blank").focus();
|
||||||
@ -38,10 +42,11 @@ export default function Item({ service }) {
|
|||||||
className="flex-shrink-0 flex items-center justify-center w-12 "
|
className="flex-shrink-0 flex items-center justify-center w-12 "
|
||||||
>
|
>
|
||||||
<Image src={resolveIcon(service.icon)} width={32} height={32} alt="logo" />
|
<Image src={resolveIcon(service.icon)} width={32} height={32} alt="logo" />
|
||||||
</div>
|
</button>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div
|
<button
|
||||||
|
type="button"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (service.href && service.href !== "#") {
|
if (service.href && service.href !== "#") {
|
||||||
window.open(service.href, "_blank").focus();
|
window.open(service.href, "_blank").focus();
|
||||||
@ -53,9 +58,12 @@ export default function Item({ service }) {
|
|||||||
{service.name}
|
{service.name}
|
||||||
<p className="text-theme-500 dark:text-theme-400 text-xs font-extralight">{service.description}</p>
|
<p className="text-theme-500 dark:text-theme-400 text-xs font-extralight">{service.description}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</button>
|
||||||
{service.container && (
|
{service.container && (
|
||||||
<Disclosure.Button as="div" className="flex-shrink-0 flex items-center justify-center w-12 cursor-pointer">
|
<Disclosure.Button
|
||||||
|
as="div"
|
||||||
|
className="flex-shrink-0 flex items-center justify-center w-12 cursor-pointer"
|
||||||
|
>
|
||||||
<Status service={service} />
|
<Status service={service} />
|
||||||
</Disclosure.Button>
|
</Disclosure.Button>
|
||||||
)}
|
)}
|
||||||
|
@ -2,7 +2,7 @@ import Item from "components/services/item";
|
|||||||
|
|
||||||
export default function List({ services }) {
|
export default function List({ services }) {
|
||||||
return (
|
return (
|
||||||
<ul role="list" className="mt-3 flex flex-col">
|
<ul className="mt-3 flex flex-col">
|
||||||
{services.map((service) => (
|
{services.map((service) => (
|
||||||
<Item key={service.name} service={service} />
|
<Item key={service.name} service={service} />
|
||||||
))}
|
))}
|
||||||
|
@ -1,28 +1,18 @@
|
|||||||
import useSWR from "swr";
|
import useSWR from "swr";
|
||||||
|
|
||||||
export default function Status({ service }) {
|
export default function Status({ service }) {
|
||||||
const { data, error } = useSWR(
|
const { data, error } = useSWR(`/api/docker/status/${service.container}/${service.server || ""}`);
|
||||||
`/api/docker/status/${service.container}/${service.server || ""}`
|
|
||||||
);
|
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
return (
|
return <div className="w-3 h-3 bg-rose-300 dark:bg-rose-500 rounded-full" />;
|
||||||
<div className="w-3 h-3 bg-rose-300 dark:bg-rose-500 rounded-full" />
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data && data.status === "running") {
|
if (data && data.status === "running") {
|
||||||
return (
|
return <div className="w-3 h-3 bg-emerald-300 dark:bg-emerald-500 rounded-full" />;
|
||||||
<div className="w-3 h-3 bg-emerald-300 dark:bg-emerald-500 rounded-full" />
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data && data.status === "not found") {
|
if (data && data.status === "not found") {
|
||||||
return (
|
return <div className="h-2.5 w-2.5 bg-orange-400/50 dark:bg-yellow-200/40 -rotate-45" />;
|
||||||
<>
|
|
||||||
<div className="h-2.5 w-2.5 bg-orange-400/50 dark:bg-yellow-200/40 -rotate-45"></div>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return <div className="w-3 h-3 bg-black/20 dark:bg-white/40 rounded-full" />;
|
return <div className="w-3 h-3 bg-black/20 dark:bg-white/40 rounded-full" />;
|
||||||
|
@ -24,9 +24,9 @@ export default function Emby({ service, title = "Emby" }) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const playing = sessionsData.filter((session) => session.hasOwnProperty("NowPlayingItem"));
|
const playing = sessionsData.filter((session) => session?.NowPlayingItem);
|
||||||
const transcoding = sessionsData.filter(
|
const transcoding = sessionsData.filter(
|
||||||
(session) => session.hasOwnProperty("PlayState") && session.PlayState.PlayMethod === "Transcode"
|
(session) => session?.PlayState && session.PlayState.PlayMethod === "Transcode"
|
||||||
);
|
);
|
||||||
const bitrate = playing.reduce((acc, session) => acc + session.NowPlayingItem.Bitrate, 0);
|
const bitrate = playing.reduce((acc, session) => acc + session.NowPlayingItem.Bitrate, 0);
|
||||||
|
|
||||||
|
@ -25,13 +25,9 @@ export default function Rutorrent({ service }) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const upload = statusData.reduce((acc, torrent) => {
|
const upload = statusData.reduce((acc, torrent) => acc + parseInt(torrent["d.get_up_rate"], 10), 0);
|
||||||
return acc + parseInt(torrent["d.get_up_rate"]);
|
|
||||||
}, 0);
|
|
||||||
|
|
||||||
const download = statusData.reduce((acc, torrent) => {
|
const download = statusData.reduce((acc, torrent) => acc + parseInt(torrent["d.get_down_rate"], 10), 0);
|
||||||
return acc + parseInt(torrent["d.get_down_rate"]);
|
|
||||||
}, 0);
|
|
||||||
|
|
||||||
const active = statusData.filter((torrent) => torrent["d.get_state"] === "1");
|
const active = statusData.filter((torrent) => torrent["d.get_state"] === "1");
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ export default function Tautulli({ service }) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = statsData.response.data;
|
const { data } = statsData.response;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Widget>
|
<Widget>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import mapIcon from "utils/owm-condition-map";
|
import mapIcon from "utils/owm-condition-map";
|
||||||
|
|
||||||
export default function Icon({ condition, timeOfDay }) {
|
export default function Icon({ condition, timeOfDay }) {
|
||||||
const Icon = mapIcon(condition, timeOfDay);
|
const IconComponent = mapIcon(condition, timeOfDay);
|
||||||
|
|
||||||
return <Icon className="w-10 h-10 text-theme-800 dark:text-theme-200"></Icon>;
|
return <IconComponent className="w-10 h-10 text-theme-800 dark:text-theme-200" />;
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ import Icon from "./icon";
|
|||||||
export default function OpenWeatherMap({ options }) {
|
export default function OpenWeatherMap({ options }) {
|
||||||
const { data, error } = useSWR(`/api/widgets/openweathermap?${new URLSearchParams(options).toString()}`);
|
const { data, error } = useSWR(`/api/widgets/openweathermap?${new URLSearchParams(options).toString()}`);
|
||||||
|
|
||||||
if (error || data?.cod == 401) {
|
if (error || data?.cod === 401) {
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col">
|
<div className="flex flex-col">
|
||||||
<div className="flex flex-row items-center justify-end">
|
<div className="flex flex-row items-center justify-end">
|
||||||
@ -23,11 +23,11 @@ export default function OpenWeatherMap({ options }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!data) {
|
if (!data) {
|
||||||
return <div className="flex flex-row items-center"></div>;
|
return <div className="flex flex-row items-center" />;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data.error) {
|
if (data.error) {
|
||||||
return <div className="flex flex-row items-center"></div>;
|
return <div className="flex flex-row items-center" />;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import useSWR from "swr";
|
import useSWR from "swr";
|
||||||
import { FiHardDrive } from "react-icons/fi";
|
import { FiHardDrive } from "react-icons/fi";
|
||||||
import { BiError } from "react-icons/bi";
|
import { BiError } from "react-icons/bi";
|
||||||
|
|
||||||
import { formatBytes } from "utils/stats-helpers";
|
import { formatBytes } from "utils/stats-helpers";
|
||||||
|
|
||||||
export default function Disk({ options }) {
|
export default function Disk({ options }) {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import useSWR from "swr";
|
import useSWR from "swr";
|
||||||
import { FaMemory } from "react-icons/fa";
|
import { FaMemory } from "react-icons/fa";
|
||||||
import { BiError } from "react-icons/bi";
|
import { BiError } from "react-icons/bi";
|
||||||
|
|
||||||
import { formatBytes } from "utils/stats-helpers";
|
import { formatBytes } from "utils/stats-helpers";
|
||||||
|
|
||||||
export default function Memory() {
|
export default function Memory() {
|
||||||
|
@ -4,7 +4,6 @@ import Memory from "./memory";
|
|||||||
|
|
||||||
export default function Resources({ options }) {
|
export default function Resources({ options }) {
|
||||||
return (
|
return (
|
||||||
<>
|
|
||||||
<div className="flex flex-col max-w:full basis-1/2 sm:basis-auto self-center">
|
<div className="flex flex-col max-w:full basis-1/2 sm:basis-auto self-center">
|
||||||
<div className="flex flex-row space-x-4 self-center">
|
<div className="flex flex-row space-x-4 self-center">
|
||||||
{options.cpu && <Cpu />}
|
{options.cpu && <Cpu />}
|
||||||
@ -17,6 +16,5 @@ export default function Resources({ options }) {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,7 @@ export default function Search({ options }) {
|
|||||||
const [query, setQuery] = useState("");
|
const [query, setQuery] = useState("");
|
||||||
|
|
||||||
if (!provider) {
|
if (!provider) {
|
||||||
return <></>;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleSubmit(event) {
|
function handleSubmit(event) {
|
||||||
@ -49,11 +49,10 @@ export default function Search({ options }) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<form className="flex-col relative h-8 my-4 min-w-full md:min-w-fit grow" onSubmit={handleSubmit}>
|
<form className="flex-col relative h-8 my-4 min-w-full md:min-w-fit grow" onSubmit={handleSubmit}>
|
||||||
<div className="flex absolute inset-y-0 left-0 items-center pl-3 pointer-events-none w-full text-theme-800 dark:text-theme-200"></div>
|
<div className="flex absolute inset-y-0 left-0 items-center pl-3 pointer-events-none w-full text-theme-800 dark:text-theme-200" />
|
||||||
<input
|
<input
|
||||||
type="search"
|
type="search"
|
||||||
autoFocus
|
className="overflow-hidden w-full placeholder-theme-900 text-xs text-theme-900 bg-theme-50 rounded-md border border-theme-300 focus:ring-theme-500 focus:border-theme-500 dark:bg-theme-800 dark:border-theme-600 dark:placeholder-theme-400 dark:text-white dark:focus:ring-theme-500 dark:focus:border-theme-500 h-full"
|
||||||
className={`overflow-hidden w-full placeholder-theme-900 text-xs text-theme-900 bg-theme-50 rounded-md border border-theme-300 focus:ring-theme-500 focus:border-theme-500 dark:bg-theme-800 dark:border-theme-600 dark:placeholder-theme-400 dark:text-white dark:focus:ring-theme-500 dark:focus:border-theme-500 h-full`}
|
|
||||||
placeholder="Search..."
|
placeholder="Search..."
|
||||||
onChange={(s) => setQuery(s.currentTarget.value)}
|
onChange={(s) => setQuery(s.currentTarget.value)}
|
||||||
required
|
required
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import mapIcon from "utils/condition-map";
|
import mapIcon from "utils/condition-map";
|
||||||
|
|
||||||
export default function Icon({ condition, timeOfDay }) {
|
export default function Icon({ condition, timeOfDay }) {
|
||||||
const Icon = mapIcon(condition, timeOfDay);
|
const IconComponent = mapIcon(condition, timeOfDay);
|
||||||
|
|
||||||
return <Icon className="w-10 h-10 text-theme-800 dark:text-theme-200"></Icon>;
|
return <IconComponent className="w-10 h-10 text-theme-800 dark:text-theme-200" />;
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,6 @@ import { BiError } from "react-icons/bi";
|
|||||||
import Icon from "./icon";
|
import Icon from "./icon";
|
||||||
|
|
||||||
export default function WeatherApi({ options }) {
|
export default function WeatherApi({ options }) {
|
||||||
console.log(options);
|
|
||||||
const { data, error } = useSWR(`/api/widgets/weather?${new URLSearchParams(options).toString()}`);
|
const { data, error } = useSWR(`/api/widgets/weather?${new URLSearchParams(options).toString()}`);
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
@ -24,11 +23,11 @@ export default function WeatherApi({ options }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!data) {
|
if (!data) {
|
||||||
return <div className="flex flex-row items-center justify-end"></div>;
|
return <div className="flex flex-row items-center justify-end" />;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data.error) {
|
if (data.error) {
|
||||||
return <div className="flex flex-row items-center justify-end"></div>;
|
return <div className="flex flex-row items-center justify-end" />;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
/* eslint-disable react/jsx-props-no-spreading */
|
||||||
import { SWRConfig } from "swr";
|
import { SWRConfig } from "swr";
|
||||||
import "styles/globals.css";
|
import "styles/globals.css";
|
||||||
import "styles/weather-icons.css";
|
import "styles/weather-icons.css";
|
@ -1,6 +1,8 @@
|
|||||||
import { promises as fs } from "fs";
|
import { promises as fs } from "fs";
|
||||||
import path from "path";
|
import path from "path";
|
||||||
|
|
||||||
import yaml from "js-yaml";
|
import yaml from "js-yaml";
|
||||||
|
|
||||||
import checkAndCopyConfig from "utils/config";
|
import checkAndCopyConfig from "utils/config";
|
||||||
|
|
||||||
export default async function handler(req, res) {
|
export default async function handler(req, res) {
|
||||||
@ -11,17 +13,13 @@ export default async function handler(req, res) {
|
|||||||
const bookmarks = yaml.load(fileContents);
|
const bookmarks = yaml.load(fileContents);
|
||||||
|
|
||||||
// map easy to write YAML objects into easy to consume JS arrays
|
// map easy to write YAML objects into easy to consume JS arrays
|
||||||
const bookmarksArray = bookmarks.map((group) => {
|
const bookmarksArray = bookmarks.map((group) => ({
|
||||||
return {
|
|
||||||
name: Object.keys(group)[0],
|
name: Object.keys(group)[0],
|
||||||
bookmarks: group[Object.keys(group)[0]].map((entries) => {
|
bookmarks: group[Object.keys(group)[0]].map((entries) => ({
|
||||||
return {
|
|
||||||
name: Object.keys(entries)[0],
|
name: Object.keys(entries)[0],
|
||||||
...entries[Object.keys(entries)[0]][0],
|
...entries[Object.keys(entries)[0]][0],
|
||||||
};
|
})),
|
||||||
}),
|
}));
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
res.send(bookmarksArray);
|
res.send(bookmarksArray);
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import Docker from "dockerode";
|
import Docker from "dockerode";
|
||||||
|
|
||||||
import getDockerArguments from "utils/docker";
|
import getDockerArguments from "utils/docker";
|
||||||
|
|
||||||
export default async function handler(req, res) {
|
export default async function handler(req, res) {
|
||||||
@ -21,30 +22,30 @@ export default async function handler(req, res) {
|
|||||||
// bad docker connections can result in a <Buffer ...> object?
|
// bad docker connections can result in a <Buffer ...> object?
|
||||||
// in any case, this ensures the result is the expected array
|
// in any case, this ensures the result is the expected array
|
||||||
if (!Array.isArray(containers)) {
|
if (!Array.isArray(containers)) {
|
||||||
return res.status(500).send({
|
res.status(500).send({
|
||||||
error: "query failed",
|
error: "query failed",
|
||||||
});
|
});
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const containerNames = containers.map((container) => {
|
const containerNames = containers.map((container) => container.Names[0].replace(/^\//, ""));
|
||||||
return container.Names[0].replace(/^\//, "");
|
|
||||||
});
|
|
||||||
const containerExists = containerNames.includes(containerName);
|
const containerExists = containerNames.includes(containerName);
|
||||||
|
|
||||||
if (!containerExists) {
|
if (!containerExists) {
|
||||||
return res.status(200).send({
|
res.status(200).send({
|
||||||
error: "not found",
|
error: "not found",
|
||||||
});
|
});
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const container = docker.getContainer(containerName);
|
const container = docker.getContainer(containerName);
|
||||||
const stats = await container.stats({ stream: false });
|
const stats = await container.stats({ stream: false });
|
||||||
|
|
||||||
return res.status(200).json({
|
res.status(200).json({
|
||||||
stats: stats,
|
stats,
|
||||||
});
|
});
|
||||||
} catch {
|
} catch {
|
||||||
return res.status(500).send({
|
res.status(500).send({
|
||||||
error: "unknown error",
|
error: "unknown error",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import Docker from "dockerode";
|
import Docker from "dockerode";
|
||||||
|
|
||||||
import getDockerArguments from "utils/docker";
|
import getDockerArguments from "utils/docker";
|
||||||
|
|
||||||
export default async function handler(req, res) {
|
export default async function handler(req, res) {
|
||||||
@ -25,9 +26,7 @@ export default async function handler(req, res) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const containerNames = containers.map((container) => {
|
const containerNames = containers.map((container) => container.Names[0].replace(/^\//, ""));
|
||||||
return container.Names[0].replace(/^\//, "");
|
|
||||||
});
|
|
||||||
const containerExists = containerNames.includes(containerName);
|
const containerExists = containerNames.includes(containerName);
|
||||||
|
|
||||||
if (!containerExists) {
|
if (!containerExists) {
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import https from "https";
|
import https from "https";
|
||||||
|
|
||||||
import getRawBody from "raw-body";
|
import getRawBody from "raw-body";
|
||||||
|
|
||||||
import { httpRequest, httpsRequest } from "utils/http";
|
import { httpRequest, httpsRequest } from "utils/http";
|
||||||
@ -11,7 +12,8 @@ export const config = {
|
|||||||
|
|
||||||
export default async function handler(req, res) {
|
export default async function handler(req, res) {
|
||||||
const headers = ["X-API-Key", "Authorization"].reduce((obj, key) => {
|
const headers = ["X-API-Key", "Authorization"].reduce((obj, key) => {
|
||||||
if (req.headers && req.headers.hasOwnProperty(key.toLowerCase())) {
|
if (req.headers && Object.prototype.hasOwnProperty.call(req.headers, key.toLowerCase())) {
|
||||||
|
// eslint-disable-next-line no-param-reassign
|
||||||
obj[key] = req.headers[key.toLowerCase()];
|
obj[key] = req.headers[key.toLowerCase()];
|
||||||
}
|
}
|
||||||
return obj;
|
return obj;
|
||||||
@ -29,23 +31,9 @@ export default async function handler(req, res) {
|
|||||||
const [status, contentType, data] = await httpsRequest(url, {
|
const [status, contentType, data] = await httpsRequest(url, {
|
||||||
agent: httpsAgent,
|
agent: httpsAgent,
|
||||||
method: req.method,
|
method: req.method,
|
||||||
headers: headers,
|
headers,
|
||||||
body:
|
body:
|
||||||
req.method == "GET" || req.method == "HEAD"
|
req.method === "GET" || req.method === "HEAD"
|
||||||
? null
|
|
||||||
: await getRawBody(req, {
|
|
||||||
encoding: "utf8",
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
|
|
||||||
res.setHeader("Content-Type", contentType);
|
|
||||||
return res.status(status).send(data);
|
|
||||||
} else {
|
|
||||||
const [status, contentType, data] = await httpRequest(url, {
|
|
||||||
method: req.method,
|
|
||||||
headers: headers,
|
|
||||||
body:
|
|
||||||
req.method == "GET" || req.method == "HEAD"
|
|
||||||
? null
|
? null
|
||||||
: await getRawBody(req, {
|
: await getRawBody(req, {
|
||||||
encoding: "utf8",
|
encoding: "utf8",
|
||||||
@ -55,4 +43,17 @@ export default async function handler(req, res) {
|
|||||||
res.setHeader("Content-Type", contentType);
|
res.setHeader("Content-Type", contentType);
|
||||||
return res.status(status).send(data);
|
return res.status(status).send(data);
|
||||||
}
|
}
|
||||||
|
const [status, contentType, data] = await httpRequest(url, {
|
||||||
|
method: req.method,
|
||||||
|
headers,
|
||||||
|
body:
|
||||||
|
req.method === "GET" || req.method === "HEAD"
|
||||||
|
? null
|
||||||
|
: await getRawBody(req, {
|
||||||
|
encoding: "utf8",
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
res.setHeader("Content-Type", contentType);
|
||||||
|
return res.status(status).send(data);
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
import { promises as fs } from "fs";
|
import { promises as fs } from "fs";
|
||||||
import path from "path";
|
import path from "path";
|
||||||
|
|
||||||
import yaml from "js-yaml";
|
import yaml from "js-yaml";
|
||||||
|
|
||||||
import checkAndCopyConfig from "utils/config";
|
import checkAndCopyConfig from "utils/config";
|
||||||
|
|
||||||
export default async function handler(req, res) {
|
export default async function handler(req, res) {
|
||||||
@ -11,12 +13,11 @@ export default async function handler(req, res) {
|
|||||||
const services = yaml.load(fileContents);
|
const services = yaml.load(fileContents);
|
||||||
|
|
||||||
// map easy to write YAML objects into easy to consume JS arrays
|
// map easy to write YAML objects into easy to consume JS arrays
|
||||||
const servicesArray = services.map((group) => {
|
const servicesArray = services.map((group) => ({
|
||||||
return {
|
|
||||||
name: Object.keys(group)[0],
|
name: Object.keys(group)[0],
|
||||||
services: group[Object.keys(group)[0]].map((entries) => {
|
services: group[Object.keys(group)[0]].map((entries) => {
|
||||||
const { widget, ...service } = entries[Object.keys(entries)[0]];
|
const { widget, ...service } = entries[Object.keys(entries)[0]];
|
||||||
let res = {
|
const result = {
|
||||||
name: Object.keys(entries)[0],
|
name: Object.keys(entries)[0],
|
||||||
...service,
|
...service,
|
||||||
};
|
};
|
||||||
@ -24,17 +25,16 @@ export default async function handler(req, res) {
|
|||||||
if (widget) {
|
if (widget) {
|
||||||
const { type } = widget;
|
const { type } = widget;
|
||||||
|
|
||||||
res.widget = {
|
result.widget = {
|
||||||
type: type,
|
type,
|
||||||
service_group: Object.keys(group)[0],
|
service_group: Object.keys(group)[0],
|
||||||
service_name: Object.keys(entries)[0],
|
service_name: Object.keys(entries)[0],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return result;
|
||||||
}),
|
}),
|
||||||
};
|
}));
|
||||||
});
|
|
||||||
|
|
||||||
res.send(servicesArray);
|
res.send(servicesArray);
|
||||||
}
|
}
|
||||||
|
@ -33,5 +33,5 @@ export default async function handler(req, res) {
|
|||||||
return serviceProxyHandler(req, res);
|
return serviceProxyHandler(req, res);
|
||||||
}
|
}
|
||||||
|
|
||||||
res.status(403).json({ error: "Unkown proxy service type" });
|
return res.status(403).json({ error: "Unkown proxy service type" });
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
import { promises as fs } from "fs";
|
import { promises as fs } from "fs";
|
||||||
import path from "path";
|
import path from "path";
|
||||||
|
|
||||||
import yaml from "js-yaml";
|
import yaml from "js-yaml";
|
||||||
|
|
||||||
import checkAndCopyConfig from "utils/config";
|
import checkAndCopyConfig from "utils/config";
|
||||||
|
|
||||||
export default async function handler(req, res) {
|
export default async function handler(req, res) {
|
||||||
@ -11,12 +13,10 @@ export default async function handler(req, res) {
|
|||||||
const widgets = yaml.load(fileContents);
|
const widgets = yaml.load(fileContents);
|
||||||
|
|
||||||
// map easy to write YAML objects into easy to consume JS arrays
|
// map easy to write YAML objects into easy to consume JS arrays
|
||||||
const widgetsArray = widgets.map((group) => {
|
const widgetsArray = widgets.map((group) => ({
|
||||||
return {
|
|
||||||
type: Object.keys(group)[0],
|
type: Object.keys(group)[0],
|
||||||
options: { ...group[Object.keys(group)[0]] },
|
options: { ...group[Object.keys(group)[0]] },
|
||||||
};
|
}));
|
||||||
});
|
|
||||||
|
|
||||||
res.send(widgetsArray);
|
res.send(widgetsArray);
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,7 @@ export default async function handler(req, res) {
|
|||||||
return res.status(400).json({ error: "Missing API key" });
|
return res.status(400).json({ error: "Missing API key" });
|
||||||
}
|
}
|
||||||
|
|
||||||
const api_url = `https://api.openweathermap.org/data/2.5/weather?lat=${latitude}&lon=${longitude}&appid=${apiKey}&units=${units}`;
|
const apiUrl = `https://api.openweathermap.org/data/2.5/weather?lat=${latitude}&lon=${longitude}&appid=${apiKey}&units=${units}`;
|
||||||
|
|
||||||
res.send(await cachedFetch(api_url, cache));
|
return res.send(await cachedFetch(apiUrl, cache));
|
||||||
}
|
}
|
||||||
|
@ -1,26 +1,30 @@
|
|||||||
import { cpu, drive, mem, netstat } from "node-os-utils";
|
import { cpu, drive, mem } from "node-os-utils";
|
||||||
|
|
||||||
export default async function handler(req, res) {
|
export default async function handler(req, res) {
|
||||||
const { type, target } = req.query;
|
const { type, target } = req.query;
|
||||||
|
|
||||||
if (type == "cpu") {
|
if (type === "cpu") {
|
||||||
return res.status(200).json({
|
return res.status(200).json({
|
||||||
cpu: {
|
cpu: {
|
||||||
usage: await cpu.usage(1000),
|
usage: await cpu.usage(1000),
|
||||||
load: cpu.loadavgTime(5),
|
load: cpu.loadavgTime(5),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
} else if (type == "disk") {
|
}
|
||||||
|
|
||||||
|
if (type === "disk") {
|
||||||
return res.status(200).json({
|
return res.status(200).json({
|
||||||
drive: await drive.info(target || "/"),
|
drive: await drive.info(target || "/"),
|
||||||
});
|
});
|
||||||
} else if (type == "memory") {
|
}
|
||||||
|
|
||||||
|
if (type === "memory") {
|
||||||
return res.status(200).json({
|
return res.status(200).json({
|
||||||
memory: await mem.info(),
|
memory: await mem.info(),
|
||||||
});
|
});
|
||||||
} else {
|
}
|
||||||
|
|
||||||
return res.status(400).json({
|
return res.status(400).json({
|
||||||
error: "invalid type",
|
error: "invalid type",
|
||||||
});
|
});
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,7 @@ export default async function handler(req, res) {
|
|||||||
return res.status(400).json({ error: "Missing API key" });
|
return res.status(400).json({ error: "Missing API key" });
|
||||||
}
|
}
|
||||||
|
|
||||||
const api_url = `http://api.weatherapi.com/v1/current.json?q=${latitude},${longitude}&key=${apiKey}`;
|
const apiUrl = `http://api.weatherapi.com/v1/current.json?q=${latitude},${longitude}&key=${apiKey}`;
|
||||||
|
|
||||||
res.send(await cachedFetch(api_url, cache));
|
return res.send(await cachedFetch(apiUrl, cache));
|
||||||
}
|
}
|
||||||
|
@ -2,13 +2,11 @@ import useSWR from "swr";
|
|||||||
import Head from "next/head";
|
import Head from "next/head";
|
||||||
import dynamic from "next/dynamic";
|
import dynamic from "next/dynamic";
|
||||||
|
|
||||||
import { ThemeProvider } from "utils/theme-context";
|
|
||||||
|
|
||||||
import ServicesGroup from "components/services/group";
|
import ServicesGroup from "components/services/group";
|
||||||
import BookmarksGroup from "components/bookmarks/group";
|
import BookmarksGroup from "components/bookmarks/group";
|
||||||
import Widget from "components/widget";
|
import Widget from "components/widget";
|
||||||
import { ColorProvider } from "utils/color-context";
|
import { ColorProvider } from "utils/color-context";
|
||||||
import Search from "components/widgets/search/search";
|
import { ThemeProvider } from "utils/theme-context";
|
||||||
|
|
||||||
const ThemeToggle = dynamic(() => import("components/theme-toggle"), {
|
const ThemeToggle = dynamic(() => import("components/theme-toggle"), {
|
||||||
ssr: false,
|
ssr: false,
|
||||||
@ -19,12 +17,11 @@ const ColorToggle = dynamic(() => import("components/color-toggle"), {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const rightAlignedWidgets = ["weatherapi", "openweathermap", "weather", "search"];
|
const rightAlignedWidgets = ["weatherapi", "openweathermap", "weather", "search"];
|
||||||
const expandedWidgets = ["search"];
|
|
||||||
|
|
||||||
export default function Home() {
|
export default function Home() {
|
||||||
const { data: services, error: servicesError } = useSWR("/api/services");
|
const { data: services } = useSWR("/api/services");
|
||||||
const { data: bookmarks, error: bookmarksError } = useSWR("/api/bookmarks");
|
const { data: bookmarks } = useSWR("/api/bookmarks");
|
||||||
const { data: widgets, error: widgetsError } = useSWR("/api/widgets");
|
const { data: widgets } = useSWR("/api/widgets");
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ColorProvider>
|
<ColorProvider>
|
||||||
@ -38,15 +35,15 @@ export default function Home() {
|
|||||||
<>
|
<>
|
||||||
{widgets
|
{widgets
|
||||||
.filter((widget) => !rightAlignedWidgets.includes(widget.type))
|
.filter((widget) => !rightAlignedWidgets.includes(widget.type))
|
||||||
.map((widget, i) => (
|
.map((widget) => (
|
||||||
<Widget key={i} widget={widget} />
|
<Widget key={widget} widget={widget} />
|
||||||
))}
|
))}
|
||||||
|
|
||||||
<div className="flex flex-wrap basis-full space-x-0 sm:space-x-4 grow sm:basis-auto justify-between md:justify-end mt-2 md:mt-0">
|
<div className="flex flex-wrap basis-full space-x-0 sm:space-x-4 grow sm:basis-auto justify-between md:justify-end mt-2 md:mt-0">
|
||||||
{widgets
|
{widgets
|
||||||
.filter((widget) => rightAlignedWidgets.includes(widget.type))
|
.filter((widget) => rightAlignedWidgets.includes(widget.type))
|
||||||
.map((widget, i) => (
|
.map((widget) => (
|
||||||
<Widget key={i} widget={widget} />
|
<Widget key={widget} widget={widget} />
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
@ -15,13 +15,13 @@ const formats = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export function formatApiCall(api, args) {
|
export function formatApiCall(api, args) {
|
||||||
const match = /\{.*?\}/g;
|
const find = /\{.*?\}/g;
|
||||||
const replace = (match) => {
|
const replace = (match) => {
|
||||||
const key = match.replace(/\{|\}/g, "");
|
const key = match.replace(/\{|\}/g, "");
|
||||||
return args[key];
|
return args[key];
|
||||||
};
|
};
|
||||||
|
|
||||||
return formats[api].replace(match, replace);
|
return formats[api].replace(find, replace);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function formatApiUrl(widget, endpoint) {
|
export function formatApiUrl(widget, endpoint) {
|
||||||
|
@ -5,9 +5,9 @@ export default async function cachedFetch(url, duration) {
|
|||||||
|
|
||||||
if (cached) {
|
if (cached) {
|
||||||
return cached;
|
return cached;
|
||||||
} else {
|
}
|
||||||
|
|
||||||
const data = await fetch(url).then((res) => res.json());
|
const data = await fetch(url).then((res) => res.json());
|
||||||
cache.put(url, data, duration * 1000 * 60);
|
cache.put(url, data, duration * 1000 * 60);
|
||||||
return data;
|
return data;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { createContext, useState, useEffect } from "react";
|
import { createContext, useState, useEffect, useMemo } from "react";
|
||||||
|
|
||||||
let lastColor = false;
|
let lastColor = false;
|
||||||
|
|
||||||
@ -16,7 +16,7 @@ const getInitialColor = () => {
|
|||||||
|
|
||||||
export const ColorContext = createContext();
|
export const ColorContext = createContext();
|
||||||
|
|
||||||
export const ColorProvider = ({ initialTheme, children }) => {
|
export function ColorProvider({ initialTheme, children }) {
|
||||||
const [color, setColor] = useState(getInitialColor);
|
const [color, setColor] = useState(getInitialColor);
|
||||||
|
|
||||||
const rawSetColor = (rawColor) => {
|
const rawSetColor = (rawColor) => {
|
||||||
@ -38,5 +38,7 @@ export const ColorProvider = ({ initialTheme, children }) => {
|
|||||||
rawSetColor(color);
|
rawSetColor(color);
|
||||||
}, [color]);
|
}, [color]);
|
||||||
|
|
||||||
return <ColorContext.Provider value={{ color, setColor }}>{children}</ColorContext.Provider>;
|
const value = useMemo(() => ({ color, setColor }), [color]);
|
||||||
};
|
|
||||||
|
return <ColorContext.Provider value={value}>{children}</ColorContext.Provider>;
|
||||||
|
}
|
@ -348,7 +348,9 @@ export default function mapIcon(weatherStatusCode, timeOfDay) {
|
|||||||
if (mapping) {
|
if (mapping) {
|
||||||
if (timeOfDay === "day") {
|
if (timeOfDay === "day") {
|
||||||
return mapping.icon.day;
|
return mapping.icon.day;
|
||||||
} else if (timeOfDay === "night") {
|
}
|
||||||
|
|
||||||
|
if (timeOfDay === "night") {
|
||||||
return mapping.icon.night;
|
return mapping.icon.night;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
|
/* eslint-disable no-console */
|
||||||
import { join } from "path";
|
import { join } from "path";
|
||||||
import { existsSync, copyFile, promises as fs } from "fs";
|
import { existsSync, copyFile, promises as fs } from "fs";
|
||||||
|
|
||||||
import yaml from "js-yaml";
|
import yaml from "js-yaml";
|
||||||
|
|
||||||
export default function checkAndCopyConfig(config) {
|
export default function checkAndCopyConfig(config) {
|
||||||
@ -8,7 +10,7 @@ export default function checkAndCopyConfig(config) {
|
|||||||
const configSkeleton = join(process.cwd(), "src", "skeleton", config);
|
const configSkeleton = join(process.cwd(), "src", "skeleton", config);
|
||||||
copyFile(configSkeleton, configYaml, (err) => {
|
copyFile(configSkeleton, configYaml, (err) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
console.log("error copying config", err);
|
console.error("error copying config", err);
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
console.info("%s was copied to the config folder", config);
|
console.info("%s was copied to the config folder", config);
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
import yaml from "js-yaml";
|
|
||||||
import path from "path";
|
import path from "path";
|
||||||
import { promises as fs } from "fs";
|
import { promises as fs } from "fs";
|
||||||
|
|
||||||
|
import yaml from "js-yaml";
|
||||||
|
|
||||||
import checkAndCopyConfig from "utils/config";
|
import checkAndCopyConfig from "utils/config";
|
||||||
|
|
||||||
export default async function getDockerArguments(server) {
|
export default async function getDockerArguments(server) {
|
||||||
@ -13,18 +15,21 @@ export default async function getDockerArguments(server) {
|
|||||||
if (!server) {
|
if (!server) {
|
||||||
if (process.platform !== "win32" && process.platform !== "darwin") {
|
if (process.platform !== "win32" && process.platform !== "darwin") {
|
||||||
return { socketPath: "/var/run/docker.sock" };
|
return { socketPath: "/var/run/docker.sock" };
|
||||||
} else {
|
}
|
||||||
|
|
||||||
return { host: "127.0.0.1" };
|
return { host: "127.0.0.1" };
|
||||||
}
|
}
|
||||||
} else if (servers[server]) {
|
|
||||||
|
if (servers[server]) {
|
||||||
if (servers[server].socket) {
|
if (servers[server].socket) {
|
||||||
return { socketPath: servers[server].socket };
|
return { socketPath: servers[server].socket };
|
||||||
} else if (servers[server].host) {
|
}
|
||||||
|
|
||||||
|
if (servers[server].host) {
|
||||||
return { host: servers[server].host, port: servers[server].port || null };
|
return { host: servers[server].host, port: servers[server].port || null };
|
||||||
} else {
|
}
|
||||||
|
|
||||||
return servers[server];
|
return servers[server];
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
return null;
|
return null;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
|
/* eslint-disable prefer-promise-reject-errors */
|
||||||
import https from "https";
|
import https from "https";
|
||||||
import http from "http";
|
import http from "http";
|
||||||
|
|
||||||
export function httpsRequest(url, params) {
|
export function httpsRequest(url, params) {
|
||||||
return new Promise(function (resolve, reject) {
|
return new Promise((resolve, reject) => {
|
||||||
var request = https.request(url, params, function (response) {
|
const request = https.request(url, params, (response) => {
|
||||||
var data = [];
|
const data = [];
|
||||||
|
|
||||||
response.on("data", (chunk) => {
|
response.on("data", (chunk) => {
|
||||||
data.push(chunk);
|
data.push(chunk);
|
||||||
@ -24,9 +25,9 @@ export function httpsRequest(url, params) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function httpRequest(url, params) {
|
export function httpRequest(url, params) {
|
||||||
return new Promise(function (resolve, reject) {
|
return new Promise((resolve, reject) => {
|
||||||
var request = http.request(url, params, function (response) {
|
const request = http.request(url, params, (response) => {
|
||||||
var data = [];
|
const data = [];
|
||||||
|
|
||||||
response.on("data", (chunk) => {
|
response.on("data", (chunk) => {
|
||||||
data.push(chunk);
|
data.push(chunk);
|
||||||
@ -57,7 +58,6 @@ export function httpProxy(url, params = {}) {
|
|||||||
agent: httpsAgent,
|
agent: httpsAgent,
|
||||||
...params,
|
...params,
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
return httpRequest(constructedUrl, params);
|
|
||||||
}
|
}
|
||||||
|
return httpRequest(constructedUrl, params);
|
||||||
}
|
}
|
||||||
|
@ -393,18 +393,17 @@ const conditions = [
|
|||||||
night: Icons.WiCloudy,
|
night: Icons.WiCloudy,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
];
|
];
|
||||||
|
|
||||||
export default function mapIcon(weatherStatusCode, timeOfDay) {
|
export default function mapIcon(weatherStatusCode, timeOfDay) {
|
||||||
const mapping = conditions.find(
|
const mapping = conditions.find((condition) => condition.code === weatherStatusCode);
|
||||||
(condition) => condition.code === weatherStatusCode
|
|
||||||
);
|
|
||||||
|
|
||||||
if (mapping) {
|
if (mapping) {
|
||||||
if (timeOfDay === "day") {
|
if (timeOfDay === "day") {
|
||||||
return mapping.icon.day;
|
return mapping.icon.day;
|
||||||
} else if (timeOfDay === "night") {
|
}
|
||||||
|
|
||||||
|
if (timeOfDay === "night") {
|
||||||
return mapping.icon.night;
|
return mapping.icon.night;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { getServiceWidget } from "utils/service-helpers";
|
import getServiceWidget from "utils/service-helpers";
|
||||||
import { formatApiCall } from "utils/api-helpers";
|
import { formatApiCall } from "utils/api-helpers";
|
||||||
import { httpProxy } from "utils/http";
|
import { httpProxy } from "utils/http";
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { getServiceWidget } from "utils/service-helpers";
|
import getServiceWidget from "utils/service-helpers";
|
||||||
import { formatApiCall } from "utils/api-helpers";
|
import { formatApiCall } from "utils/api-helpers";
|
||||||
import { httpProxy } from "utils/http";
|
import { httpProxy } from "utils/http";
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { getServiceWidget } from "utils/service-helpers";
|
import getServiceWidget from "utils/service-helpers";
|
||||||
import { formatApiCall } from "utils/api-helpers";
|
import { formatApiCall } from "utils/api-helpers";
|
||||||
|
|
||||||
export default async function npmProxyHandler(req, res) {
|
export default async function npmProxyHandler(req, res) {
|
||||||
@ -25,7 +25,7 @@ export default async function npmProxyHandler(req, res) {
|
|||||||
method: "GET",
|
method: "GET",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
Authorization: "Bearer " + authResponse.token,
|
Authorization: `Bearer ${authResponse.token}`,
|
||||||
},
|
},
|
||||||
}).then((response) => response.json());
|
}).then((response) => response.json());
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { JSONRPCClient } from "json-rpc-2.0";
|
import { JSONRPCClient } from "json-rpc-2.0";
|
||||||
import { getServiceWidget } from "utils/service-helpers";
|
|
||||||
|
import getServiceWidget from "utils/service-helpers";
|
||||||
|
|
||||||
export default async function nzbgetProxyHandler(req, res) {
|
export default async function nzbgetProxyHandler(req, res) {
|
||||||
const { group, service, endpoint } = req.query;
|
const { group, service, endpoint } = req.query;
|
||||||
@ -25,9 +26,9 @@ export default async function nzbgetProxyHandler(req, res) {
|
|||||||
if (response.status === 200) {
|
if (response.status === 200) {
|
||||||
const jsonRPCResponse = await response.json();
|
const jsonRPCResponse = await response.json();
|
||||||
return client.receive(jsonRPCResponse);
|
return client.receive(jsonRPCResponse);
|
||||||
} else if (jsonRPCRequest.id !== undefined) {
|
|
||||||
return Promise.reject(new Error(response.statusText));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return Promise.reject(new Error(response.statusText));
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import RuTorrent from "rutorrent-promise";
|
import RuTorrent from "rutorrent-promise";
|
||||||
|
|
||||||
import { getServiceWidget } from "utils/service-helpers";
|
import getServiceWidget from "utils/service-helpers";
|
||||||
|
|
||||||
export default async function rutorrentProxyHandler(req, res) {
|
export default async function rutorrentProxyHandler(req, res) {
|
||||||
const { group, service } = req.query;
|
const { group, service } = req.query;
|
||||||
|
@ -1,24 +1,21 @@
|
|||||||
import { promises as fs } from "fs";
|
import { promises as fs } from "fs";
|
||||||
import path from "path";
|
import path from "path";
|
||||||
|
|
||||||
import yaml from "js-yaml";
|
import yaml from "js-yaml";
|
||||||
|
|
||||||
export async function getServiceWidget(group, service) {
|
export default async function getServiceWidget(group, service) {
|
||||||
const servicesYaml = path.join(process.cwd(), "config", "services.yaml");
|
const servicesYaml = path.join(process.cwd(), "config", "services.yaml");
|
||||||
const fileContents = await fs.readFile(servicesYaml, "utf8");
|
const fileContents = await fs.readFile(servicesYaml, "utf8");
|
||||||
const services = yaml.load(fileContents);
|
const services = yaml.load(fileContents);
|
||||||
|
|
||||||
// map easy to write YAML objects into easy to consume JS arrays
|
// map easy to write YAML objects into easy to consume JS arrays
|
||||||
const servicesArray = services.map((group) => {
|
const servicesArray = services.map((servicesGroup) => ({
|
||||||
return {
|
name: Object.keys(servicesGroup)[0],
|
||||||
name: Object.keys(group)[0],
|
services: servicesGroup[Object.keys(servicesGroup)[0]].map((entries) => ({
|
||||||
services: group[Object.keys(group)[0]].map((entries) => {
|
|
||||||
return {
|
|
||||||
name: Object.keys(entries)[0],
|
name: Object.keys(entries)[0],
|
||||||
...entries[Object.keys(entries)[0]],
|
...entries[Object.keys(entries)[0]],
|
||||||
};
|
})),
|
||||||
}),
|
}));
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
const serviceGroup = servicesArray.find((g) => g.name === group);
|
const serviceGroup = servicesArray.find((g) => g.name === group);
|
||||||
if (serviceGroup) {
|
if (serviceGroup) {
|
||||||
|
@ -19,7 +19,7 @@ export function formatBytes(bytes, decimals = 2) {
|
|||||||
|
|
||||||
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
||||||
|
|
||||||
return parseFloat(bytes / Math.pow(k, i)).toFixed(dm) + " " + sizes[i];
|
return `${parseFloat(bytes / k ** i).toFixed(dm)} ${sizes[i]}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function formatBits(bytes, decimals = 2) {
|
export function formatBits(bytes, decimals = 2) {
|
||||||
@ -31,5 +31,5 @@ export function formatBits(bytes, decimals = 2) {
|
|||||||
|
|
||||||
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
||||||
|
|
||||||
return parseFloat(bytes / Math.pow(k, i)).toFixed(dm) + " " + sizes[i];
|
return `${parseFloat(bytes / k ** i).toFixed(dm)} ${sizes[i]}`;
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { createContext, useState, useEffect } from "react";
|
import { createContext, useState, useEffect, useMemo } from "react";
|
||||||
|
|
||||||
const getInitialTheme = () => {
|
const getInitialTheme = () => {
|
||||||
if (typeof window !== "undefined" && window.localStorage) {
|
if (typeof window !== "undefined" && window.localStorage) {
|
||||||
@ -18,7 +18,7 @@ const getInitialTheme = () => {
|
|||||||
|
|
||||||
export const ThemeContext = createContext();
|
export const ThemeContext = createContext();
|
||||||
|
|
||||||
export const ThemeProvider = ({ initialTheme, children }) => {
|
export function ThemeProvider({ initialTheme, children }) {
|
||||||
const [theme, setTheme] = useState(getInitialTheme);
|
const [theme, setTheme] = useState(getInitialTheme);
|
||||||
|
|
||||||
const rawSetTheme = (rawTheme) => {
|
const rawSetTheme = (rawTheme) => {
|
||||||
@ -39,5 +39,7 @@ export const ThemeProvider = ({ initialTheme, children }) => {
|
|||||||
rawSetTheme(theme);
|
rawSetTheme(theme);
|
||||||
}, [theme]);
|
}, [theme]);
|
||||||
|
|
||||||
return <ThemeContext.Provider value={{ theme, setTheme }}>{children}</ThemeContext.Provider>;
|
const value = useMemo(() => ({ theme, setTheme }), [theme]);
|
||||||
};
|
|
||||||
|
return <ThemeContext.Provider value={value}>{children}</ThemeContext.Provider>;
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user