From 8ea2ccf1108b1ecd695534df9eee07aee014e09e Mon Sep 17 00:00:00 2001 From: icyleaf Date: Wed, 18 Oct 2023 13:54:17 +0800 Subject: [PATCH] Enhancement: support dot-notated field properties in docker labels (#2195) --- docs/configs/docker.md | 17 +++++++ package-lock.json | 6 --- package.json | 1 - pnpm-lock.yaml | 7 --- src/utils/config/service-helpers.js | 2 +- src/utils/config/shvl.js | 70 +++++++++++++++++++++++++++++ 6 files changed, 88 insertions(+), 15 deletions(-) create mode 100644 src/utils/config/shvl.js diff --git a/docs/configs/docker.md b/docs/configs/docker.md index 133c263b3..b4e089bb3 100644 --- a/docs/configs/docker.md +++ b/docs/configs/docker.md @@ -153,6 +153,23 @@ labels: - homepage.widget.fields=["field1","field2"] # optional ``` +You can add specify fields for e.g. the [CustomAPI](/widgets/services/customapi) widget by using array-style dot notation: + +```yaml +labels: + - homepage.group=Media + - homepage.name=Emby + - homepage.icon=emby.png + - homepage.href=http://emby.home/ + - homepage.description=Media server + - homepage.widget.type=customapi + - homepage.widget.url=http://argus.service/api/v1/service/summary/emby + - homepage.widget.field[0].label=Deployed Version + - homepage.widget.field[0].field.status=deployed_version + - homepage.widget.field[1].label=Latest Version + - homepage.widget.field[1].field.status=latest_version +``` + ## Docker Swarm Docker swarm is supported and Docker services are specified with the same `server` and `container` notation. To enable swarm support you will need to include a `swarm` setting in your docker.yaml, e.g. diff --git a/package-lock.json b/package-lock.json index d2d9bd423..2f9cd9f20 100644 --- a/package-lock.json +++ b/package-lock.json @@ -30,7 +30,6 @@ "react-i18next": "^11.18.6", "react-icons": "^4.4.0", "recharts": "^2.7.2", - "shvl": "^3.0.0", "swr": "^1.3.0", "systeminformation": "^5.17.12", "tough-cookie": "^4.1.2", @@ -5628,11 +5627,6 @@ "node": ">=4" } }, - "node_modules/shvl": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shvl/-/shvl-3.0.0.tgz", - "integrity": "sha512-5IomAM3ykE/g9K9L6lhODc+TpCuN03rrhlboegeKyyfh66DDdpRD5JN37DYhNHH+RaYjiIDx64K/Ms/xQYOR5w==" - }, "node_modules/side-channel": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", diff --git a/package.json b/package.json index 6a33b5ed9..52b36cef6 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,6 @@ "react-i18next": "^11.18.6", "react-icons": "^4.4.0", "recharts": "^2.7.2", - "shvl": "^3.0.0", "swr": "^1.3.0", "systeminformation": "^5.17.12", "tough-cookie": "^4.1.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6ff7151a8..11379201a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -71,9 +71,6 @@ dependencies: recharts: specifier: ^2.7.2 version: 2.7.2(prop-types@15.8.1)(react-dom@18.2.0)(react@18.2.0) - shvl: - specifier: ^3.0.0 - version: 3.0.0 swr: specifier: ^1.3.0 version: 1.3.0(react@18.2.0) @@ -3614,10 +3611,6 @@ packages: rechoir: 0.6.2 dev: false - /shvl@3.0.0: - resolution: {integrity: sha512-5IomAM3ykE/g9K9L6lhODc+TpCuN03rrhlboegeKyyfh66DDdpRD5JN37DYhNHH+RaYjiIDx64K/Ms/xQYOR5w==} - dev: false - /side-channel@1.0.4: resolution: {integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==} dependencies: diff --git a/src/utils/config/service-helpers.js b/src/utils/config/service-helpers.js index 8c7c8e4e0..6cdddf672 100644 --- a/src/utils/config/service-helpers.js +++ b/src/utils/config/service-helpers.js @@ -3,13 +3,13 @@ import path from "path"; import yaml from "js-yaml"; import Docker from "dockerode"; -import * as shvl from "shvl"; import { CustomObjectsApi, NetworkingV1Api, ApiextensionsV1Api } from "@kubernetes/client-node"; import createLogger from "utils/logger"; import checkAndCopyConfig, { CONF_DIR, substituteEnvironmentVars } from "utils/config/config"; import getDockerArguments from "utils/config/docker"; import getKubeConfig from "utils/config/kubernetes"; +import * as shvl from "utils/config/shvl"; const logger = createLogger("service-helpers"); diff --git a/src/utils/config/shvl.js b/src/utils/config/shvl.js new file mode 100644 index 000000000..8df751981 --- /dev/null +++ b/src/utils/config/shvl.js @@ -0,0 +1,70 @@ +/* eslint-disable */ + +/* +Code primarely based on shvl repository: https://github.com/robinvdvleuten/shvl + +MIT License + +Copyright (c) Robin van der Vleuten + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +export function get(object, path, def) { + return ( + // Split the path into keys and reduce the object to the target value + object = path.split(/[.[\]]+/).reduce(function (obj, p) { + // Check each nested object to see if the key exists + return obj && obj[p] !== undefined ? obj[p] : undefined; + }, object) + ) === undefined + // If the final value is undefined, return the default value + ? def + : object; // Otherwise, return the value found +} + +export function set(obj, path, val) { + // Split the path into keys and filter out any empty strings + const keys = path.split(/[.[\]]+/).filter(Boolean); + + // Pop the last key to set the value later + const lastKey = keys.pop(); + + // Prevent setting dangerous keys like __proto__ + if (/^(__proto__|constructor|prototype)$/.test(lastKey)) return obj; + + // Reduce the object to the nested object where we want to set the value + keys.reduce((acc, key, i) => { + // Again, block dangerous keys + if (/^(__proto__|constructor|prototype)$/.test(key)) return {}; + + // Check if next key is an array index + const isIndex = /^\d+$/.test(keys[i + 1]); + + // If current key doesn't exist, initialise it as an array or object + acc[key] = Array.isArray(acc[key]) + ? acc[key] + : (isIndex ? [] : acc[key] || {}); + + // Return nested object for next iteration + return acc[key]; + }, obj)[lastKey] = val; // Finally set the value + + return obj; +}