mirror of
				https://github.com/karl0ss/homepage.git
				synced 2025-11-04 08:20:58 +00:00 
			
		
		
		
	Merge pull request #1807 from userXinos/omv-widget
OpenMediaVault widget
This commit is contained in:
		
						commit
						b0f29709c2
					
				@ -701,5 +701,13 @@
 | 
				
			|||||||
        "errored": "Errors",
 | 
					        "errored": "Errors",
 | 
				
			||||||
        "noRecent": "Out of Date",
 | 
					        "noRecent": "Out of Date",
 | 
				
			||||||
        "totalUsed": "Used Storage"
 | 
					        "totalUsed": "Used Storage"
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "openmediavault": {
 | 
				
			||||||
 | 
					        "downloading": "Downloading",
 | 
				
			||||||
 | 
					        "total": "Total",
 | 
				
			||||||
 | 
					        "running": "Running",
 | 
				
			||||||
 | 
					        "stopped": "Stopped",
 | 
				
			||||||
 | 
					        "passed": "Passed",
 | 
				
			||||||
 | 
					        "failed": "Failed"
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -298,6 +298,7 @@ export function cleanServiceGroups(groups) {
 | 
				
			|||||||
          metric, // glances
 | 
					          metric, // glances
 | 
				
			||||||
          stream, // mjpeg
 | 
					          stream, // mjpeg
 | 
				
			||||||
          fit,
 | 
					          fit,
 | 
				
			||||||
 | 
					          method, // openmediavault widget
 | 
				
			||||||
        } = cleanedService.widget;
 | 
					        } = cleanedService.widget;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let fieldsList = fields;
 | 
					        let fieldsList = fields;
 | 
				
			||||||
