diff --git a/src/components/widgets/unifi_console/unifi_console.jsx b/src/components/widgets/unifi_console/unifi_console.jsx index 7427bd23c79..889a517f182 100644 --- a/src/components/widgets/unifi_console/unifi_console.jsx +++ b/src/components/widgets/unifi_console/unifi_console.jsx @@ -10,7 +10,7 @@ export default function Widget({ options }) { // eslint-disable-next-line no-param-reassign options.type = "unifi_console"; - const { data: statsData, error: statsError } = useWidgetAPI(options, "stat/sites"); + const { data: statsData, error: statsError } = useWidgetAPI(options, "stat/sites", { index: options.index }); if (statsError || statsData?.error) { return ( diff --git a/src/pages/api/widgets/glances.js b/src/pages/api/widgets/glances.js index 86992dd10f2..5d4622b8d55 100644 --- a/src/pages/api/widgets/glances.js +++ b/src/pages/api/widgets/glances.js @@ -1,29 +1,17 @@ import { httpProxy } from "utils/proxy/http"; import createLogger from "utils/logger"; -import { getSettings } from "utils/config/config"; +import { getPrivateWidgetOptions } from "utils/config/widget-helpers"; const logger = createLogger("glances"); export default async function handler(req, res) { - const { id } = req.query; + const { index } = req.query; - let errorMessage; - - let instanceID = "glances"; - if (id) { // multiple instances - instanceID = id; - } - const settings = getSettings(); - const instanceSettings = settings[instanceID]; - if (!instanceSettings) { - errorMessage = id ? `There is no glances section with id '${id}' in settings.yaml` : "There is no glances section in settings.yaml"; - logger.error(errorMessage); - return res.status(400).json({ error: errorMessage }); - } + const privateWidgetOptions = await getPrivateWidgetOptions("glances", index); - const url = instanceSettings?.url; + const url = privateWidgetOptions?.url; if (!url) { - errorMessage = "Missing Glances URL"; + const errorMessage = "Missing Glances URL"; logger.error(errorMessage); return res.status(400).json({ error: errorMessage }); } @@ -32,8 +20,8 @@ export default async function handler(req, res) { const headers = { "Accept-Encoding": "application/json" }; - if (instanceSettings.username && instanceSettings.password) { - headers.Authorization = `Basic ${Buffer.from(`${instanceSettings.username}:${instanceSettings.password}`).toString("base64")}` + if (privateWidgetOptions.username && privateWidgetOptions.password) { + headers.Authorization = `Basic ${Buffer.from(`${privateWidgetOptions.username}:${privateWidgetOptions.password}`).toString("base64")}` } const params = { method: "GET", headers }; diff --git a/src/utils/config/api-response.js b/src/utils/config/api-response.js index 809927d1b48..5cc1127e3c8 100644 --- a/src/utils/config/api-response.js +++ b/src/utils/config/api-response.js @@ -6,6 +6,7 @@ import yaml from "js-yaml"; import checkAndCopyConfig from "utils/config/config"; import { servicesFromConfig, servicesFromDocker, cleanServiceGroups } from "utils/config/service-helpers"; +import { cleanWidgetGroups, widgetsFromConfig } from "utils/config/widget-helpers"; export async function bookmarksResponse() { checkAndCopyConfig("bookmarks.yaml"); @@ -29,21 +30,17 @@ export async function bookmarksResponse() { } export async function widgetsResponse() { - checkAndCopyConfig("widgets.yaml"); + let configuredWidgets; - const widgetsYaml = path.join(process.cwd(), "config", "widgets.yaml"); - const fileContents = await fs.readFile(widgetsYaml, "utf8"); - const widgets = yaml.load(fileContents); - - if (!widgets) return []; - - // map easy to write YAML objects into easy to consume JS arrays - const widgetsArray = widgets.map((group) => ({ - type: Object.keys(group)[0], - options: { ...group[Object.keys(group)[0]] }, - })); + try { + configuredWidgets = cleanWidgetGroups(await widgetsFromConfig()); + } catch (e) { + console.error("Failed to load widgets, please check widgets.yaml for errors or remove example entries."); + if (e) console.error(e); + configuredWidgets = []; + } - return widgetsArray; + return configuredWidgets; } export async function servicesResponse() { diff --git a/src/utils/config/config.js b/src/utils/config/config.js index 16861de8181..0003c589d94 100644 --- a/src/utils/config/config.js +++ b/src/utils/config/config.js @@ -33,4 +33,4 @@ export function getSettings() { const settingsYaml = join(process.cwd(), "config", "settings.yaml"); const fileContents = readFileSync(settingsYaml, "utf8"); return yaml.load(fileContents); -} +} \ No newline at end of file diff --git a/src/utils/config/service-helpers.js b/src/utils/config/service-helpers.js index 99ce34d1ff4..15740d22bf6 100644 --- a/src/utils/config/service-helpers.js +++ b/src/utils/config/service-helpers.js @@ -165,4 +165,4 @@ export default async function getServiceWidget(group, service) { } return false; -} +} \ No newline at end of file diff --git a/src/utils/config/widget-helpers.js b/src/utils/config/widget-helpers.js new file mode 100644 index 00000000000..c9bdd0fbbc5 --- /dev/null +++ b/src/utils/config/widget-helpers.js @@ -0,0 +1,73 @@ +import { promises as fs } from "fs"; +import path from "path"; + +import yaml from "js-yaml"; + +import checkAndCopyConfig from "utils/config/config"; + +export async function widgetsFromConfig() { + checkAndCopyConfig("widgets.yaml"); + + const widgetsYaml = path.join(process.cwd(), "config", "widgets.yaml"); + const fileContents = await fs.readFile(widgetsYaml, "utf8"); + const widgets = yaml.load(fileContents); + + if (!widgets) return []; + + // map easy to write YAML objects into easy to consume JS arrays + const widgetsArray = widgets.map((group, index) => ({ + type: Object.keys(group)[0], + options: { + index, + ...group[Object.keys(group)[0]] + }, + })); + return widgetsArray; +} + +export async function cleanWidgetGroups(widgets) { + return widgets.map((widget, index) => { + const sanitizedOptions = widget.options; + const optionKeys = Object.keys(sanitizedOptions); + ["url", "username", "password", "key"].forEach((pO) => { + if (optionKeys.includes(pO)) { + delete sanitizedOptions[pO]; + } + }); + + return { + type: widget.type, + options: { + index, + ...sanitizedOptions + }, + } + }); +} + +export async function getPrivateWidgetOptions(type, widgetIndex) { + const widgets = await widgetsFromConfig(); + + const privateOptions = widgets.map((widget) => { + const { + index, + url, + username, + password, + key + } = widget.options; + + return { + type: widget.type, + options: { + index, + url, + username, + password, + key + }, + } + }); + + return (type !== undefined && widgetIndex !== undefined) ? privateOptions.find(o => o.type === type && o.options.index === parseInt(widgetIndex, 10))?.options : privateOptions; +} \ No newline at end of file diff --git a/src/widgets/unifi/proxy.js b/src/widgets/unifi/proxy.js index 53ee49f039b..dc1c437b960 100644 --- a/src/widgets/unifi/proxy.js +++ b/src/widgets/unifi/proxy.js @@ -3,8 +3,8 @@ import cache from "memory-cache"; import { formatApiCall } from "utils/proxy/api-helpers"; import { httpProxy } from "utils/proxy/http"; import { addCookieToJar, setCookieHeader } from "utils/proxy/cookie-jar"; -import { getSettings } from "utils/config/config"; import getServiceWidget from "utils/config/service-helpers"; +import { getPrivateWidgetOptions } from "utils/config/widget-helpers"; import createLogger from "utils/logger"; import widgets from "widgets/widgets"; @@ -15,13 +15,13 @@ const logger = createLogger(proxyName); async function getWidget(req) { const { group, service, type } = req.query; - + let widget = null; - if (type === "unifi_console") { - const settings = getSettings(); - widget = settings.unifi_console; + if (type === "unifi_console") { // info widget + const index = req.query?.query ? JSON.parse(req.query.query).index : undefined; + widget = await getPrivateWidgetOptions(type, index); if (!widget) { - logger.debug("There is no unifi_console section in settings.yaml"); + logger.debug("Error retrieving settings for this Unifi widget"); return null; } widget.type = "unifi";