Skip to content

Commit

Permalink
feat: basic install status view
Browse files Browse the repository at this point in the history
  • Loading branch information
jordan-acosta committed Jun 19, 2024
1 parent 63c02af commit c973f5d
Show file tree
Hide file tree
Showing 4 changed files with 162 additions and 14 deletions.
1 change: 1 addition & 0 deletions app/[installer-slug]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ export default async function Installer({ params, searchParams }) {
<main className="flex-auto" id="steps">
<InstallStepper
app={app}
installer={installer}
searchParams={searchParams}
createInstall={createInstall}
getInstall={getInstall}
Expand Down
51 changes: 51 additions & 0 deletions components/InstallStatus.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
"use client";

import React from "react";

import Card from "./Card";
import StatusIcon from "./StatusIcon";

export const InstallStatus: FC<{ install: Record<string, any> }> = ({
install,
}) => {
let sandboxStatus = "pending";
let sandboxStatusDescription = "Sandbox has not deployed yet.";
if (install.install_sandbox_runs && install.install_sandbox_runs.length > 0) {
const lastRun = install.install_sandbox_runs[0];
sandboxStatus = lastRun.status;
sandboxStatusDescription = lastRun.status_description;
}

const components = install.install_components.map((component, idx) => {
let status = "pending";
let status_description = "Component has not deployed yet.";
if (component.install_deploys.length > 0) {
const lastDeploy = component.install_deploys[0];
status = lastDeploy.status;
status_description = lastDeploy.status_description;
}
return (
<div key={idx}>
<span className="font-medium">
<StatusIcon status={sandboxStatus} /> {component.component.name}:
</span>{" "}
<span>{status_description}</span>
</div>
);
});

return (
<div>
<Card className="grid p-4 divide-y mb-4">
<div className="font-bold">
<StatusIcon status={sandboxStatus} /> Sandbox
</div>
<div>{sandboxStatusDescription}</div>
</Card>
<Card className="grid p-4 divide-y">
<div className="font-bold">Components</div>
{components}
</Card>
</div>
);
};
107 changes: 93 additions & 14 deletions components/InstallStepper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,25 @@ import {
Accordion,
AccordionHeader,
AccordionBody,
Alert,
} from "@material-tailwind/react";
import {
AWSInstallerFormFields,
InputFields,
AzureInstallerFormFields,
StepOneAWS,
StepOneAzure,
Link,
} from "../components";
import { InstallStatus } from "./InstallStatus";
import StatusIcon from "./StatusIcon";
import showdown from "showdown";

const markdown = new showdown.Converter();

const InstallStepper = ({
app,
installer,
searchParams,
regions,
createInstall,
Expand All @@ -38,19 +46,61 @@ const InstallStepper = ({
));

// track state of install
const [install, setInstall] = React.useState({ id: "" });
const [install, setInstall] = React.useState({
id: "",
status: "not created",
status_description: "No install has been created yet.",
install_components: [],
});
const [error, setError] = React.useState({
description: "",
error: "",
user_error: false,
});

// create install when form is submitted
// create or update install when form is submitted
const formAction = async (event) => {
event.preventDefault();

const formData = new FormData(event.target);
let installID = "";
if (install.id === "") {
const formData = new FormData(event.target);
// if we haven't created the install yet, create it
const res = await createInstall(app, formData);
if (res.error) {
setError(res);
return;
}
installID = res.id;
} else {
updateInstall(install);
reprovisionInstall(install.id);
// if we've already created the install, update it and reprovision
const updateRes = updateInstall(formData);
if (updateRes.error) {
setError(updateRes);
return;
}

const reproRes = reprovisionInstall(install.id);
if (reproRes.error) {
setError(reproRes);
return;
}
}

// by this point we should have an install ID
// fetch the install so we can render the status
const res = await getInstall(installID);
if (res.error) {
setError(res);
return;
}

setInstall(res);
setError({
description: "",
error: "",
user_error: false,
});
};

// poll for install status once we have an ID
Expand All @@ -76,7 +126,10 @@ const InstallStepper = ({
const res = await getInstall(install.id);
setInstall(res);
}
}, 1000 * 3);
}, 1000 * 5);

console.log("install: ", install);
console.log("error: ", error);

const stepContent = app.input_config.input_groups.map((group, idx) => (
<Accordion open={activeStep === idx + 2}>
Expand All @@ -87,6 +140,13 @@ const InstallStepper = ({
</Accordion>
));

const errorAlert =
error.error !== "" ? (
<div className="fixed w-full right-0 bottom-0 left-0 p-4">
<Alert color="red">{error.description}</Alert>
</div>
) : null;

return (
<div className="w-full p-4">
<Stepper
Expand Down Expand Up @@ -163,18 +223,37 @@ const InstallStepper = ({
{...stepContent}

<Accordion open={activeStep === steps.length + 2}>
<AccordionHeader>Install Status</AccordionHeader>
<AccordionHeader>
<span>
Install Status <StatusIcon status={install.status} />
</span>
</AccordionHeader>
<AccordionBody>
<Button
type="submit"
className="rounded text-sm text-gray-50 bg-primary-600 hover:bg-primary-700 focus:bg-primary-700 active:bg-primary-800 px-4 py-1.5 w-fit m-4"
>
Submit
</Button>
{JSON.stringify(install)}
<div className="grid grid-cols-2 gap-2">
<div>
<div
dangerouslySetInnerHTML={{
__html: markdown.makeHtml(
installer?.metadata?.post_install_markdown,
),
}}
/>
</div>

<div>
<InstallStatus install={install} />
<Button
type="submit"
className="block mr-0 ml-auto rounded text-sm text-gray-50 bg-primary-600 hover:bg-primary-700 focus:bg-primary-700 active:bg-primary-800 px-4 py-1.5 w-fit mt-4"
>
{install.id === "" ? "Create Install" : "Update Install"}
</Button>
</div>
</div>
</AccordionBody>
</Accordion>
</form>
{errorAlert}
</div>
);
};
Expand Down
17 changes: 17 additions & 0 deletions components/StatusIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import React from "react";

const StatusIcon: FC<{ status: string; status_description: string }> = ({
status,
className,
}) => {
let clr = "yellow-500";
if (status === "active") {
clr = "green-600";
} else if (status === "error") {
clr = "red-500";
}

return <span className={`text-${clr} ${className}`}></span>;
};

export default StatusIcon;

0 comments on commit c973f5d

Please sign in to comment.