Add optional boxed styling and error component to information widgets

Signed-off-by: Denis Papec <denis.papec@gmail.com>
pull/1603/head
Denis Papec 1 year ago
parent 3e01fc12e4
commit c5b6dcc1e0
No known key found for this signature in database
GPG Key ID: DE0912C69A47222C

@ -1,5 +1,6 @@
import { useState, useEffect } from "react";
import { useTranslation } from "next-i18next";
import classNames from "classnames";
const textSizes = {
"4xl": "text-4xl",
@ -17,7 +18,7 @@ export default function DateTime({ options }) {
const { i18n } = useTranslation();
const [date, setDate] = useState("");
const dateLocale = locale ?? i18n.language;
useEffect(() => {
const dateFormat = new Intl.DateTimeFormat(dateLocale, { ...format });
const interval = setInterval(() => {
@ -27,7 +28,10 @@ export default function DateTime({ options }) {
}, [date, setDate, dateLocale, format]);
return (
<div className="flex flex-col justify-center first:ml-0 ml-4">
<div className={classNames(
"flex flex-col justify-center first:ml-0 ml-4",
options?.styleBoxed === true && " mt-2 m:mb-0 rounded-md shadow-md shadow-theme-900/10 dark:shadow-theme-900/20 bg-theme-100/20 dark:bg-white/5 p-3",
)}>
<div className="flex flex-row items-center grow justify-end">
<span className={`text-theme-800 dark:text-theme-200 tabular-nums ${textSizes[textSize || "lg"]}`}>
{date}

@ -0,0 +1,23 @@
import { useTranslation } from "react-i18next";
import { BiError } from "react-icons/bi";
import classNames from "classnames";
export default function Error({ options }) {
const { t } = useTranslation();
return (
<div className={classNames(
"flex flex-col justify-center first:ml-0 ml-4 mr-2",
options?.styleBoxed === true && " ml-4 mt-2 m:mb-0 rounded-md shadow-md shadow-theme-900/10 dark:shadow-theme-900/20 bg-theme-100/20 dark:bg-white/5 p-3",
)}>
<div className="flex flex-row items-center justify-end">
<div className="flex flex-col items-center">
<BiError className="w-8 h-8 text-theme-800 dark:text-theme-200" />
<div className="flex flex-col ml-3 text-left">
<span className="text-theme-800 dark:text-theme-200 text-sm">{t("widget.api_error")}</span>
</div>
</div>
</div>
</div>
);
}

@ -1,11 +1,12 @@
import useSWR from "swr";
import { useContext } from "react";
import { BiError } from "react-icons/bi";
import { FaMemory, FaRegClock, FaThermometerHalf } from "react-icons/fa";
import { FiCpu, FiHardDrive } from "react-icons/fi";
import { useTranslation } from "next-i18next";
import classNames from "classnames";
import UsageBar from "../resources/usage-bar";
import Error from "../error";
import { SettingsContext } from "utils/contexts/settings";
@ -26,23 +27,15 @@ export default function Widget({ options }) {
);
if (error || data?.error) {
return (
<div className="flex flex-col justify-center first:ml-0 ml-4">
<div className="flex flex-row items-center justify-end">
<div className="flex flex-row items-center">
<BiError className="w-8 h-8 text-theme-800 dark:text-theme-200" />
<div className="flex flex-col ml-3 text-left">
<span className="text-theme-800 dark:text-theme-200 text-sm">{t("widget.api_error")}</span>
</div>
</div>
</div>
</div>
);
return <Error options={options} />
}
if (!data) {
return (
<div className="flex flex-col max-w:full sm:basis-auto self-center grow-0 flex-wrap ml-4">
<div className={classNames(
"flex flex-col max-w:full sm:basis-auto self-center grow-0 flex-wrap ml-4",
options?.styleBoxed === true && " mb-0 sm:mb-0 rounded-md shadow-md shadow-theme-900/10 dark:shadow-theme-900/20 bg-theme-100/20 dark:bg-white/5 p-3",
)}>
<div className="flex flex-row self-center flex-wrap justify-between">
<div className="flex-none flex flex-row items-center mr-3 py-1.5">
<FiCpu className="text-theme-800 dark:text-theme-200 w-5 h-5" />
@ -101,7 +94,10 @@ export default function Widget({ options }) {
}
return (
<a href={options.url} target={settings.target ?? "_blank"} className="flex flex-col max-w:full sm:basis-auto self-center grow-0 flex-wrap">
<a href={options.url} target={settings.target ?? "_blank"} className={classNames(
"flex flex-col max-w:full sm:basis-auto self-center grow-0 flex-wrap",
options?.styleBoxed === true && " mb-0 mt-2 sm:mb-0 rounded-md shadow-md shadow-theme-900/10 dark:shadow-theme-900/20 bg-theme-100/20 dark:bg-white/5 p-3",
)}>
<div className="flex flex-row self-center flex-wrap justify-between">
<div className="flex-none flex flex-row items-center mr-3 py-1.5">
<FiCpu className="text-theme-800 dark:text-theme-200 w-5 h-5" />
@ -184,7 +180,7 @@ export default function Widget({ options }) {
<div className="flex flex-col ml-3 text-left min-w-[85px]">
<span className="text-theme-800 dark:text-theme-200 text-xs flex flex-row justify-between">
<div className="pl-0.5">
{t("common.number", {
{t("common.number", {
value: mainTemp,
maximumFractionDigits: 1,
style: "unit",
@ -196,7 +192,7 @@ export default function Widget({ options }) {
{options.expanded && (
<span className="text-theme-800 dark:text-theme-200 text-xs flex flex-row justify-between">
<div className="pl-0.5 pr-1">
{t("common.number", {
{t("common.number", {
value: maxTemp,
maximumFractionDigits: 1,
style: "unit",

@ -1,3 +1,5 @@
import classNames from "classnames";
const textSizes = {
"4xl": "text-4xl",
"3xl": "text-3xl",
@ -12,7 +14,10 @@ const textSizes = {
export default function Greeting({ options }) {
if (options.text) {
return (
<div className="flex flex-row items-center justify-start">
<div className={classNames(
"flex flex-row items-center justify-start",
options?.styleBoxed === true && " ml-4 mt-2 m:mb-0 rounded-md shadow-md shadow-theme-900/10 dark:shadow-theme-900/20 bg-theme-100/20 dark:bg-white/5 p-3",
)}>
<span className={`text-theme-800 dark:text-theme-200 mr-3 ${textSizes[options.text_size || "xl"]}`}>
{options.text}
</span>

@ -1,12 +1,14 @@
import useSWR from "swr";
import { BiError } from "react-icons/bi";
import { useTranslation } from "next-i18next";
import classNames from "classnames";
import Error from "../error";
import Node from "./node";
export default function Widget({ options }) {
const { cluster, nodes } = options;
const { t, i18n } = useTranslation();
const { i18n } = useTranslation();
const defaultData = {
cpu: {
@ -29,23 +31,15 @@ export default function Widget({ options }) {
);
if (error || data?.error) {
return (
<div className="flex flex-col justify-center first:ml-0 ml-4">
<div className="flex flex-row items-center justify-end">
<div className="flex flex-row items-center">
<BiError className="w-8 h-8 text-theme-800 dark:text-theme-200" />
<div className="flex flex-col ml-3 text-left">
<span className="text-theme-800 dark:text-theme-200 text-sm">{t("widget.api_error")}</span>
</div>
</div>
</div>
</div>
);
return <Error options={options} />
}
if (!data) {
return (
<div className="flex flex-col max-w:full sm:basis-auto self-center grow-0 flex-wrap">
<div className={classNames(
"flex flex-col max-w:full sm:basis-auto self-center grow-0 flex-wrap",
options?.styleBoxed === true && " ml-4 mt-2 m:mb-0 rounded-md shadow-md shadow-theme-900/10 dark:shadow-theme-900/20 bg-theme-100/20 dark:bg-white/5 p-3",
)}>
<div className="flex flex-row self-center flex-wrap justify-between">
{cluster.show &&
<Node type="cluster" key="cluster" options={options.cluster} data={defaultData} />
@ -59,7 +53,10 @@ export default function Widget({ options }) {
}
return (
<div className="flex flex-col max-w:full sm:basis-auto self-center grow-0 flex-wrap">
<div className={classNames(
"flex flex-col max-w:full sm:basis-auto self-center grow-0 flex-wrap",
options?.styleBoxed === true && " ml-4 mt-2 m:mb-0 rounded-md shadow-md shadow-theme-900/10 dark:shadow-theme-900/20 bg-theme-100/20 dark:bg-white/5 p-3",
)}>
<div className="flex flex-row self-center flex-wrap justify-between">
{cluster.show &&
<Node key="cluster" type="cluster" options={options.cluster} data={data.cluster} />

@ -1,8 +1,13 @@
import classNames from "classnames";
import ResolvedIcon from "components/resolvedicon"
export default function Logo({ options }) {
return (
<div className="w-12 h-12 flex flex-row items-center align-middle mr-3 self-center">
<div className={classNames(
"w-12 h-12 flex flex-row items-center align-middle mr-3 self-center",
options?.styleBoxed === true && " ml-4 mt-2 m:mb-0 rounded-md shadow-md shadow-theme-900/10 dark:shadow-theme-900/20 bg-theme-100/20 dark:bg-white/5 p-3",
)}>
{options.icon ?
<ResolvedIcon icon={options.icon} width={48} height={48} /> :
// fallback to homepage logo

@ -1,37 +1,36 @@
import useSWR from "swr";
import { BiError } from "react-icons/bi";
import { useTranslation } from "next-i18next";
import classNames from "classnames";
import Error from "../error";
import Node from "./node";
export default function Longhorn({ options }) {
const { expanded, total, labels, include, nodes } = options;
const { t } = useTranslation();
const { data, error } = useSWR(`/api/widgets/longhorn`, {
refreshInterval: 1500
});
if (error || data?.error) {
return (
<div className="flex flex-col max-w:full sm:basis-auto self-center grow-0 flex-wrap">
<BiError className="text-theme-800 dark:text-theme-200 w-5 h-5" />
<div className="flex flex-col ml-3 text-left">
<span className="text-theme-800 dark:text-theme-200 text-xs">{t("widget.api_error")}</span>
</div>
</div>
);
return <Error options={options} />
}
if (!data) {
return (
<div className="flex flex-col max-w:full sm:basis-auto self-center grow-0 flex-wrap">
<div className={classNames(
"flex flex-col max-w:full sm:basis-auto self-center grow-0 flex-wrap",
options?.styleBoxed === true && " ml-4 mt-2 m:mb-0 rounded-md shadow-md shadow-theme-900/10 dark:shadow-theme-900/20 bg-theme-100/20 dark:bg-white/5 p-3",
)}>
<div className="flex flex-row self-center flex-wrap justify-between" />
</div>
);
}
return (
<div className="flex flex-col max-w:full sm:basis-auto self-center grow-0 flex-wrap">
<div className={classNames(
"flex flex-col max-w:full sm:basis-auto self-center grow-0 flex-wrap",
options?.styleBoxed === true && " ml-4 mt-2 m:mb-0 rounded-md shadow-md shadow-theme-900/10 dark:shadow-theme-900/20 bg-theme-100/20 dark:bg-white/5 p-3",
)}>
<div className="flex flex-row self-center flex-wrap justify-between">
{data.nodes
.filter((node) => {

@ -1,9 +1,11 @@
import useSWR from "swr";
import { useState } from "react";
import { BiError } from "react-icons/bi";
import { WiCloudDown } from "react-icons/wi";
import { MdLocationDisabled, MdLocationSearching } from "react-icons/md";
import { useTranslation } from "next-i18next";
import classNames from "classnames";
import Error from "../error";
import Icon from "./icon";
@ -15,24 +17,15 @@ function Widget({ options }) {
);
if (error || data?.error) {
return (
<div className="flex flex-col justify-center first:ml-0 ml-4 mr-2">
<div className="flex flex-row items-center justify-end">
<div className="flex flex-col items-center">
<BiError className="w-8 h-8 text-theme-800 dark:text-theme-200" />
<div className="flex flex-col ml-3 text-left">
<span className="text-theme-800 dark:text-theme-200 text-sm">{t("widget.api_error")}</span>
<span className="text-theme-800 dark:text-theme-200 text-xs">-</span>
</div>
</div>
</div>
</div>
);
return <Error options={options} />
}
if (!data) {
return (
<div className="flex flex-col justify-center first:ml-0 ml-4 mr-2">
<div className={classNames(
"flex flex-col justify-center first:ml-0 ml-4 mr-2",
options?.styleBoxed === true && " ml-4 mt-2 m:mb-0 rounded-md shadow-md shadow-theme-900/10 dark:shadow-theme-900/20 bg-theme-100/20 dark:bg-white/5 p-3",
)}>
<div className="flex flex-row items-center justify-end">
<div className="flex flex-col items-center">
<WiCloudDown className="w-8 h-8 text-theme-800 dark:text-theme-200" />
@ -50,7 +43,10 @@ function Widget({ options }) {
const timeOfDay = data.current_weather.time > data.daily.sunrise[0] && data.current_weather.time < data.daily.sunset[0] ? "day" : "night";
return (
<div className="flex flex-col justify-center first:ml-0 ml-4 mr-2">
<div className={classNames(
"flex flex-col justify-center first:ml-0 ml-4 mr-2",
options?.styleBoxed === true && " ml-4 mt-2 m:mb-0 rounded-md shadow-md shadow-theme-900/10 dark:shadow-theme-900/20 bg-theme-100/20 dark:bg-white/5 p-3",
)}>
<div className="flex flex-row items-center justify-end">
<div className="flex flex-col items-center">
<Icon condition={data.current_weather.weathercode} timeOfDay={timeOfDay} />
@ -107,8 +103,10 @@ export default function OpenMeteo({ options }) {
<button
type="button"
onClick={() => requestLocation()}
className="flex flex-col justify-center first:ml-0 ml-4 mr-2"
>
className={classNames(
"flex flex-col justify-center first:ml-0 ml-4 mr-2",
options?.styleBoxed === true && " ml-4 mt-2 m:mb-0 rounded-md shadow-md shadow-theme-900/10 dark:shadow-theme-900/20 bg-theme-100/20 dark:bg-white/5 p-3",
)}>
<div className="flex flex-row items-center justify-end">
<div className="flex flex-col items-center">
{requesting ? (

@ -1,9 +1,11 @@
import useSWR from "swr";
import { useState } from "react";
import { BiError } from "react-icons/bi";
import { WiCloudDown } from "react-icons/wi";
import { MdLocationDisabled, MdLocationSearching } from "react-icons/md";
import { useTranslation } from "next-i18next";
import classNames from "classnames";
import Error from "../error";
import Icon from "./icon";
@ -15,24 +17,15 @@ function Widget({ options }) {
);
if (error || data?.cod === 401 || data?.error) {
return (
<div className="flex flex-col justify-center first:ml-auto ml-4 mr-2">
<div className="flex flex-row items-center justify-end">
<div className="hidden sm:flex flex-col items-center">
<BiError className="w-8 h-8 text-theme-800 dark:text-theme-200" />
<div className="flex flex-col ml-3 text-left">
<span className="text-theme-800 dark:text-theme-200 text-sm">{t("widget.api_error")}</span>
<span className="text-theme-800 dark:text-theme-200 text-xs">-</span>
</div>
</div>
</div>
</div>
);
return <Error options={options} />
}
if (!data) {
return (
<div className="flex flex-col justify-center first:ml-auto ml-4 mr-2">
<div className={classNames(
"flex flex-col justify-center first:ml-auto ml-4 mr-2",
options?.styleBoxed === true && " ml-4 mt-2 m:mb-0 rounded-md shadow-md shadow-theme-900/10 dark:shadow-theme-900/20 bg-theme-100/20 dark:bg-white/5 p-3",
)}>
<div className="flex flex-row items-center justify-end">
<div className="hidden sm:flex flex-col items-center">
<WiCloudDown className="w-8 h-8 text-theme-800 dark:text-theme-200" />
@ -49,7 +42,10 @@ function Widget({ options }) {
const unit = options.units === "metric" ? "celsius" : "fahrenheit";
return (
<div className="flex flex-col justify-center first:ml-auto ml-2 mr-2">
<div className={classNames(
"flex flex-col justify-center first:ml-auto ml-2 mr-2",
options?.styleBoxed === true && " ml-4 mt-2 m:mb-0 rounded-md shadow-md shadow-theme-900/10 dark:shadow-theme-900/20 bg-theme-100/20 dark:bg-white/5 p-3",
)}>
<div className="flex flex-row items-center justify-end">
<div className="hidden sm:flex flex-col items-center">
<Icon
@ -105,7 +101,10 @@ export default function OpenWeatherMap({ options }) {
<button
type="button"
onClick={() => requestLocation()}
className="flex flex-col justify-center first:ml-auto ml-4 mr-2"
className={classNames(
"flex flex-col justify-center first:ml-auto ml-4 mr-2",
options?.styleBoxed === true && " ml-4 mt-2 m:mb-0 rounded-md shadow-md shadow-theme-900/10 dark:shadow-theme-900/20 bg-theme-100/20 dark:bg-white/5 p-3",
)}
>
<div className="flex flex-row items-center justify-end">
<div className="hidden sm:flex flex-col items-center">

@ -1,3 +1,5 @@
import classNames from "classnames";
import Disk from "./disk";
import Cpu from "./cpu";
import Memory from "./memory";
@ -7,7 +9,10 @@ import Uptime from "./uptime";
export default function Resources({ options }) {
const { expanded, units } = options;
return (
<div className="flex flex-col max-w:full sm:basis-auto self-center grow-0 flex-wrap">
<div className={classNames(
"flex flex-col max-w:full sm:basis-auto self-center grow-0 flex-wrap",
options?.styleBoxed === true && " ml-4 mt-2 m:mb-0 rounded-md shadow-md shadow-theme-900/10 dark:shadow-theme-900/20 bg-theme-100/20 dark:bg-white/5 p-3",
)}>
<div className="flex flex-row self-center flex-wrap justify-between">
{options.cpu && <Cpu expanded={expanded} />}
{options.memory && <Memory expanded={expanded} />}

@ -76,7 +76,7 @@ export default function Search({ options }) {
setSelectedProvider(storedProvider);
}
}, [availableProviderIds]);
if (!availableProviderIds) {
return null;
}
@ -102,7 +102,10 @@ export default function Search({ options }) {
}
return (
<form className="flex-col relative h-8 my-4 min-w-fit grow first:ml-0 ml-4" onSubmit={handleSubmit}>
<form className={classNames(
"flex-col relative h-8 my-4 min-w-fit grow first:ml-0 ml-4",
options?.styleBoxed === true && " h-14 ml-4 mt-4 m:mb-0 rounded-md shadow-md shadow-theme-900/10 dark:shadow-theme-900/20 bg-theme-100/20 dark:bg-white/5 p-3",
)} 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-white" />
<input
type="text"
@ -146,8 +149,8 @@ export default function Search({ options }) {
leaveTo="transform opacity-0 scale-95"
>
<Listbox.Options
className="absolute right-0 z-10 mt-1 origin-top-right rounded-md
bg-theme-100 dark:bg-theme-600 shadow-lg
className="absolute right-0 z-10 mt-1 origin-top-right rounded-md
bg-theme-100 dark:bg-theme-600 shadow-lg
ring-1 ring-black ring-opacity-5 focus:outline-none"
>
<div className="flex flex-col">

@ -2,6 +2,9 @@ import { BiError, BiWifi, BiCheckCircle, BiXCircle, BiNetworkChart } from "react
import { MdSettingsEthernet } from "react-icons/md";
import { useTranslation } from "next-i18next";
import { SiUbiquiti } from "react-icons/si";
import classNames from "classnames";
import Error from "../error";
import useWidgetAPI from "utils/proxy/use-widget-api";
@ -13,25 +16,17 @@ export default function Widget({ options }) {
const { data: statsData, error: statsError } = useWidgetAPI(options, "stat/sites", { index: options.index });
if (statsError) {
return (
<div className="flex flex-col justify-center first:ml-0 ml-4">
<div className="flex flex-row items-center justify-end">
<div className="flex flex-col items-center">
<BiError className="w-8 h-8 text-theme-800 dark:text-theme-200" />
<div className="flex flex-col ml-3 text-left">
<span className="text-theme-800 dark:text-theme-200 text-sm">{t("widget.api_error")}</span>
</div>
</div>
</div>
</div>
);
return <Error options={options} />
}
const defaultSite = options.site ? statsData?.data.find(s => s.desc === options.site) : statsData?.data?.find(s => s.name === "default");
if (!defaultSite) {
return (
<div className="flex flex-col justify-center first:ml-0 ml-4">
<div className={classNames(
"flex flex-col justify-center first:ml-0 ml-4",
options?.styleBoxed === true && " ml-4 mt-2 m:mb-0 rounded-md shadow-md shadow-theme-900/10 dark:shadow-theme-900/20 bg-theme-100/20 dark:bg-white/5 p-3",
)}>
<div className="flex flex-row items-center justify-end">
<div className="flex flex-col items-center">
<SiUbiquiti className="w-5 h-5 text-theme-800 dark:text-theme-200" />
@ -57,7 +52,10 @@ export default function Widget({ options }) {
const dataEmpty = !(wan.show || lan.show || wlan.show || uptime);
return (
<div className="flex-none flex flex-row items-center mr-3 py-1.5">
<div className={classNames(
"flex-none flex flex-row items-center mr-3 py-1.5",
options?.styleBoxed === true && " ml-4 mt-2 m:mb-0 rounded-md shadow-md shadow-theme-900/10 dark:shadow-theme-900/20 bg-theme-100/20 dark:bg-white/5 p-3",
)}>
<div className="flex flex-col">
<div className="flex flex-row ml-3 mb-0.5">
<SiUbiquiti className="text-theme-800 dark:text-theme-200 w-3 h-3 mr-1" />

@ -1,9 +1,11 @@
import useSWR from "swr";
import { useState } from "react";
import { BiError } from "react-icons/bi";
import { WiCloudDown } from "react-icons/wi";
import { MdLocationDisabled, MdLocationSearching } from "react-icons/md";
import { useTranslation } from "next-i18next";
import classNames from "classnames";
import Error from "../error";
import Icon from "./icon";
@ -15,24 +17,15 @@ function Widget({ options }) {
);
if (error || data?.error) {
return (
<div className="flex flex-col justify-center first:ml-0 ml-4 mr-2">
<div className="flex flex-row items-center justify-end">
<div className="flex flex-col items-center">
<BiError className="w-8 h-8 text-theme-800 dark:text-theme-200" />
<div className="flex flex-col ml-3 text-left">
<span className="text-theme-800 dark:text-theme-200 text-sm">{t("widget.api_error")}</span>
<span className="text-theme-800 dark:text-theme-200 text-xs">-</span>
</div>
</div>
</div>
</div>
);
return <Error options={options} />
}
if (!data) {
return (
<div className="flex flex-col justify-center first:ml-0 ml-4 mr-2">
<div className={classNames(
"flex flex-col justify-center first:ml-0 ml-4 mr-2",
options?.styleBoxed === true && " ml-4 mt-2 m:mb-0 rounded-md shadow-md shadow-theme-900/10 dark:shadow-theme-900/20 bg-theme-100/20 dark:bg-white/5 p-3",
)}>
<div className="flex flex-row items-center justify-end">
<div className="flex flex-col items-center">
<WiCloudDown className="w-8 h-8 text-theme-800 dark:text-theme-200" />
@ -49,7 +42,10 @@ function Widget({ options }) {
const unit = options.units === "metric" ? "celsius" : "fahrenheit";
return (
<div className="flex flex-col justify-center first:ml-0 ml-4 mr-2">
<div className={classNames(
"flex flex-col justify-center first:ml-0 ml-4 mr-2",
options?.styleBoxed === true && " ml-4 mt-2 m:mb-0 rounded-md shadow-md shadow-theme-900/10 dark:shadow-theme-900/20 bg-theme-100/20 dark:bg-white/5 p-3",
)}>
<div className="flex flex-row items-center justify-end">
<div className="flex flex-col items-center">
<Icon condition={data.current.condition.code} timeOfDay={data.current.is_day ? "day" : "night"} />
@ -106,7 +102,10 @@ export default function WeatherApi({ options }) {
<button
type="button"
onClick={() => requestLocation()}
className="flex flex-col justify-center first:ml-0 ml-4 mr-2"
className={classNames(
"flex flex-col justify-center first:ml-0 ml-4 mr-2",
options?.styleBoxed === true && " ml-4 mt-2 m:mb-0 rounded-md shadow-md shadow-theme-900/10 dark:shadow-theme-900/20 bg-theme-100/20 dark:bg-white/5 p-3",
)}
>
<div className="flex flex-row items-center justify-end">
<div className="flex flex-col items-center">

@ -46,7 +46,7 @@ function parseLonghornData(data) {
export default async function handler(req, res) {
const settings = getSettings();
const longhornSettings = settings?.providers?.longhorn;
const longhornSettings = settings?.providers?.longhorn || {};
const {url, username, password} = longhornSettings;
if (!url) {

Loading…
Cancel
Save