HealthcheckAlert.tsx raw

   1  import { AlertTriangleIcon, CheckCircle2Icon } from "lucide-react";
   2  import { Alert, AlertDescription, AlertTitle } from "src/components/ui/alert";
   3  import { useHealthCheck } from "src/hooks/useHealthCheck";
   4  import { AlbyInfoIncident, HealthAlarm } from "src/types";
   5  import { ExternalLinkButton } from "../ui/custom/external-link-button";
   6  
   7  export function HealthCheckAlert() {
   8    const { data: health } = useHealthCheck();
   9  
  10    const ok = !health?.alarms?.length;
  11  
  12    if (!health) {
  13      return null;
  14    }
  15  
  16    if (ok) {
  17      return null;
  18    }
  19  
  20    function getAlarmTitle(alarm: HealthAlarm) {
  21      // TODO: could show extra data from alarm.rawDetails
  22      // for some alarm types
  23      try {
  24        switch (alarm.kind) {
  25          case "alby_service":
  26            return (
  27              "Alby Services: " +
  28              (alarm.rawDetails as AlbyInfoIncident[])
  29                ?.map((incident) => `${incident.name} (${incident.status})`)
  30                .join(", ")
  31            );
  32          case "channels_offline":
  33            return "One or more channels are offline";
  34          case "node_not_ready":
  35            return "Node is not ready";
  36          case "nostr_relay_offline":
  37            return (
  38              "Could not connect to relay: " +
  39              (alarm.rawDetails as string[]).join(", ")
  40            );
  41          case "vss_no_subscription":
  42            return "Your lightning channel data is stored encrypted by Alby's Versioned Storage Service which is a paid feature. Restart your subscription or send your funds to another wallet as soon as possible.";
  43        }
  44      } catch (error) {
  45        console.error("failed to parse alarm details", alarm.kind, error);
  46      }
  47      return alarm.kind || "Unknown";
  48    }
  49  
  50    return (
  51      <>
  52        <Alert className="animate-highlight">
  53          {ok ? (
  54            <>
  55              <CheckCircle2Icon className="h-4 w-4" />
  56              <AlertTitle>Alby Hub is running smoothly</AlertTitle>
  57            </>
  58          ) : (
  59            <>
  60              <AlertTriangleIcon className="h-4 w-4" />
  61              <AlertTitle>
  62                {health.alarms.length} issues impacting your hub were found
  63              </AlertTitle>
  64            </>
  65          )}
  66          <AlertDescription>
  67            {health.alarms?.length && (
  68              <ul className="mt-2 whitespace-pre-wrap list-disc list-inside">
  69                {health.alarms?.map((alarm) => (
  70                  <li key={alarm.kind}>{getAlarmTitle(alarm)}</li>
  71                ))}
  72              </ul>
  73            )}
  74            <div className="mt-4 flex gap-2">
  75              <ExternalLinkButton
  76                size="sm"
  77                variant="secondary"
  78                to="https://status.getalby.com"
  79              >
  80                Alby Service Status
  81              </ExternalLinkButton>
  82              <ExternalLinkButton
  83                size="sm"
  84                variant="secondary"
  85                to="https://guides.getalby.com/user-guide/alby-hub/faq/what-happens-if-the-healthcheck-indicator-turns-red"
  86              >
  87                Learn More
  88              </ExternalLinkButton>
  89            </div>
  90          </AlertDescription>
  91        </Alert>
  92      </>
  93    );
  94  }
  95