@ -368,6 +369,9 @@ export function cleanServiceGroups(groups) {
 | 
				
			|||||||
          if (stream) cleanedService.widget.stream = stream;
 | 
					          if (stream) cleanedService.widget.stream = stream;
 | 
				
			||||||
          if (fit) cleanedService.widget.fit = fit;
 | 
					          if (fit) cleanedService.widget.fit = fit;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					        if (type === "openmediavault") {
 | 
				
			||||||
 | 
					          if (method) cleanedService.widget.method = method;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      return cleanedService;
 | 
					      return cleanedService;
 | 
				
			||||||
 | 
				
			|||||||
@ -59,6 +59,7 @@ const components = {
 | 
				
			|||||||
  ombi: dynamic(() => import("./ombi/component")),
 | 
					  ombi: dynamic(() => import("./ombi/component")),
 | 
				
			||||||
  opnsense: dynamic(() => import("./opnsense/component")),
 | 
					  opnsense: dynamic(() => import("./opnsense/component")),
 | 
				
			||||||
  overseerr: dynamic(() => import("./overseerr/component")),
 | 
					  overseerr: dynamic(() => import("./overseerr/component")),
 | 
				
			||||||
 | 
					  openmediavault: dynamic(() => import("./openmediavault/component")),
 | 
				
			||||||
  paperlessngx: dynamic(() => import("./paperlessngx/component")),
 | 
					  paperlessngx: dynamic(() => import("./paperlessngx/component")),
 | 
				
			||||||
  pfsense: dynamic(() => import("./pfsense/component")),
 | 
					  pfsense: dynamic(() => import("./pfsense/component")),
 | 
				
			||||||
  photoprism: dynamic(() => import("./photoprism/component")),
 | 
					  photoprism: dynamic(() => import("./photoprism/component")),
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										16
									
								
								src/widgets/openmediavault/component.jsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								src/widgets/openmediavault/component.jsx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,16 @@
 | 
				
			|||||||
 | 
					import ServicesGetStatus from "./methods/services_get_status";
 | 
				
			||||||
 | 
					import SmartGetList from "./methods/smart_get_list";
 | 
				
			||||||
 | 
					import DownloaderGetDownloadList from "./methods/downloader_get_downloadlist";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default function Component({ service }) {
 | 
				
			||||||
 | 
					  switch (service.widget.method) {
 | 
				
			||||||
 | 
					    case "services.getStatus":
 | 
				
			||||||
 | 
					      return <ServicesGetStatus service={service} />;
 | 
				
			||||||
 | 
					    case "smart.getListBg":
 | 
				
			||||||
 | 
					      return <SmartGetList service={service} />;
 | 
				
			||||||
 | 
					    case "downloader.getDownloadList":
 | 
				
			||||||
 | 
					      return <DownloaderGetDownloadList service={service} />;
 | 
				
			||||||
 | 
					    default:
 | 
				
			||||||
 | 
					      return null;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,36 @@
 | 
				
			|||||||
 | 
					import useWidgetAPI from "utils/proxy/use-widget-api";
 | 
				
			||||||
 | 
					import Container from "components/services/widget/container";
 | 
				
			||||||
 | 
					import Block from "components/services/widget/block";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const downloadReduce = (acc, e) => {
 | 
				
			||||||
 | 
					  if (e.downloading) {
 | 
				
			||||||
 | 
					    return acc + 1;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  return acc;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const items = [
 | 
				
			||||||
 | 
					  { label: "openmediavault.downloading", getNumber: (data) => (!data ? null : data.reduce(downloadReduce, 0)) },
 | 
				
			||||||
 | 
					  { label: "openmediavault.total", getNumber: (data) => (!data ? null : data?.length) },
 | 
				
			||||||
 | 
					];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default function Component({ service }) {
 | 
				
			||||||
 | 
					  const { data, error } = useWidgetAPI(service.widget);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (error) {
 | 
				
			||||||
 | 
					    return <Container service={service} error={error} />;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const itemsWithData = items.map((item) => ({
 | 
				
			||||||
 | 
					    ...item,
 | 
				
			||||||
 | 
					    number: item.getNumber(data?.response?.data),
 | 
				
			||||||
 | 
					  }));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <Container service={service}>
 | 
				
			||||||
 | 
					      {itemsWithData.map((e) => (
 | 
				
			||||||
 | 
					        <Block key={e.label} label={e.label} value={e.number} />
 | 
				
			||||||
 | 
					      ))}
 | 
				
			||||||
 | 
					    </Container>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										43
									
								
								src/widgets/openmediavault/methods/services_get_status.jsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								src/widgets/openmediavault/methods/services_get_status.jsx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,43 @@
 | 
				
			|||||||
 | 
					import useWidgetAPI from "utils/proxy/use-widget-api";
 | 
				
			||||||
 | 
					import Container from "components/services/widget/container";
 | 
				
			||||||
 | 
					import Block from "components/services/widget/block";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const isRunningReduce = (acc, e) => {
 | 
				
			||||||
 | 
					  if (e.running) {
 | 
				
			||||||
 | 
					    return acc + 1;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  return acc;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					const notRunningReduce = (acc, e) => {
 | 
				
			||||||
 | 
					  if (!e.running) {
 | 
				
			||||||
 | 
					    return acc + 1;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  return acc;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const items = [
 | 
				
			||||||
 | 
					  { label: "openmediavault.running", getNumber: (data) => (!data ? null : data.reduce(isRunningReduce, 0)) },
 | 
				
			||||||
 | 
					  { label: "openmediavault.stopped", getNumber: (data) => (!data ? null : data.reduce(notRunningReduce, 0)) },
 | 
				
			||||||
 | 
					  { label: "openmediavault.total", getNumber: (data) => (!data ? null : data?.length) },
 | 
				
			||||||
 | 
					];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default function Component({ service }) {
 | 
				
			||||||
 | 
					  const { data, error } = useWidgetAPI(service.widget);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (error) {
 | 
				
			||||||
 | 
					    return <Container service={service} error={error} />;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const itemsWithData = items.map((item) => ({
 | 
				
			||||||
 | 
					    ...item,
 | 
				
			||||||
 | 
					    number: item.getNumber(data?.response?.data),
 | 
				
			||||||
 | 
					  }));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <Container service={service}>
 | 
				
			||||||
 | 
					      {itemsWithData.map((e) => (
 | 
				
			||||||
 | 
					        <Block key={e.label} label={e.label} value={e.number} />
 | 
				
			||||||
 | 
					      ))}
 | 
				
			||||||
 | 
					    </Container>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										42
									
								
								src/widgets/openmediavault/methods/smart_get_list.jsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								src/widgets/openmediavault/methods/smart_get_list.jsx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,42 @@
 | 
				
			|||||||
 | 
					import useWidgetAPI from "utils/proxy/use-widget-api";
 | 
				
			||||||
 | 
					import Container from "components/services/widget/container";
 | 
				
			||||||
 | 
					import Block from "components/services/widget/block";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const passedReduce = (acc, e) => {
 | 
				
			||||||
 | 
					  if (e.overallstatus === "GOOD") {
 | 
				
			||||||
 | 
					    return acc + 1;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  return acc;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					const failedReduce = (acc, e) => {
 | 
				
			||||||
 | 
					  if (e.overallstatus !== "GOOD") {
 | 
				
			||||||
 | 
					    return acc + 1;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  return acc;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const items = [
 | 
				
			||||||
 | 
					  { label: "openmediavault.passed", getNumber: (data) => (!data ? null : data.reduce(passedReduce, 0)) },
 | 
				
			||||||
 | 
					  { label: "openmediavault.failed", getNumber: (data) => (!data ? null : data.reduce(failedReduce, 0)) },
 | 
				
			||||||
 | 
					];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default function Component({ service }) {
 | 
				
			||||||
 | 
					  const { data, error } = useWidgetAPI(service.widget);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (error) {
 | 
				
			||||||
 | 
					    return <Container service={service} error={error} />;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const itemsWithData = items.map((item) => ({
 | 
				
			||||||
 | 
					    ...item,
 | 
				
			||||||
 | 
					    number: item.getNumber(JSON.parse(data?.response?.output || "{}")?.data),
 | 
				
			||||||
 | 
					  }));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <Container service={service}>
 | 
				
			||||||
 | 
					      {itemsWithData.map((e) => (
 | 
				
			||||||
 | 
					        <Block key={e.label} label={e.label} value={e.number} />
 | 
				
			||||||
 | 
					      ))}
 | 
				
			||||||
 | 
					    </Container>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										151
									
								
								src/widgets/openmediavault/proxy.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										151
									
								
								src/widgets/openmediavault/proxy.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,151 @@
 | 
				
			|||||||
 | 
					import { formatApiCall } from "utils/proxy/api-helpers";
 | 
				
			||||||
 | 
					import { httpProxy } from "utils/proxy/http";
 | 
				
			||||||
 | 
					import getServiceWidget from "utils/config/service-helpers";
 | 
				
			||||||
 | 
					import { addCookieToJar, setCookieHeader } from "utils/proxy/cookie-jar";
 | 
				
			||||||
 | 
					import createLogger from "utils/logger";
 | 
				
			||||||
 | 
					import widgets from "widgets/widgets";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const PROXY_NAME = "OMVProxyHandler";
 | 
				
			||||||
 | 
					const BG_MAX_RETRIES = 50;
 | 
				
			||||||
 | 
					const BG_POLL_PERIOD = 500;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const logger = createLogger(PROXY_NAME);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					async function getWidget(req) {
 | 
				
			||||||
 | 
					  const { group, service } = req.query;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (!group || !service) {
 | 
				
			||||||
 | 
					    logger.debug("Invalid or missing service '%s' or group '%s'", service, group);
 | 
				
			||||||
 | 
					    return null;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const widget = await getServiceWidget(group, service);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (!widget) {
 | 
				
			||||||
 | 
					    logger.debug("Invalid or missing widget for service '%s' in group '%s'", service, group);
 | 
				
			||||||
 | 
					    return null;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return widget;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					async function rpc(url, request) {
 | 
				
			||||||
 | 
					  const params = {
 | 
				
			||||||
 | 
					    method: "POST",
 | 
				
			||||||
 | 
					    headers: { "Content-Type": "application/json" },
 | 
				
			||||||
 | 
					    body: JSON.stringify(request),
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					  setCookieHeader(url, params);
 | 
				
			||||||
 | 
					  const [status, contentType, data, headers] = await httpProxy(url, params);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return { status, contentType, data, headers };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					async function poll(attemptsLeft, makeReqByPos, pos = 0) {
 | 
				
			||||||
 | 
					  if (attemptsLeft <= 0) {
 | 
				
			||||||
 | 
					    return null;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const resp = await makeReqByPos(pos);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const data = JSON.parse(resp.data.toString()).response;
 | 
				
			||||||
 | 
					  if (data.running === true || data.outputPending) {
 | 
				
			||||||
 | 
					    await new Promise((resolve) => {
 | 
				
			||||||
 | 
					      setTimeout(resolve, BG_POLL_PERIOD);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    return poll(attemptsLeft - 1, makeReqByPos, data.pos);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  return resp;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					async function tryLogin(widget) {
 | 
				
			||||||
 | 
					  const url = new URL(formatApiCall(widgets?.[widget.type]?.api, { ...widget }));
 | 
				
			||||||
 | 
					  const { username, password } = widget;
 | 
				
			||||||
 | 
					  const resp = await rpc(url, {
 | 
				
			||||||
 | 
					    method: "login",
 | 
				
			||||||
 | 
					    service: "session",
 | 
				
			||||||
 | 
					    params: { username, password },
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (resp.status !== 200) {
 | 
				
			||||||
 | 
					    logger.error("HTTP %d logging in to OpenMediaVault. Data: %s", resp.status, resp.data);
 | 
				
			||||||
 | 
					    return [false, resp];
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const json = JSON.parse(resp.data.toString());
 | 
				
			||||||
 | 
					  if (json.response.authenticated !== true) {
 | 
				
			||||||
 | 
					    logger.error("Login error in OpenMediaVault. Data: %s", resp.data);
 | 
				
			||||||
 | 
					    resp.status = 401;
 | 
				
			||||||
 | 
					    return [false, resp];
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return [true, resp];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					async function processBg(url, filename) {
 | 
				
			||||||
 | 
					  const resp = await poll(BG_MAX_RETRIES, (pos) =>
 | 
				
			||||||
 | 
					    rpc(url, {
 | 
				
			||||||
 | 
					      service: "exec",
 | 
				
			||||||
 | 
					      method: "getOutput",
 | 
				
			||||||
 | 
					      params: { pos, filename },
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (resp == null) {
 | 
				
			||||||
 | 
					    const errText = "The maximum number of attempts to receive a response from Bg data has been exceeded.";
 | 
				
			||||||
 | 
					    logger.error(errText);
 | 
				
			||||||
 | 
					    return errText;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  if (resp.status !== 200) {
 | 
				
			||||||
 | 
					    logger.error("HTTP %d getting Bg data from OpenMediaVault RPC. Data: %s", resp.status, resp.data);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  return resp;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default async function proxyHandler(req, res) {
 | 
				
			||||||
 | 
					  const widget = await getWidget(req);
 | 
				
			||||||
 | 
					  if (!widget) {
 | 
				
			||||||
 | 
					    return res.status(400).json({ error: "Invalid proxy service type" });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const api = widgets?.[widget.type]?.api;
 | 
				
			||||||
 | 
					  if (!api) {
 | 
				
			||||||
 | 
					    return res.status(403).json({ error: "Service does not support RPC calls" });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const url = new URL(formatApiCall(api, { ...widget }));
 | 
				
			||||||
 | 
					  const [service, method] = widget.method.split(".");
 | 
				
			||||||
 | 
					  const rpcReq = { params: { limit: -1, start: 0 }, service, method };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  let resp = await rpc(url, rpcReq);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (resp.status === 401) {
 | 
				
			||||||
 | 
					    logger.debug("Session not authenticated.");
 | 
				
			||||||
 | 
					    const [success, lResp] = await tryLogin(widget);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (success) {
 | 
				
			||||||
 | 
					      addCookieToJar(url, lResp.headers);
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      res.status(lResp.status).json({ error: { message: `HTTP Error ${lResp.status}`, url, data: lResp.data } });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    logger.debug("Retrying OpenMediaVault request after login.");
 | 
				
			||||||
 | 
					    resp = await rpc(url, rpcReq);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (resp.status !== 200) {
 | 
				
			||||||
 | 
					    logger.error("HTTP %d getting data from OpenMediaVault RPC. Data: %s", resp.status, resp.data);
 | 
				
			||||||
 | 
					    return res.status(resp.status).json({ error: { message: `HTTP Error ${resp.status}`, url, data: resp.data } });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (method.endsWith("Bg")) {
 | 
				
			||||||
 | 
					    const json = JSON.parse(resp.data.toString());
 | 
				
			||||||
 | 
					    const bgResp = await processBg(url, json.response);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (typeof bgResp === "string") {
 | 
				
			||||||
 | 
					      return res.status(400).json({ error: bgResp });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return res.status(bgResp.status).send(bgResp.data);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return res.status(resp.status).send(resp.data);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										8
									
								
								src/widgets/openmediavault/widget.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								src/widgets/openmediavault/widget.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,8 @@
 | 
				
			|||||||
 | 
					import proxyHandler from "./proxy";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const widget = {
 | 
				
			||||||
 | 
					  api: "{url}/rpc.php",
 | 
				
			||||||
 | 
					  proxyHandler,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default widget;
 | 
				
			||||||
@ -53,6 +53,7 @@ import omada from "./omada/widget";
 | 
				
			|||||||
import ombi from "./ombi/widget";
 | 
					import ombi from "./ombi/widget";
 | 
				
			||||||
import opnsense from "./opnsense/widget";
 | 
					import opnsense from "./opnsense/widget";
 | 
				
			||||||
import overseerr from "./overseerr/widget";
 | 
					import overseerr from "./overseerr/widget";
 | 
				
			||||||
 | 
					import openmediavault from "./openmediavault/widget";
 | 
				
			||||||
import paperlessngx from "./paperlessngx/widget";
 | 
					import paperlessngx from "./paperlessngx/widget";
 | 
				
			||||||
import pfsense from "./pfsense/widget";
 | 
					import pfsense from "./pfsense/widget";
 | 
				
			||||||
import photoprism from "./photoprism/widget";
 | 
					import photoprism from "./photoprism/widget";
 | 
				
			||||||
@ -148,6 +149,7 @@ const widgets = {
 | 
				
			|||||||
  ombi,
 | 
					  ombi,
 | 
				
			||||||
  opnsense,
 | 
					  opnsense,
 | 
				
			||||||
  overseerr,
 | 
					  overseerr,
 | 
				
			||||||
 | 
					  openmediavault,
 | 
				
			||||||
  paperlessngx,
 | 
					  paperlessngx,
 | 
				
			||||||
  pfsense,
 | 
					  pfsense,
 | 
				
			||||||
  photoprism,
 | 
					  photoprism,
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user