Merge branch 'master' into sevey/composite-actions

This commit is contained in:
Matthew Sevey 2022-04-06 15:34:37 -04:00 committed by GitHub
commit be1a890cc9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
40 changed files with 780 additions and 648 deletions

View File

@ -2,8 +2,8 @@ const { createProxyMiddleware } = require("http-proxy-middleware");
module.exports = { module.exports = {
siteMetadata: { siteMetadata: {
title: `Accounts Dashboard`, title: "Skynet Account",
siteUrl: `https://www.yourdomain.tld`, siteUrl: `https://account.${process.env.GATSBY_PORTAL_DOMAIN}/`,
}, },
trailingSlash: "never", trailingSlash: "never",
plugins: [ plugins: [

View File

@ -83,13 +83,19 @@ export const APIKey = ({ apiKey, onRemoved, onEdited, onRemovalError }) => {
{isPublic && ( {isPublic && (
<button <button
title="Add or remove skylinks" title="Add or remove skylinks"
aria-label="Add or remove skylinks"
className="p-1 transition-colors hover:text-primary" className="p-1 transition-colors hover:text-primary"
onClick={promptEdit} onClick={promptEdit}
> >
<CogIcon size={22} /> <CogIcon size={22} />
</button> </button>
)} )}
<button title="Delete this API key" className="p-1 transition-colors hover:text-error" onClick={promptRemoval}> <button
title="Delete this API key"
aria-label="Delete this API key"
className="p-1 transition-colors hover:text-error"
onClick={promptRemoval}
>
<TrashIcon size={16} /> <TrashIcon size={16} />
</button> </button>
</span> </span>
@ -121,7 +127,11 @@ export const APIKey = ({ apiKey, onRemoved, onEdited, onRemovalError }) => {
<code className="whitespace-nowrap select-all truncate bg-palette-100 odd:bg-white p-1"> <code className="whitespace-nowrap select-all truncate bg-palette-100 odd:bg-white p-1">
{skylink} {skylink}
</code> </code>
<button className="p-1 transition-colors hover:text-error" onClick={() => removeSkylink(skylink)}> <button
className="p-1 transition-colors hover:text-error"
onClick={() => removeSkylink(skylink)}
aria-label="Remove skylink"
>
<TrashIcon size={16} /> <TrashIcon size={16} />
</button> </button>
</li> </li>

View File

@ -22,7 +22,7 @@ const TooltipContent = styled.div.attrs({
className: "bg-primary-light/10 text-palette-600 py-2 px-4 ", className: "bg-primary-light/10 text-palette-600 py-2 px-4 ",
})``; })``;
export const CopyButton = ({ value, className }) => { export const CopyButton = ({ value, className, ariaLabel = "Copy" }) => {
const containerRef = useRef(); const containerRef = useRef();
const [copied, setCopied] = useState(false); const [copied, setCopied] = useState(false);
const [timer, setTimer] = useState(null); const [timer, setTimer] = useState(null);
@ -39,7 +39,7 @@ export const CopyButton = ({ value, className }) => {
return ( return (
<div ref={containerRef} className={`inline-flex relative overflow-visible pr-2 ${className ?? ""}`}> <div ref={containerRef} className={`inline-flex relative overflow-visible pr-2 ${className ?? ""}`}>
<Button onClick={handleCopy} className={copied ? "text-primary" : ""}> <Button onClick={handleCopy} className={copied ? "text-primary" : ""} aria-label={ariaLabel}>
<CopyIcon size={16} /> <CopyIcon size={16} />
</Button> </Button>
<TooltipContainer $visible={copied}> <TooltipContainer $visible={copied}>

View File

@ -101,7 +101,6 @@ export default function CurrentUsage() {
> >
UPGRADE UPGRADE
</Link>{" "} </Link>{" "}
{/* TODO: proper URL */}
<span>{usage.filesLimit}</span> <span>{usage.filesLimit}</span>
</span> </span>
</div> </div>

View File

@ -84,19 +84,19 @@ export default function FileTable({ items }) {
<TableCell className="w-[180px]">{date}</TableCell> <TableCell className="w-[180px]">{date}</TableCell>
<TableCell className="hidden lg:table-cell pr-6 !overflow-visible"> <TableCell className="hidden lg:table-cell pr-6 !overflow-visible">
<div className="flex items-center"> <div className="flex items-center">
<CopyButton value={skylink} className="mr-2" /> <CopyButton value={skylink} className="mr-2" aria-label="Copy skylink" />
<span className="w-full inline-block truncate">{skylink}</span> <span className="w-full inline-block truncate">{skylink}</span>
</div> </div>
</TableCell> </TableCell>
<TableCell className="w-[100px] !overflow-visible"> <TableCell className="w-[100px] !overflow-visible">
<div className="flex text-palette-600 gap-4"> <div className="flex text-palette-600 gap-4">
<PopoverMenu options={buildShareMenu(item)} openClassName="text-primary"> <PopoverMenu options={buildShareMenu(item)} openClassName="text-primary">
<button> <button aria-label="Share this skylink">
<ShareIcon size={22} /> <ShareIcon size={22} />
</button> </button>
</PopoverMenu> </PopoverMenu>
<PopoverMenu options={buildOptionsMenu(item)} openClassName="text-primary"> <PopoverMenu options={buildOptionsMenu(item)} openClassName="text-primary">
<button> <button aria-label="Manage this skylink">
<CogIcon /> <CogIcon />
</button> </button>
</PopoverMenu> </PopoverMenu>

View File

@ -0,0 +1,27 @@
import { Helmet } from "react-helmet";
import { graphql, useStaticQuery } from "gatsby";
export const Metadata = ({ children }) => {
const { site } = useStaticQuery(
graphql`
query Q {
site {
siteMetadata {
title
}
}
}
`
);
const { title } = site.siteMetadata;
return (
<Helmet htmlAttributes={{ lang: "en" }} titleTemplate={`%s | ${title}`} defaultTitle={title}>
<link rel="icon" href="/favicon.ico" type="image/x-icon" />
<meta name="description" content="Manage your Skynet uploads, account subscription, settings and API keys" />
<link rel="preconnect" href={`https://${process.env.GATSBY_PORTAL_DOMAIN}/`} />
{children}
</Helmet>
);
};

View File

@ -0,0 +1 @@
export * from "./Metadata";

View File

@ -11,7 +11,7 @@ export const Modal = ({ children, className, onClose }) => (
<ModalPortal> <ModalPortal>
<Overlay onClick={onClose}> <Overlay onClick={onClose}>
<div className={cn("relative w-modal max-w-modal shadow-sm rounded")}> <div className={cn("relative w-modal max-w-modal shadow-sm rounded")}>
<button onClick={onClose} className="absolute top-[20px] right-[20px]"> <button onClick={onClose} className="absolute top-[20px] right-[20px]" aria-label="Close">
<PlusIcon size={14} className="rotate-45" /> <PlusIcon size={14} className="rotate-45" />
</button> </button>
<Panel className={cn("px-8 py-6 sm:px-12 sm:py-10", className)}>{children}</Panel> <Panel className={cn("px-8 py-6 sm:px-12 sm:py-10", className)}>{children}</Panel>

View File

@ -94,6 +94,7 @@ export const NavBar = () => {
partiallyActive partiallyActive
/> />
<DropdownMenuLink <DropdownMenuLink
as="button"
onClick={onLogout} onClick={onLogout}
activeClassName="text-primary" activeClassName="text-primary"
className="cursor-pointer" className="cursor-pointer"

View File

@ -12,6 +12,7 @@ export default function Bullets({ visibleSlides, activeIndex, allSlides, changeS
.map((_, index) => ( .map((_, index) => (
<button <button
key={index} key={index}
aria-label={`Slide ${index + 1}`}
type="button" type="button"
className={`rounded-full w-3 h-3 ${activeIndex === index ? "bg-primary" : "border-2 cursor-pointer"}`} className={`rounded-full w-3 h-3 ${activeIndex === index ? "bg-primary" : "border-2 cursor-pointer"}`}
onClick={(event) => changeSlide(event, index)} onClick={(event) => changeSlide(event, index)}

View File

@ -105,7 +105,11 @@ const Uploader = ({ mode }) => {
</div> </div>
) : ( ) : (
<div className="p-5"> <div className="p-5">
<Button $primary className="w-[40px] h-[40px] !p-0 inline-flex justify-center items-center"> <Button
$primary
className="w-[40px] h-[40px] !p-0 inline-flex justify-center items-center"
aria-label="Upload new file"
>
<PlusIcon size={12} /> <PlusIcon size={12} />
</Button> </Button>
<span className="ml-4">Add, or drop your files here</span> <span className="ml-4">Add, or drop your files here</span>

View File

@ -44,7 +44,7 @@ export const AddAPIKeyForm = forwardRef(({ onSuccess, type }, ref) => {
<code className="p-2 rounded border border-palette-200 text-xs selection:bg-primary/30 truncate"> <code className="p-2 rounded border border-palette-200 text-xs selection:bg-primary/30 truncate">
{generatedKey} {generatedKey}
</code> </code>
<CopyButton value={generatedKey} className="whitespace-nowrap" /> <CopyButton value={generatedKey} className="whitespace-nowrap" aria-label="Copy the new API key" />
</div> </div>
</Alert> </Alert>
)} )}
@ -94,7 +94,7 @@ export const AddAPIKeyForm = forwardRef(({ onSuccess, type }, ref) => {
{isSubmitting ? ( {isSubmitting ? (
<CircledProgressIcon size={38} className="text-palette-300 animate-[spin_3s_linear_infinite]" /> <CircledProgressIcon size={38} className="text-palette-300 animate-[spin_3s_linear_infinite]" />
) : ( ) : (
<Button type="submit" className="px-2.5"> <Button type="submit" className="px-2.5" aria-label="Create general API key">
<PlusIcon size={14} /> <PlusIcon size={14} />
</Button> </Button>
)} )}

View File

@ -59,7 +59,7 @@ export const AddPublicAPIKeyForm = forwardRef(({ onSuccess }, ref) => {
<code className="p-2 rounded border border-palette-200 text-xs selection:bg-primary/30 truncate"> <code className="p-2 rounded border border-palette-200 text-xs selection:bg-primary/30 truncate">
{generatedKey} {generatedKey}
</code> </code>
<CopyButton value={generatedKey} className="whitespace-nowrap" /> <CopyButton value={generatedKey} className="whitespace-nowrap" aria-label="Copy the new public API key" />
</div> </div>
</Alert> </Alert>
)} )}
@ -137,7 +137,7 @@ export const AddPublicAPIKeyForm = forwardRef(({ onSuccess }, ref) => {
touched={skylinksTouched[index]} touched={skylinksTouched[index]}
/> />
<span className="w-[24px] shrink-0 mt-3"> <span className="w-[24px] shrink-0 mt-3">
<button type="button" onClick={() => remove(index)}> <button type="button" onClick={() => remove(index)} aria-label="Remove this skylink">
<TrashIcon size={16} /> <TrashIcon size={16} />
</button> </button>
</span> </span>
@ -160,6 +160,7 @@ export const AddPublicAPIKeyForm = forwardRef(({ onSuccess }, ref) => {
/> />
<button <button
type="button" type="button"
aria-label="Add this skylink"
onClick={() => appendSkylink(values.nextSkylink)} onClick={() => appendSkylink(values.nextSkylink)}
className={cn("shrink-0 mt-1.5 w-[24px] h-[24px]", { className={cn("shrink-0 mt-1.5 w-[24px] h-[24px]", {
"text-palette-300 cursor-not-allowed": isNextSkylinkInvalid, "text-palette-300 cursor-not-allowed": isNextSkylinkInvalid,

View File

@ -48,7 +48,7 @@ export const AddSkylinkToAPIKeyForm = ({ addSkylink }) => (
{isSubmitting ? ( {isSubmitting ? (
<CircledProgressIcon size={38} className="text-palette-300 animate-[spin_3s_linear_infinite]" /> <CircledProgressIcon size={38} className="text-palette-300 animate-[spin_3s_linear_infinite]" />
) : ( ) : (
<Button type="submit" className="px-2.5"> <Button type="submit" className="px-2.5" aria-label="Add this skylink">
<PlusIcon size={14} /> <PlusIcon size={14} />
</Button> </Button>
)} )}

View File

@ -4,6 +4,7 @@ import { navigate } from "gatsby";
import AuthLayout from "../../layouts/AuthLayout"; import AuthLayout from "../../layouts/AuthLayout";
import { LoginForm } from "../../components/forms"; import { LoginForm } from "../../components/forms";
import { useUser } from "../../contexts/user"; import { useUser } from "../../contexts/user";
import { Metadata } from "../../components/Metadata";
const LoginPage = ({ location }) => { const LoginPage = ({ location }) => {
const { user, mutate: refreshUserState } = useUser(); const { user, mutate: refreshUserState } = useUser();
@ -17,16 +18,21 @@ const LoginPage = ({ location }) => {
}, [user, redirectTo]); }, [user, redirectTo]);
return ( return (
<div className="bg-white px-8 py-10 md:py-32 lg:px-16 xl:px-28 min-h-screen"> <>
<div className="mb-4 md:mb-16"> <Metadata>
<img src="/images/logo-black-text.svg" alt="Skynet" /> <title>Sign In</title>
</Metadata>
<div className="bg-white px-8 py-10 md:py-32 lg:px-16 xl:px-28 min-h-screen">
<div className="mb-4 md:mb-16">
<img src="/images/logo-black-text.svg" alt="Skynet" />
</div>
<LoginForm
onSuccess={async () => {
await refreshUserState();
}}
/>
</div> </div>
<LoginForm </>
onSuccess={async () => {
await refreshUserState();
}}
/>
</div>
); );
}; };

View File

@ -4,6 +4,7 @@ import AuthLayout from "../../layouts/AuthLayout";
import { RecoveryForm } from "../../components/forms/RecoveryForm"; import { RecoveryForm } from "../../components/forms/RecoveryForm";
import HighlightedLink from "../../components/HighlightedLink"; import HighlightedLink from "../../components/HighlightedLink";
import { Metadata } from "../../components/Metadata";
const State = { const State = {
Pure: "PURE", Pure: "PURE",
@ -15,31 +16,36 @@ const ResetPasswordPage = () => {
const [state, setState] = useState(State.Pure); const [state, setState] = useState(State.Pure);
return ( return (
<div className="bg-white px-8 py-10 md:py-32 lg:px-16 xl:px-28 min-h-screen"> <>
<div className="mb-4 md:mb-16"> <Metadata>
<img src="/images/logo-black-text.svg" alt="Skynet" /> <title>Reset Password</title>
</Metadata>
<div className="bg-white px-8 py-10 md:py-32 lg:px-16 xl:px-28 min-h-screen">
<div className="mb-4 md:mb-16">
<img src="/images/logo-black-text.svg" alt="Skynet" />
</div>
{state !== State.Success && (
<RecoveryForm onSuccess={() => setState(State.Success)} onFailure={() => setState(State.Failure)} />
)}
{state === State.Success && (
<p className="text-primary text-center font-semibold">Please check your inbox for further instructions.</p>
)}
{state === State.Failure && (
<p className="text-error text-center">Something went wrong, please try again later.</p>
)}
<div className="text-sm text-center mt-8">
<p>
Suddenly remembered your password? <HighlightedLink to="/auth/login">Sign in</HighlightedLink>
</p>
<p>
Don't actually have an account? <HighlightedLink to="/auth/signup">Create one!</HighlightedLink>
</p>
</div>
</div> </div>
{state !== State.Success && ( </>
<RecoveryForm onSuccess={() => setState(State.Success)} onFailure={() => setState(State.Failure)} />
)}
{state === State.Success && (
<p className="text-primary text-center font-semibold">Please check your inbox for further instructions.</p>
)}
{state === State.Failure && (
<p className="text-error text-center">Something went wrong, please try again later.</p>
)}
<div className="text-sm text-center mt-8">
<p>
Suddenly remembered your password? <HighlightedLink to="/auth/login">Sign in</HighlightedLink>
</p>
<p>
Don't actually have an account? <HighlightedLink to="/auth/signup">Create one!</HighlightedLink>
</p>
</div>
</div>
); );
}; };

View File

@ -9,6 +9,7 @@ import HighlightedLink from "../../components/HighlightedLink";
import { SignUpForm } from "../../components/forms/SignUpForm"; import { SignUpForm } from "../../components/forms/SignUpForm";
import { usePortalSettings } from "../../contexts/portal-settings"; import { usePortalSettings } from "../../contexts/portal-settings";
import { PlansProvider, usePlans } from "../../contexts/plans"; import { PlansProvider, usePlans } from "../../contexts/plans";
import { Metadata } from "../../components/Metadata";
const FreePortalHeader = () => { const FreePortalHeader = () => {
const { plans } = usePlans(); const { plans } = usePlans();
@ -57,6 +58,9 @@ const SignUpPage = () => {
return ( return (
<PlansProvider> <PlansProvider>
<Metadata>
<title>Sign Up</title>
</Metadata>
<div className="bg-white px-8 py-10 md:py-32 lg:px-16 xl:px-28 min-h-screen"> <div className="bg-white px-8 py-10 md:py-32 lg:px-16 xl:px-28 min-h-screen">
<div className="mb-4 md:mb-16"> <div className="mb-4 md:mb-16">
<img src="/images/logo-black-text.svg" alt="Skynet" /> <img src="/images/logo-black-text.svg" alt="Skynet" />

View File

@ -1,28 +1,34 @@
import * as React from "react"; import * as React from "react";
import { useSearchParam } from "react-use";
import DashboardLayout from "../layouts/DashboardLayout"; import DashboardLayout from "../layouts/DashboardLayout";
import { Panel } from "../components/Panel"; import { Panel } from "../components/Panel";
import { Tab, TabPanel, Tabs } from "../components/Tabs"; import { Tab, TabPanel, Tabs } from "../components/Tabs";
import { Metadata } from "../components/Metadata";
import FileList from "../components/FileList/FileList"; import FileList from "../components/FileList/FileList";
import { useSearchParam } from "react-use";
const FilesPage = () => { const FilesPage = () => {
const defaultTab = useSearchParam("tab"); const defaultTab = useSearchParam("tab");
return ( return (
<Panel title="Files"> <>
<Tabs defaultTab={defaultTab || "uploads"}> <Metadata>
<Tab id="uploads" title="Uploads" /> <title>My Files</title>
<Tab id="downloads" title="Downloads" /> </Metadata>
<TabPanel tabId="uploads" className="pt-4"> <Panel title="Files">
<FileList type="uploads" /> <Tabs defaultTab={defaultTab || "uploads"}>
</TabPanel> <Tab id="uploads" title="Uploads" />
<TabPanel tabId="downloads" className="pt-4"> <Tab id="downloads" title="Downloads" />
<FileList type="downloads" /> <TabPanel tabId="uploads" className="pt-4">
</TabPanel> <FileList type="uploads" />
</Tabs> </TabPanel>
</Panel> <TabPanel tabId="downloads" className="pt-4">
<FileList type="downloads" />
</TabPanel>
</Tabs>
</Panel>
</>
); );
}; };

View File

@ -13,6 +13,7 @@ import CurrentUsage from "../components/CurrentUsage";
import Uploader from "../components/Uploader/Uploader"; import Uploader from "../components/Uploader/Uploader";
import CurrentPlan from "../components/CurrentPlan"; import CurrentPlan from "../components/CurrentPlan";
import { FullScreenLoadingIndicator } from "../components/LoadingIndicator"; import { FullScreenLoadingIndicator } from "../components/LoadingIndicator";
import { Metadata } from "../components/Metadata";
import useUpgradeRedirect from "../hooks/useUpgradeRedirect"; import useUpgradeRedirect from "../hooks/useUpgradeRedirect";
const IndexPage = () => { const IndexPage = () => {
@ -24,51 +25,60 @@ const IndexPage = () => {
} }
return ( return (
<PlansProvider> <>
<div className="w-full"> <Metadata>
<Slider <title>Dashboard</title>
slides={[ </Metadata>
<Panel title="Upload" className="h-[330px]"> {verifyingSubscription ? (
<Tabs variant="fill"> <FullScreenLoadingIndicator />
<Tab id="files" title="Files" /> ) : (
<Tab id="directory" title="Directory" /> <PlansProvider>
<TabPanel tabId="files" className="h-full overflow-y-auto"> <div className="w-full">
<Uploader mode="file" /> <Slider
</TabPanel> slides={[
<TabPanel tabId="directory" className="h-full overflow-y-auto"> <Panel title="Upload" className="h-[330px]">
<Uploader mode="directory" /> <Tabs variant="fill">
</TabPanel> <Tab id="files" title="Files" />
</Tabs> <Tab id="directory" title="Directory" />
</Panel>, <TabPanel tabId="files" className="h-full overflow-y-auto">
<Panel <Uploader mode="file" />
title={ </TabPanel>
<> <TabPanel tabId="directory" className="h-full overflow-y-auto">
<ArrowRightIcon /> Usage <Uploader mode="directory" />
</> </TabPanel>
} </Tabs>
className="h-[330px]" </Panel>,
> <Panel
<CurrentUsage /> title={
</Panel>, <>
<Panel <ArrowRightIcon /> Usage
title={ </>
<> }
<ArrowRightIcon /> Current plan className="h-[330px]"
</> >
} <CurrentUsage />
className="h-[330px]" </Panel>,
> <Panel
<CurrentPlan /> title={
</Panel>, <>
]} <ArrowRightIcon /> Current plan
/> </>
</div> }
{showRecentActivity && ( className="h-[330px]"
<div className="mt-10"> >
<LatestActivity /> <CurrentPlan />
</div> </Panel>,
]}
/>
</div>
{showRecentActivity && (
<div className="mt-10">
<LatestActivity />
</div>
)}
</PlansProvider>
)} )}
</PlansProvider> </>
); );
}; };

View File

@ -7,6 +7,7 @@ import { AddAPIKeyForm, APIKeyType } from "../../components/forms/AddAPIKeyForm"
import { APIKeyList } from "../../components/APIKeyList/APIKeyList"; import { APIKeyList } from "../../components/APIKeyList/APIKeyList";
import { Alert } from "../../components/Alert"; import { Alert } from "../../components/Alert";
import { AddPublicAPIKeyForm } from "../../components/forms/AddPublicAPIKeyForm"; import { AddPublicAPIKeyForm } from "../../components/forms/AddPublicAPIKeyForm";
import { Metadata } from "../../components/Metadata";
const APIKeysPage = () => { const APIKeysPage = () => {
const { data: apiKeys = [], mutate: reloadKeys, error } = useSWR("user/apikeys"); const { data: apiKeys = [], mutate: reloadKeys, error } = useSWR("user/apikeys");
@ -29,6 +30,9 @@ const APIKeysPage = () => {
return ( return (
<> <>
<Metadata>
<title>API Keys</title>
</Metadata>
<div className="flex flex-col xl:flex-row"> <div className="flex flex-col xl:flex-row">
<div className="flex flex-col gap-10 lg:shrink-0 lg:max-w-[576px] xl:max-w-[524px]"> <div className="flex flex-col gap-10 lg:shrink-0 lg:max-w-[576px] xl:max-w-[524px]">
<div> <div>

View File

@ -4,6 +4,7 @@ import UserSettingsLayout from "../../layouts/UserSettingsLayout";
import { Switch } from "../../components/Switch"; import { Switch } from "../../components/Switch";
import { Button } from "../../components/Button"; import { Button } from "../../components/Button";
import { Metadata } from "../../components/Metadata";
const useExportOptions = () => { const useExportOptions = () => {
const [pinnedFiles, setPinnedFiles] = useState(false); const [pinnedFiles, setPinnedFiles] = useState(false);
@ -29,6 +30,9 @@ const ExportPage = () => {
return ( return (
<> <>
<Metadata>
<title>Export</title>
</Metadata>
<div className="flex flex-col xl:flex-row"> <div className="flex flex-col xl:flex-row">
<div className="flex flex-col gap-10 lg:shrink-0 lg:max-w-[576px] xl:max-w-[524px]"> <div className="flex flex-col gap-10 lg:shrink-0 lg:max-w-[576px] xl:max-w-[524px]">
<section> <section>

View File

@ -7,6 +7,7 @@ import { AccountSettingsForm } from "../../components/forms/AccountSettingsForm"
import { Modal } from "../../components/Modal/Modal"; import { Modal } from "../../components/Modal/Modal";
import { AccountRemovalForm } from "../../components/forms/AccountRemovalForm"; import { AccountRemovalForm } from "../../components/forms/AccountRemovalForm";
import { Alert } from "../../components/Alert"; import { Alert } from "../../components/Alert";
import { Metadata } from "../../components/Metadata";
const State = { const State = {
Pure: "PURE", Pure: "PURE",
@ -39,6 +40,9 @@ const AccountPage = () => {
return ( return (
<> <>
<Metadata>
<title>Settings</title>
</Metadata>
<div className="flex flex-col xl:flex-row"> <div className="flex flex-col xl:flex-row">
<div className="flex flex-col gap-10 lg:shrink-0 lg:max-w-[576px] xl:max-w-[524px]"> <div className="flex flex-col gap-10 lg:shrink-0 lg:max-w-[576px] xl:max-w-[524px]">
<section> <section>

View File

@ -1,13 +1,17 @@
import * as React from "react"; import * as React from "react";
import { StaticImage } from "gatsby-plugin-image";
import UserSettingsLayout from "../../layouts/UserSettingsLayout"; import UserSettingsLayout from "../../layouts/UserSettingsLayout";
import { Switch } from "../../components/Switch"; import { Switch } from "../../components/Switch";
import { StaticImage } from "gatsby-plugin-image"; import { Metadata } from "../../components/Metadata";
const NotificationsPage = () => { const NotificationsPage = () => {
return ( return (
<> <>
<Metadata>
<title>Notifications</title>
</Metadata>
<div className="flex"> <div className="flex">
<div className="flex flex-col gap-10 lg:shrink-0 lg:max-w-[576px] xl:max-w-[524px]"> <div className="flex flex-col gap-10 lg:shrink-0 lg:max-w-[576px] xl:max-w-[524px]">
<h4>Notifications</h4> <h4>Notifications</h4>

View File

@ -13,6 +13,7 @@ import { Button } from "../components/Button";
import { usePortalSettings } from "../contexts/portal-settings"; import { usePortalSettings } from "../contexts/portal-settings";
import { Alert } from "../components/Alert"; import { Alert } from "../components/Alert";
import HighlightedLink from "../components/HighlightedLink"; import HighlightedLink from "../components/HighlightedLink";
import { Metadata } from "../components/Metadata";
const PAID_PORTAL_BREAKPOINTS = [ const PAID_PORTAL_BREAKPOINTS = [
{ {
@ -88,6 +89,9 @@ const PlansSlider = () => {
return ( return (
<div className="w-full mb-24"> <div className="w-full mb-24">
<Metadata>
<title>Upgrade</title>
</Metadata>
{settings.isSubscriptionRequired && !activePlan && ( {settings.isSubscriptionRequired && !activePlan && (
<Alert $variant="info" className="mb-6"> <Alert $variant="info" className="mb-6">
<p className="font-semibold mt-0">This Skynet portal requires a paid subscription.</p> <p className="font-semibold mt-0">This Skynet portal requires a paid subscription.</p>

View File

@ -5,6 +5,7 @@ import { AllUsersAuthLayout } from "../../layouts/AuthLayout";
import HighlightedLink from "../../components/HighlightedLink"; import HighlightedLink from "../../components/HighlightedLink";
import accountsService from "../../services/accountsService"; import accountsService from "../../services/accountsService";
import { Metadata } from "../../components/Metadata";
const State = { const State = {
Pure: "PURE", Pure: "PURE",
@ -52,24 +53,29 @@ const EmailConfirmationPage = ({ location }) => {
}, [token]); }, [token]);
return ( return (
<div className="bg-white px-8 py-10 md:py-32 lg:px-16 xl:px-28 min-h-screen"> <>
<div className="mb-4 md:mb-16"> <Metadata>
<img src="/images/logo-black-text.svg" alt="Skynet" /> <title>Confirm E-mail Address</title>
</div> </Metadata>
<div className="text-center"> <div className="bg-white px-8 py-10 md:py-32 lg:px-16 xl:px-28 min-h-screen">
{state === State.Pure && <p>Please wait while we verify your account...</p>} <div className="mb-4 md:mb-16">
<img src="/images/logo-black-text.svg" alt="Skynet" />
</div>
<div className="text-center">
{state === State.Pure && <p>Please wait while we verify your account...</p>}
{state === State.Success && ( {state === State.Success && (
<> <>
<p className="text-primary font-semibold">All done!</p> <p className="text-primary font-semibold">All done!</p>
<p>You will be redirected to your dashboard shortly.</p> <p>You will be redirected to your dashboard shortly.</p>
<HighlightedLink to="/">Redirect now.</HighlightedLink> <HighlightedLink to="/">Redirect now.</HighlightedLink>
</> </>
)} )}
{state === State.Failure && <p className="text-error">Something went wrong, please try again later.</p>} {state === State.Failure && <p className="text-error">Something went wrong, please try again later.</p>}
</div>
</div> </div>
</div> </>
); );
}; };

View File

@ -5,6 +5,7 @@ import AuthLayout from "../../layouts/AuthLayout";
import { ResetPasswordForm } from "../../components/forms/ResetPasswordForm"; import { ResetPasswordForm } from "../../components/forms/ResetPasswordForm";
import HighlightedLink from "../../components/HighlightedLink"; import HighlightedLink from "../../components/HighlightedLink";
import { Metadata } from "../../components/Metadata";
const State = { const State = {
Pure: "PURE", Pure: "PURE",
@ -19,35 +20,40 @@ const RecoverPage = ({ location }) => {
const [state, setState] = useState(State.Pure); const [state, setState] = useState(State.Pure);
return ( return (
<div className="bg-white px-8 py-10 md:py-32 lg:px-16 xl:px-28 min-h-screen"> <>
<div className="mb-4 md:mb-16"> <Metadata>
<img src="/images/logo-black-text.svg" alt="Skynet" /> <title>Recover Your Account</title>
</div> </Metadata>
{state !== State.Success && ( <div className="bg-white px-8 py-10 md:py-32 lg:px-16 xl:px-28 min-h-screen">
<ResetPasswordForm <div className="mb-4 md:mb-16">
token={token} <img src="/images/logo-black-text.svg" alt="Skynet" />
onSuccess={() => { </div>
setState(State.Success); {state !== State.Success && (
navigate("/"); <ResetPasswordForm
}} token={token}
onFailure={() => setState(State.Failure)} onSuccess={() => {
/> setState(State.Success);
)} navigate("/");
}}
onFailure={() => setState(State.Failure)}
/>
)}
{state === State.Success && ( {state === State.Success && (
<p className="text-primary text-center font-semibold"> <p className="text-primary text-center font-semibold">
All done! You will be redirected to your dashboard shortly. All done! You will be redirected to your dashboard shortly.
</p>
)}
{state === State.Failure && (
<p className="text-error text-center">Something went wrong, please try again later.</p>
)}
<p className="text-sm text-center mt-8">
Suddenly remembered your old password? <HighlightedLink to="/auth/login">Sign in</HighlightedLink>
</p> </p>
)} </div>
</>
{state === State.Failure && (
<p className="text-error text-center">Something went wrong, please try again later.</p>
)}
<p className="text-sm text-center mt-8">
Suddenly remembered your old password? <HighlightedLink to="/auth/login">Sign in</HighlightedLink>
</p>
</div>
); );
}; };

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -11,7 +11,7 @@
"@fontsource/sora": "4.5.5", "@fontsource/sora": "4.5.5",
"@fontsource/source-sans-pro": "4.5.6", "@fontsource/source-sans-pro": "4.5.6",
"@stripe/react-stripe-js": "1.7.0", "@stripe/react-stripe-js": "1.7.0",
"@stripe/stripe-js": "1.25.0", "@stripe/stripe-js": "1.26.0",
"classnames": "2.3.1", "classnames": "2.3.1",
"copy-text-to-clipboard": "^3.0.1", "copy-text-to-clipboard": "^3.0.1",
"dayjs": "1.11.0", "dayjs": "1.11.0",
@ -20,14 +20,14 @@
"formik": "2.2.9", "formik": "2.2.9",
"http-status-codes": "2.2.0", "http-status-codes": "2.2.0",
"ky": "0.30.0", "ky": "0.30.0",
"next": "12.1.1", "next": "12.1.4",
"normalize.css": "8.0.1", "normalize.css": "8.0.1",
"pretty-bytes": "6.0.0", "pretty-bytes": "6.0.0",
"react": "17.0.2", "react": "17.0.2",
"react-dom": "17.0.2", "react-dom": "17.0.2",
"react-toastify": "8.2.0", "react-toastify": "8.2.0",
"skynet-js": "3.0.2", "skynet-js": "3.0.2",
"stripe": "8.212.0", "stripe": "8.215.0",
"swr": "1.2.2", "swr": "1.2.2",
"yup": "0.32.11" "yup": "0.32.11"
}, },
@ -36,9 +36,9 @@
"@tailwindcss/typography": "0.5.2", "@tailwindcss/typography": "0.5.2",
"autoprefixer": "10.4.4", "autoprefixer": "10.4.4",
"eslint": "8.12.0", "eslint": "8.12.0",
"eslint-config-next": "12.1.1", "eslint-config-next": "12.1.4",
"postcss": "8.4.12", "postcss": "8.4.12",
"prettier": "2.6.1", "prettier": "2.6.2",
"tailwindcss": "3.0.23" "tailwindcss": "3.0.23"
} }
} }

View File

@ -77,77 +77,77 @@
resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45"
integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==
"@next/env@12.1.1": "@next/env@12.1.4":
version "12.1.1" version "12.1.4"
resolved "https://registry.yarnpkg.com/@next/env/-/env-12.1.1.tgz#8a927397697ee9d94852feb5fed57a813d299979" resolved "https://registry.yarnpkg.com/@next/env/-/env-12.1.4.tgz#5af629b43075281ecd7f87938802b7cf5b67e94b"
integrity sha512-VmTRkfo/IXOQCATndjW3OjKb8zmAuB07eDdzO9XvuXZP87SyvnCYw3jrhUuFhOe/FVsKiloafa5LJfToUpvjUQ== integrity sha512-7gQwotJDKnfMxxXd8xJ2vsX5AzyDxO3zou0+QOXX8/unypA6icw5+wf6A62yKZ6qQ4UZHHxS68pb6UV+wNneXg==
"@next/eslint-plugin-next@12.1.1": "@next/eslint-plugin-next@12.1.4":
version "12.1.1" version "12.1.4"
resolved "https://registry.yarnpkg.com/@next/eslint-plugin-next/-/eslint-plugin-next-12.1.1.tgz#e3e51503e9d7f987a0e080344648bc84ac1e8eb8" resolved "https://registry.yarnpkg.com/@next/eslint-plugin-next/-/eslint-plugin-next-12.1.4.tgz#9c52637af8eecab24dac3f2e5098376f6fc2dff4"
integrity sha512-5hd1VFWZzECADhvA+OE+g0CnrRBFZbPm03HbiUtpk7XeluNn7xVxBU6XvNQA+YrQ7qe5jCK9q7R8MbI9R55Y/Q== integrity sha512-BRy565KVK6Cdy8LHaHTiwctLqBu/RT84RLpESug70BDJzBlV8QBvODyx/j7wGhvYqp9kvstM05lyb6JaTkSCcQ==
dependencies: dependencies:
glob "7.1.7" glob "7.1.7"
"@next/swc-android-arm-eabi@12.1.1": "@next/swc-android-arm-eabi@12.1.4":
version "12.1.1" version "12.1.4"
resolved "https://registry.yarnpkg.com/@next/swc-android-arm-eabi/-/swc-android-arm-eabi-12.1.1.tgz#2b134efb6639a770db10688a93ce0d2a9362fc5e" resolved "https://registry.yarnpkg.com/@next/swc-android-arm-eabi/-/swc-android-arm-eabi-12.1.4.tgz#c3dae178b7c15ad627d2e9b8dfb38caecb5c4ac7"
integrity sha512-phV9H6d1eK1oVC7nmKKcCXvgOWT4K7aLC/beyO6yvbFC4XtBLE21vPwVl7B4ybz5xjSa6TXoR3TMR6vkW6Mv+A== integrity sha512-FJg/6a3s2YrUaqZ+/DJZzeZqfxbbWrynQMT1C5wlIEq9aDLXCFpPM/PiOyJh0ahxc0XPmi6uo38Poq+GJTuKWw==
"@next/swc-android-arm64@12.1.1": "@next/swc-android-arm64@12.1.4":
version "12.1.1" version "12.1.4"
resolved "https://registry.yarnpkg.com/@next/swc-android-arm64/-/swc-android-arm64-12.1.1.tgz#4fc66990c71c066f99fc435c0e8a4b3191bdfb4a" resolved "https://registry.yarnpkg.com/@next/swc-android-arm64/-/swc-android-arm64-12.1.4.tgz#f320d60639e19ecffa1f9034829f2d95502a9a51"
integrity sha512-X5qEz0YeeYT0Gz2wXPAEtRKEuAsLUIEgC/DDfS98t/5Idjv0S4aqIX+TQdzoXP5bwQkIr+mSg+MBIdLtbtnCsA== integrity sha512-LXraazvQQFBgxIg3Htny6G5V5he9EK7oS4jWtMdTGIikmD/OGByOv8ZjLuVLZLtVm3UIvaAiGtlQSLecxJoJDw==
"@next/swc-darwin-arm64@12.1.1": "@next/swc-darwin-arm64@12.1.4":
version "12.1.1" version "12.1.4"
resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-12.1.1.tgz#a5b4ea73ebf769f48dae97942b6b6fbeaf3f1dfc" resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-12.1.4.tgz#fd578278312613eddcf3aee26910100509941b63"
integrity sha512-bKKSNaTdnO3XPnfaR4NSpPcbs80fdbtOYC2lgtqLzA0bOMioupixMP5GrA/gfJHwh7GRH+A+sbgKQWsqSsYAqQ== integrity sha512-SSST/dBymecllZxcqTCcSTCu5o1NKk9I+xcvhn/O9nH6GWjgvGgGkNqLbCarCa0jJ1ukvlBA138FagyrmZ/4rQ==
"@next/swc-darwin-x64@12.1.1": "@next/swc-darwin-x64@12.1.4":
version "12.1.1" version "12.1.4"
resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-12.1.1.tgz#064d50c08d9eec0fc1ff76e190d4fe43184aa8b7" resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-12.1.4.tgz#ace5f80d8c8348efe194f6d7074c6213c52b3944"
integrity sha512-2VOsA6WLDuDBA6935djohWGGeUIKeQhXwDwu1CKx1b8+6YMMIvFr/y2dpPWoct+5/IjFz84a2MnbABwpoNB9YA== integrity sha512-p1lwdX0TVjaoDXQVuAkjtxVBbCL/urgxiMCBwuPDO7TikpXtSRivi+mIzBj5q7ypgICFmIAOW3TyupXeoPRAnA==
"@next/swc-linux-arm-gnueabihf@12.1.1": "@next/swc-linux-arm-gnueabihf@12.1.4":
version "12.1.1" version "12.1.4"
resolved "https://registry.yarnpkg.com/@next/swc-linux-arm-gnueabihf/-/swc-linux-arm-gnueabihf-12.1.1.tgz#6cd6edda7f17ad1ceb1cd242419d93a643b1de31" resolved "https://registry.yarnpkg.com/@next/swc-linux-arm-gnueabihf/-/swc-linux-arm-gnueabihf-12.1.4.tgz#2bf2c83863635f19c71c226a2df936e001cce29c"
integrity sha512-1urXtWwqjqbbpJBWeJYz5ATgelKacVNdKIdhfahbsmW+DZGoK5TYovgieyHFYUCyHdTuKeLTVR62ahIRUBv1YA== integrity sha512-67PZlgkCn3TDxacdVft0xqDCL7Io1/C4xbAs0+oSQ0xzp6OzN2RNpuKjHJrJgKd0DsE1XZ9sCP27Qv0591yfyg==
"@next/swc-linux-arm64-gnu@12.1.1": "@next/swc-linux-arm64-gnu@12.1.4":
version "12.1.1" version "12.1.4"
resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-12.1.1.tgz#d480c71de4150728c0c67a363c7f17291db3f070" resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-12.1.4.tgz#d577190f641c9b4b463719dd6b8953b6ba9be8d9"
integrity sha512-CDD9yFuknDvTOzzDnvfmb58USI5Vu6FUyzw96udKj7KA/n1YrNQ4K8X7KsDCRZoqfRWYceAyj1EpwHkfdiB7bg== integrity sha512-OnOWixhhw7aU22TQdQLYrgpgFq0oA1wGgnjAiHJ+St7MLj82KTDyM9UcymAMbGYy6nG/TFOOHdTmRMtCRNOw0g==
"@next/swc-linux-arm64-musl@12.1.1": "@next/swc-linux-arm64-musl@12.1.4":
version "12.1.1" version "12.1.4"
resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-12.1.1.tgz#9578705269b746617c763c1ac5c5b26084f1e5ce" resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-12.1.4.tgz#e70ffe70393d8f9242deecdb282ce5a8fd588b14"
integrity sha512-nxyjgmbOpZm7gGPj9EV5Cqosoujt+ih/8SO2XG+BetgfAk0+c15793DHVAljNuc8GF9wpzqQnjMMUZ211VmQsg== integrity sha512-UoRMzPZnsAavdWtVylYxH8DNC7Uy0i6RrvNwT4PyQVdfANBn2omsUkcH5lgS2O7oaz0nAYLk1vqyZDO7+tJotA==
"@next/swc-linux-x64-gnu@12.1.1": "@next/swc-linux-x64-gnu@12.1.4":
version "12.1.1" version "12.1.4"
resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-12.1.1.tgz#40f3c79b65b6cfc880e6131a25f7936716ded1b9" resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-12.1.4.tgz#91498a130387fb1961902f2bee55863f8e910cff"
integrity sha512-L8Cu8kH3Vn2dnRpvcvGGA1TlmDP2WXJ+qDwvjb/ikDXLdRdmFvJwHh45JUGiW2FHed3lGseOgNsuYiDvnT8Cdw== integrity sha512-nM+MA/frxlTLUKLJKorctdI20/ugfHRjVEEkcLp/58LGG7slNaP1E5d5dRA1yX6ISjPcQAkywas5VlGCg+uTvA==
"@next/swc-linux-x64-musl@12.1.1": "@next/swc-linux-x64-musl@12.1.4":
version "12.1.1" version "12.1.4"
resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-12.1.1.tgz#922ea0306d36b5fd860d8cc5a6f4c53dca09395c" resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-12.1.4.tgz#78057b03c148c121553d41521ad38f6c732762ff"
integrity sha512-4RAb7L69MoRSggBqUfF3OrtBCUN2zPDi7asfL7bfxEhH10LGzyfil8dT0GVjPOPFz/SyLx3ORd6avGij2IlJUA== integrity sha512-GoRHxkuW4u4yKw734B9SzxJwVdyEJosaZ62P7ifOwcujTxhgBt3y76V2nNUrsSuopcKI2ZTDjaa+2wd5zyeXbA==
"@next/swc-win32-arm64-msvc@12.1.1": "@next/swc-win32-arm64-msvc@12.1.4":
version "12.1.1" version "12.1.4"
resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-12.1.1.tgz#be13af4e33c071e6ec97b2cfead51eb57ecf189b" resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-12.1.4.tgz#05bbaabacac23b8edf6caa99eb86b17550a09051"
integrity sha512-zvkuNIgOxkAU3RbzWRGCcFasDxWJdhONt2YeRGe39dJERHhEFA1u4HgaZw/SFE/kfrNRUZbXjJNAg3OU/EpPZw== integrity sha512-6TQkQze0ievXwHJcVUrIULwCYVe3ccX6T0JgZ1SiMeXpHxISN7VJF/O8uSCw1JvXZYZ6ud0CJ7nfC5HXivgfPg==
"@next/swc-win32-ia32-msvc@12.1.1": "@next/swc-win32-ia32-msvc@12.1.4":
version "12.1.1" version "12.1.4"
resolved "https://registry.yarnpkg.com/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-12.1.1.tgz#2a5adb993542fc54fedfd525c69593f75c055595" resolved "https://registry.yarnpkg.com/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-12.1.4.tgz#8fd2fb48f04a2802e51fc320878bf6b411c1c866"
integrity sha512-GsNDtZ//uKWNVjiwv3YKQYsDXuRWTz8jTmxopf5Ws3dK+zA77hn4o46LBQg0JPCNqTUO6eIOlUBjqSL6ejxmSQ== integrity sha512-CsbX/IXuZ5VSmWCpSetG2HD6VO5FTsO39WNp2IR2Ut/uom9XtLDJAZqjQEnbUTLGHuwDKFjrIO3LkhtROXLE/g==
"@next/swc-win32-x64-msvc@12.1.1": "@next/swc-win32-x64-msvc@12.1.4":
version "12.1.1" version "12.1.4"
resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-12.1.1.tgz#21c12feb6acf75cac7c1ae4ca7f251aa1943f081" resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-12.1.4.tgz#a72ed44c9b1f850986a30fe36c59e01f8a79b5f3"
integrity sha512-nH5osn/uK9wsjT8Jh1YxMtRrkN5hoCNLQjsEdvfUfb+loQXeYiBd3n/0DUJkf6Scjfv6/htfUTPP3AEa7AbBxQ== integrity sha512-JtYuWzKXKLDMgE/xTcFtCm1MiCIRaAc5XYZfYX3n/ZWSI1SJS/GMm+Su0SAHJgRFavJh6U/p998YwO/iGTIgqQ==
"@nodelib/fs.scandir@2.1.5": "@nodelib/fs.scandir@2.1.5":
version "2.1.5" version "2.1.5"
@ -182,10 +182,10 @@
dependencies: dependencies:
prop-types "^15.7.2" prop-types "^15.7.2"
"@stripe/stripe-js@1.25.0": "@stripe/stripe-js@1.26.0":
version "1.25.0" version "1.26.0"
resolved "https://registry.yarnpkg.com/@stripe/stripe-js/-/stripe-js-1.25.0.tgz#74334e3f9971e8dfd352a67581c6e02dc5c2ebf8" resolved "https://registry.yarnpkg.com/@stripe/stripe-js/-/stripe-js-1.26.0.tgz#45670924753c01e18d0544ea1f1067b474aaa96f"
integrity sha512-cywIoKu3sJnBPQ1eKi3BzFHWslA2ePqHvQhcxp7iYYlo1tWcVgEKTSh7y7hb6GoR4TyT3DwlK4v1vOZpVg8u4Q== integrity sha512-4R1vC75yKaCVFARW3bhelf9+dKt4NP4iZY/sIjGK7AAMBVvZ47eG74NvsAIUdUnhOXSWFMjdFWqv+etk5BDW4g==
"@tailwindcss/forms@0.5.0": "@tailwindcss/forms@0.5.0":
version "0.5.0" version "0.5.0"
@ -786,12 +786,12 @@ escape-string-regexp@^4.0.0:
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34"
integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==
eslint-config-next@12.1.1: eslint-config-next@12.1.4:
version "12.1.1" version "12.1.4"
resolved "https://registry.yarnpkg.com/eslint-config-next/-/eslint-config-next-12.1.1.tgz#11f948c5f4959267c2157dff8f2c28d067e3e1d9" resolved "https://registry.yarnpkg.com/eslint-config-next/-/eslint-config-next-12.1.4.tgz#939ea2ff33034763300bf1e62482cea91212d274"
integrity sha512-+Ql9F07Pafs+cDgy8Zp0F8FxCBq7ke02ZyC2/MMEiGAX+WlnuUCrboBDnfzmHJpAAkcBPjUthunu6LBnF9KWIQ== integrity sha512-Uj0jrVjoQbg9qerxRjSHoOOv3PEzoZxpb8G9LYct25fsflP8xIiUq0l4WEu2KSB5owuLv5hie7wSMqPEsHj+bQ==
dependencies: dependencies:
"@next/eslint-plugin-next" "12.1.1" "@next/eslint-plugin-next" "12.1.4"
"@rushstack/eslint-patch" "1.0.8" "@rushstack/eslint-patch" "1.0.8"
"@typescript-eslint/parser" "5.10.1" "@typescript-eslint/parser" "5.10.1"
eslint-import-resolver-node "0.3.4" eslint-import-resolver-node "0.3.4"
@ -1693,29 +1693,28 @@ natural-compare@^1.4.0:
resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=
next@12.1.1: next@12.1.4:
version "12.1.1" version "12.1.4"
resolved "https://registry.yarnpkg.com/next/-/next-12.1.1.tgz#f5e73d3a204da0632484a56040c23a4796958bc6" resolved "https://registry.yarnpkg.com/next/-/next-12.1.4.tgz#597a9bdec7aec778b442c4f6d41afd2c64a54b23"
integrity sha512-IOfEIAgroMtsoYz6HXpDS+b5WB9WZ+MH266COXGlcpIiYSgUyJf9xV6vF+zY2RPvBJFT4fUW0EVdVnoOmTloDw== integrity sha512-DA4g97BM4Z0nKtDvCTm58RxdvoQyYzeg0AeVbh0N4Y/D8ELrNu47lQeEgRGF8hV4eQ+Sal90zxrJQQG/mPQ8CQ==
dependencies: dependencies:
"@next/env" "12.1.1" "@next/env" "12.1.4"
caniuse-lite "^1.0.30001283" caniuse-lite "^1.0.30001283"
postcss "8.4.5" postcss "8.4.5"
styled-jsx "5.0.1" styled-jsx "5.0.1"
use-subscription "1.5.1"
optionalDependencies: optionalDependencies:
"@next/swc-android-arm-eabi" "12.1.1" "@next/swc-android-arm-eabi" "12.1.4"
"@next/swc-android-arm64" "12.1.1" "@next/swc-android-arm64" "12.1.4"
"@next/swc-darwin-arm64" "12.1.1" "@next/swc-darwin-arm64" "12.1.4"
"@next/swc-darwin-x64" "12.1.1" "@next/swc-darwin-x64" "12.1.4"
"@next/swc-linux-arm-gnueabihf" "12.1.1" "@next/swc-linux-arm-gnueabihf" "12.1.4"
"@next/swc-linux-arm64-gnu" "12.1.1" "@next/swc-linux-arm64-gnu" "12.1.4"
"@next/swc-linux-arm64-musl" "12.1.1" "@next/swc-linux-arm64-musl" "12.1.4"
"@next/swc-linux-x64-gnu" "12.1.1" "@next/swc-linux-x64-gnu" "12.1.4"
"@next/swc-linux-x64-musl" "12.1.1" "@next/swc-linux-x64-musl" "12.1.4"
"@next/swc-win32-arm64-msvc" "12.1.1" "@next/swc-win32-arm64-msvc" "12.1.4"
"@next/swc-win32-ia32-msvc" "12.1.1" "@next/swc-win32-ia32-msvc" "12.1.4"
"@next/swc-win32-x64-msvc" "12.1.1" "@next/swc-win32-x64-msvc" "12.1.4"
node-releases@^2.0.2: node-releases@^2.0.2:
version "2.0.2" version "2.0.2"
@ -1956,10 +1955,10 @@ prelude-ls@^1.2.1:
resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396"
integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==
prettier@2.6.1: prettier@2.6.2:
version "2.6.1" version "2.6.2"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.6.1.tgz#d472797e0d7461605c1609808e27b80c0f9cfe17" resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.6.2.tgz#e26d71a18a74c3d0f0597f55f01fb6c06c206032"
integrity sha512-8UVbTBYGwN37Bs9LERmxCPjdvPxlEowx2urIL6urHzdb3SDq4B/Z6xLFCblrSnE4iKWcS6ziJ3aOYrc1kz/E2A== integrity sha512-PkUpF+qoXTqhOeWL9fu7As8LXsIUZ1WYaJiY/a7McAQzxjk82OF0tibkFXVCDImZtWxbvojFjerkiLb0/q8mew==
pretty-bytes@6.0.0: pretty-bytes@6.0.0:
version "6.0.0" version "6.0.0"
@ -1994,10 +1993,10 @@ punycode@^2.1.0:
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==
qs@^6.6.0: qs@^6.10.3:
version "6.10.1" version "6.10.3"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.10.1.tgz#4931482fa8d647a5aab799c5271d2133b981fb6a" resolved "https://registry.yarnpkg.com/qs/-/qs-6.10.3.tgz#d6cde1b2ffca87b5aa57889816c5f81535e22e8e"
integrity sha512-M528Hph6wsSVOBiYUnGf+K/7w0hNshs/duGsNXPUCLH5XAqjEtiPGwNONLV0tBH8NoGb0mvD5JubnUTrujKDTg== integrity sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==
dependencies: dependencies:
side-channel "^1.0.4" side-channel "^1.0.4"
@ -2265,13 +2264,13 @@ strip-json-comments@^3.1.0, strip-json-comments@^3.1.1:
resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006"
integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==
stripe@8.212.0: stripe@8.215.0:
version "8.212.0" version "8.215.0"
resolved "https://registry.yarnpkg.com/stripe/-/stripe-8.212.0.tgz#78dc8d2be770580be23a8e597641a9ace6fd1035" resolved "https://registry.yarnpkg.com/stripe/-/stripe-8.215.0.tgz#bb464e256fb83da9ea2f514711fd0f6f7ae7dc9a"
integrity sha512-xQ2uPMRAmRyOiMZktw3hY8jZ8LFR9lEQRPEaQ5WcDcn51kMyn46GeikOikxiFTHEN8PeKRdwtpz4yNArAvu/Kg== integrity sha512-M+7iTZ9bzTkU1Ms+Zsuh0mTQfEzOjMoqyEaVBpuUmdbWTvshavzpAihsOkfabEu+sNY0vdbQxxHZ4kI3W8pKHQ==
dependencies: dependencies:
"@types/node" ">=8.1.0" "@types/node" ">=8.1.0"
qs "^6.6.0" qs "^6.10.3"
styled-jsx@5.0.1: styled-jsx@5.0.1:
version "5.0.1" version "5.0.1"
@ -2425,13 +2424,6 @@ url-parse@^1.4.7:
querystringify "^2.1.1" querystringify "^2.1.1"
requires-port "^1.0.0" requires-port "^1.0.0"
use-subscription@1.5.1:
version "1.5.1"
resolved "https://registry.yarnpkg.com/use-subscription/-/use-subscription-1.5.1.tgz#73501107f02fad84c6dd57965beb0b75c68c42d1"
integrity sha512-Xv2a1P/yReAjAbhylMfFplFKj9GssgTwN7RlcTxBujFQcloStWNDQdc4g4NRWH9xS4i/FDk04vQBptAXoF3VcA==
dependencies:
object-assign "^4.1.1"
util-deprecate@^1.0.2: util-deprecate@^1.0.2:
version "1.0.2" version "1.0.2"
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"

View File

@ -8,6 +8,6 @@
"is-valid-domain": "^0.1.6" "is-valid-domain": "^0.1.6"
}, },
"devDependencies": { "devDependencies": {
"prettier": "^2.6.1" "prettier": "^2.6.2"
} }
} }

View File

@ -265,10 +265,10 @@ path-to-regexp@0.1.7:
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c"
integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w= integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=
prettier@^2.6.1: prettier@^2.6.2:
version "2.6.1" version "2.6.2"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.6.1.tgz#d472797e0d7461605c1609808e27b80c0f9cfe17" resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.6.2.tgz#e26d71a18a74c3d0f0597f55f01fb6c06c206032"
integrity sha512-8UVbTBYGwN37Bs9LERmxCPjdvPxlEowx2urIL6urHzdb3SDq4B/Z6xLFCblrSnE4iKWcS6ziJ3aOYrc1kz/E2A== integrity sha512-PkUpF+qoXTqhOeWL9fu7As8LXsIUZ1WYaJiY/a7McAQzxjk82OF0tibkFXVCDImZtWxbvojFjerkiLb0/q8mew==
proxy-addr@~2.0.7: proxy-addr@~2.0.7:
version "2.0.7" version "2.0.7"

View File

@ -10,6 +10,6 @@
"punycode": "^2.1.1" "punycode": "^2.1.1"
}, },
"devDependencies": { "devDependencies": {
"prettier": "^2.6.1" "prettier": "^2.6.2"
} }
} }

View File

@ -314,10 +314,10 @@ path-to-regexp@0.1.7:
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c"
integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w= integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=
prettier@^2.6.1: prettier@^2.6.2:
version "2.6.1" version "2.6.2"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.6.1.tgz#d472797e0d7461605c1609808e27b80c0f9cfe17" resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.6.2.tgz#e26d71a18a74c3d0f0597f55f01fb6c06c206032"
integrity sha512-8UVbTBYGwN37Bs9LERmxCPjdvPxlEowx2urIL6urHzdb3SDq4B/Z6xLFCblrSnE4iKWcS6ziJ3aOYrc1kz/E2A== integrity sha512-PkUpF+qoXTqhOeWL9fu7As8LXsIUZ1WYaJiY/a7McAQzxjk82OF0tibkFXVCDImZtWxbvojFjerkiLb0/q8mew==
proxy-addr@~2.0.7: proxy-addr@~2.0.7:
version "2.0.7" version "2.0.7"

View File

@ -19,6 +19,6 @@
}, },
"devDependencies": { "devDependencies": {
"jest": "^27.5.1", "jest": "^27.5.1",
"prettier": "^2.6.1" "prettier": "^2.6.2"
} }
} }

View File

@ -2643,10 +2643,10 @@ prelude-ls@~1.1.2:
resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54"
integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=
prettier@^2.6.1: prettier@^2.6.2:
version "2.6.1" version "2.6.2"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.6.1.tgz#d472797e0d7461605c1609808e27b80c0f9cfe17" resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.6.2.tgz#e26d71a18a74c3d0f0597f55f01fb6c06c206032"
integrity sha512-8UVbTBYGwN37Bs9LERmxCPjdvPxlEowx2urIL6urHzdb3SDq4B/Z6xLFCblrSnE4iKWcS6ziJ3aOYrc1kz/E2A== integrity sha512-PkUpF+qoXTqhOeWL9fu7As8LXsIUZ1WYaJiY/a7McAQzxjk82OF0tibkFXVCDImZtWxbvojFjerkiLb0/q8mew==
pretty-format@^27.5.1: pretty-format@^27.5.1:
version "27.5.1" version "27.5.1"

View File

@ -13,10 +13,10 @@
"copy-text-to-clipboard": "3.0.1", "copy-text-to-clipboard": "3.0.1",
"crypto-browserify": "3.12.0", "crypto-browserify": "3.12.0",
"framer-motion": "6.2.8", "framer-motion": "6.2.8",
"gatsby": "4.10.3", "gatsby": "4.11.1",
"gatsby-background-image": "1.6.0", "gatsby-background-image": "1.6.0",
"gatsby-plugin-image": "2.10.1", "gatsby-plugin-image": "2.11.1",
"gatsby-plugin-manifest": "4.10.2", "gatsby-plugin-manifest": "4.11.1",
"gatsby-plugin-postcss": "5.10.0", "gatsby-plugin-postcss": "5.10.0",
"gatsby-plugin-react-helmet": "5.10.0", "gatsby-plugin-react-helmet": "5.10.0",
"gatsby-plugin-robots-txt": "1.7.0", "gatsby-plugin-robots-txt": "1.7.0",
@ -25,14 +25,14 @@
"gatsby-plugin-svgr": "3.0.0-beta.0", "gatsby-plugin-svgr": "3.0.0-beta.0",
"gatsby-source-filesystem": "4.10.1", "gatsby-source-filesystem": "4.10.1",
"gatsby-transformer-sharp": "4.10.0", "gatsby-transformer-sharp": "4.10.0",
"gatsby-transformer-yaml": "4.10.0", "gatsby-transformer-yaml": "4.11.0",
"gbimage-bridge": "0.2.1", "gbimage-bridge": "0.2.1",
"http-status-codes": "2.2.0", "http-status-codes": "2.2.0",
"ms": "2.1.3", "ms": "2.1.3",
"nanoid": "3.3.2", "nanoid": "3.3.2",
"normalize.css": "8.0.1", "normalize.css": "8.0.1",
"path-browserify": "1.0.1", "path-browserify": "1.0.1",
"polished": "4.1.4", "polished": "4.2.1",
"postcss": "8.4.12", "postcss": "8.4.12",
"prop-types": "15.8.1", "prop-types": "15.8.1",
"react": "17.0.2", "react": "17.0.2",

File diff suppressed because it is too large Load Diff

View File

@ -13,11 +13,13 @@ ENV_VARIABLES=("AWS_ACCESS_KEY_ID" "AWS_SECRET_ACCESS_KEY" "PORTAL_DOMAIN" "SERV
for ENV_VARIABLE in "${ENV_VARIABLES[@]}"; do for ENV_VARIABLE in "${ENV_VARIABLES[@]}"; do
ENV_VARIABLE_VALUE=$(grep -v '^#' /home/user/skynet-webportal/.env | grep ${ENV_VARIABLE} || true) ENV_VARIABLE_VALUE=$(grep -v '^#' /home/user/skynet-webportal/.env | grep ${ENV_VARIABLE} || true)
if test -z "${ENV_VARIABLE_VALUE}"; then if test -z "${ENV_VARIABLE_VALUE}"; then
if $ENV_VARIABLE ~= "SERVER_DOMAIN"; then # all variables except SERVER_DOMAIN are required
if [ "${ENV_VARIABLE}" != "SERVER_DOMAIN" ]; then
echo "Environment variable ${ENV_VARIABLE} is not set" && exit 1 echo "Environment variable ${ENV_VARIABLE} is not set" && exit 1
fi fi
else
export ${ENV_VARIABLE_VALUE}
fi fi
export ${ENV_VARIABLE_VALUE}
done done
# create bucket skynet-backup-[portaldomain] (replace dots with dashes and strip anything other than alnum) # create bucket skynet-backup-[portaldomain] (replace dots with dashes and strip anything other than alnum)
@ -30,11 +32,17 @@ if test -z "${SERVER_DOMAIN}"; then
SERVER_PREFIX=$(echo ${SERVER_UID} | tr '.' '-' | tr -cd '[[:alnum:]]-') SERVER_PREFIX=$(echo ${SERVER_UID} | tr '.' '-' | tr -cd '[[:alnum:]]-')
else else
# use both uid and server domain if available (replace dots with dashes and strip anything other than alnum) # use both uid and server domain if available (replace dots with dashes and strip anything other than alnum)
SERVER_PREFIX=$(echo ${SERVER_UID}-${SERVER_DOMAIN} | tr '.' '-' | tr -cd '[[:alnum:]]-') SERVER_PREFIX=$(echo ${SERVER_DOMAIN}-${SERVER_UID} | tr '.' '-' | tr -cd '[[:alnum:]]-')
SERVER_PREFIX_LEGACY=$(echo ${SERVER_UID}-${SERVER_DOMAIN} | tr '.' '-' | tr -cd '[[:alnum:]]-')
fi fi
aws s3api create-bucket --acl private --bucket ${BUCKET_NAME} aws s3api create-bucket --acl private --bucket ${BUCKET_NAME}
# move old backup dir to new location if legacy backup path exists
if test -n "${SERVER_PREFIX_LEGACY}"; then
aws s3 mv --recursive s3://${BUCKET_NAME}/${SERVER_PREFIX_LEGACY} s3://${BUCKET_NAME}/${SERVER_PREFIX}
fi
# sync all nginx logs # sync all nginx logs
mkdir -p /home/user/skynet-webportal/docker/data/nginx/logs # ensure path exists mkdir -p /home/user/skynet-webportal/docker/data/nginx/logs # ensure path exists
aws s3 sync --no-progress /home/user/skynet-webportal/docker/data/nginx/logs s3://${BUCKET_NAME}/${SERVER_PREFIX}/docker/data/nginx/logs aws s3 sync --no-progress /home/user/skynet-webportal/docker/data/nginx/logs s3://${BUCKET_NAME}/${SERVER_PREFIX}/docker/data/nginx/logs

View File

@ -33,6 +33,13 @@ sc_precision = 10**24
setup_done = False setup_done = False
# get docker container id and return None if container not found
def get_docker_container_id(container_name):
docker_cmd = "docker ps -q -f name=" + container_name
output = subprocess.check_output(docker_cmd, shell=True).decode("utf-8")
return None if output == "" else output
# find out local siad ip by inspecting its docker container # find out local siad ip by inspecting its docker container
def get_docker_container_ip(container_name): def get_docker_container_ip(container_name):
ip_regex = re.compile(r"^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$") ip_regex = re.compile(r"^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$")

View File

@ -10,7 +10,7 @@ import traceback
from datetime import datetime, timedelta from datetime import datetime, timedelta
import requests import requests
from bot_utils import setup, send_msg, get_docker_container_ip from bot_utils import setup, send_msg, get_docker_container_id, get_docker_container_ip
""" """
health-checker reads the /health-check endpoint of the portal and dispatches health-checker reads the /health-check endpoint of the portal and dispatches
@ -136,6 +136,12 @@ async def check_disk():
async def check_health(): async def check_health():
print("\nChecking portal health status...") print("\nChecking portal health status...")
# do not try to run health checks if health-check container does not exist
# possible use case is fresh or taken down server that has only skyd running
if not get_docker_container_id("health-check"):
print("Container health-check not found - skipping health checks")
return
try: try:
endpoint = "http://{}:{}".format(get_docker_container_ip("health-check"), 3100) endpoint = "http://{}:{}".format(get_docker_container_ip("health-check"), 3100)
except: except: