Skip to content

Commit

Permalink
Merge pull request #633 from zenml-io/future
Browse files Browse the repository at this point in the history
Release
  • Loading branch information
Cahllagerfeld authored Jul 16, 2024
2 parents c5cfcdb + f9ae065 commit 9379d0c
Show file tree
Hide file tree
Showing 15 changed files with 287 additions and 75 deletions.
62 changes: 62 additions & 0 deletions src/app/stacks/ResumeStackBanner.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { InfoBox } from "@/components/Infobox";
import { stackQueries } from "@/data/stacks";
import { routes } from "@/router/routes";
import { useQuery } from "@tanstack/react-query";
import { Button, Skeleton } from "@zenml-io/react-component-library";
import { Dispatch, SetStateAction, useEffect } from "react";
import { Link } from "react-router-dom";
import { clearWizardData, parseWizardData } from "./create/new-infrastructure/persist";

type Props = {
setHasResumeableStack: Dispatch<SetStateAction<boolean>>;
};

export function ResumeStackBanner({ setHasResumeableStack }: Props) {
const { success, data } = parseWizardData();
const stack = useQuery({
...stackQueries.stackDeploymentStack({
provider: data?.provider || "aws",
stack_name: data?.stackName || "",
date_start: data?.timestamp
}),
enabled: success,
throwOnError: true
});

useEffect(() => {
if (stack.data) {
clearWizardData();
setHasResumeableStack(false);
}
}, [stack.data]);

if (!success) return null;

if (stack.isError) return null;
if (stack.isPending) return <Skeleton className="h-[70px] w-full" />;

return (
<InfoBox className="w-full">
<section className="flex flex-wrap items-center justify-between gap-y-2">
<div className="flex flex-wrap items-center gap-2">
<p className="font-semibold">You have a Stack provision incomplete</p>
<p className="text-text-sm">
Return to the setup and finish the configuration on your cloud provider
</p>
</div>
<div>
<Button
className="w-fit bg-theme-surface-primary"
intent="primary"
emphasis="subtle"
asChild
>
<Link to={routes.stacks.create.newInfra}>
<span>Review Stack</span>
</Link>
</Button>
</div>
</section>
</InfoBox>
);
}
19 changes: 12 additions & 7 deletions src/app/stacks/StackList.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
import { stackQueries } from "@/data/stacks";
import Refresh from "@/assets/icons/refresh.svg?react";
import Plus from "@/assets/icons/plus.svg?react";
import Refresh from "@/assets/icons/refresh.svg?react";
import Pagination from "@/components/Pagination";
import { SearchField } from "@/components/SearchField";
import { stackQueries } from "@/data/stacks";
import { routes } from "@/router/routes";
import { useQuery } from "@tanstack/react-query";
import { Button, DataTable, Skeleton } from "@zenml-io/react-component-library";
import Pagination from "@/components/Pagination";
import { useState } from "react";
import { Link } from "react-router-dom";
import { getStackColumns } from "./columns";
import { parseWizardData } from "./create/new-infrastructure/persist";
import { ResumeStackBanner } from "./ResumeStackBanner";
import { useStacklistQueryParams } from "./service";
import { SearchField } from "@/components/SearchField";
import { Link } from "react-router-dom";
import { routes } from "@/router/routes";

export function StackList() {
const [hasResumeableStack, setResumeableStack] = useState(parseWizardData().success);
const queryParams = useStacklistQueryParams();
const { refetch, data } = useQuery({
...stackQueries.stackList({ ...queryParams, sort_by: "desc:updated" }),
Expand All @@ -20,7 +24,7 @@ export function StackList() {
return (
<section className="p-5">
<div className="flex flex-col gap-5">
<div className="flex items-center justify-between">
<div className="flex flex-wrap items-center justify-between gap-y-4">
<SearchField searchParams={queryParams} />
<div className="flex items-center justify-between gap-2">
<Button intent="primary" emphasis="subtle" size="md" onClick={() => refetch()}>
Expand All @@ -36,6 +40,7 @@ export function StackList() {
</div>
</div>
<div className="flex flex-col items-center gap-5">
{hasResumeableStack && <ResumeStackBanner setHasResumeableStack={setResumeableStack} />}
<div className="w-full">
{data ? (
<DataTable columns={getStackColumns()} data={data.items} />
Expand Down
2 changes: 1 addition & 1 deletion src/app/stacks/columns.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export function getStackColumns(): ColumnDef<Stack>[] {
</Avatar>
<div>
<div className="flex items-center gap-1">
<StackSheet stackId={id}>
<StackSheet stackName={name} stackId={id}>
<h2 className="text-text-md font-semibold">{name}</h2>
</StackSheet>
</div>
Expand Down
20 changes: 18 additions & 2 deletions src/app/stacks/create/new-infrastructure/NewInfraFormContext.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { StackDeploymentProvider } from "@/types/stack";
import { Dispatch, SetStateAction, createContext, useContext, useRef, useState } from "react";
import { parseWizardData } from "./persist";

type Data = {
provider?: StackDeploymentProvider;
Expand All @@ -15,14 +16,27 @@ type NewInfraFormType = {
formRef: React.RefObject<HTMLFormElement>;
setTimestamp: Dispatch<SetStateAction<string>>;
timestamp: string;
isLoading: boolean;
setIsLoading: Dispatch<SetStateAction<boolean>>;
};

export const NewInfraFormContext = createContext<NewInfraFormType | null>(null);

export function NewInfraFormProvider({ children }: { children: React.ReactNode }) {
const { success, data: parsedData } = parseWizardData();

const [isNextButtonDisabled, setIsNextButtonDisabled] = useState(false);
const [data, setData] = useState<Data>({});
const [timestamp, setTimestamp] = useState<string>("");
const [isLoading, setIsLoading] = useState(success ? true : false);
const [data, setData] = useState<Data>(
success
? {
location: parsedData.location,
provider: parsedData.provider,
stackName: parsedData.stackName
}
: {}
);
const [timestamp, setTimestamp] = useState<string>(success ? parsedData.timestamp : "");
const formRef = useRef<HTMLFormElement>(null);

return (
Expand All @@ -32,6 +46,8 @@ export function NewInfraFormProvider({ children }: { children: React.ReactNode }
setIsNextButtonDisabled,
data,
setData,
isLoading,
setIsLoading,
formRef,
timestamp,
setTimestamp
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,21 @@ import { Dispatch, SetStateAction, createContext, useContext, useState } from "r
type NewInfraWizardType = {
currentStep: number;
setCurrentStep: Dispatch<SetStateAction<number>>;
isLoading: boolean;
setIsLoading: Dispatch<SetStateAction<boolean>>;
};

export const NewInfraWizardContext = createContext<NewInfraWizardType | null>(null);

export function NewInfraWizardProvider({ children }: { children: React.ReactNode }) {
const [currentStep, setCurrentStep] = useState(1);
const [isLoading, setIsLoading] = useState(false);
export function NewInfraWizardProvider({
children,
initialStep = 1
}: {
children: React.ReactNode;
initialStep?: number;
}) {
const [currentStep, setCurrentStep] = useState(initialStep);

return (
<NewInfraWizardContext.Provider
value={{ currentStep, setCurrentStep, isLoading, setIsLoading }}
>
<NewInfraWizardContext.Provider value={{ currentStep, setCurrentStep }}>
{children}
</NewInfraWizardContext.Provider>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import { useQuery } from "@tanstack/react-query";
import { Button, Skeleton } from "@zenml-io/react-component-library";
import { stackQueries } from "../../../../../../data/stacks";
import { useNewInfraFormContext } from "../../NewInfraFormContext";
import { useNewInfraWizardContext } from "../../NewInfraWizardContext";
import { GCPCodesnippet, GCPWarning } from "../../Providers/GCP";
import { setWizardData } from "../../persist";

export function DeployButtonPart() {
const { data } = useNewInfraFormContext();
Expand Down Expand Up @@ -36,9 +36,7 @@ type DeploymentButtonProps = {
setTimestampBool?: boolean;
};
export function DeploymentButton({ setTimestampBool }: DeploymentButtonProps) {
const { data, setTimestamp } = useNewInfraFormContext();

const { setIsLoading } = useNewInfraWizardContext();
const { data, setTimestamp, setIsLoading } = useNewInfraFormContext();

const stackDeploymentConfig = useQuery({
...stackQueries.stackDeploymentConfig({
Expand All @@ -57,7 +55,14 @@ export function DeploymentButton({ setTimestampBool }: DeploymentButtonProps) {
}

function handleClick() {
setTimestampBool && setTimestamp(new Date().toISOString().slice(0, -1)!);
const timestamp = new Date().toISOString().slice(0, -1);
setTimestampBool && setTimestamp(timestamp);
setWizardData({
location: data.location || "",
provider: data.provider || "aws",
stackName: data.stackName!,
timestamp
});
setIsLoading(true);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@ import { useEffect, useState } from "react";
import { useNewInfraFormContext } from "../../NewInfraFormContext";
import { useNewInfraWizardContext } from "../../NewInfraWizardContext";
import { CloudComponents } from "../../Providers";
import { DeploymentButton } from "./ButtonStep";
import { GCPCodesnippet } from "../../Providers/GCP";
import { clearWizardData } from "../../persist";
import { DeploymentButton } from "./ButtonStep";

export function ProvisioningStep() {
const { data, timestamp, setIsNextButtonDisabled } = useNewInfraFormContext();
Expand All @@ -32,6 +33,7 @@ export function ProvisioningStep() {

useEffect(() => {
if (stackData) {
clearWizardData();
setCurrentStep((prev) => prev + 1);
setIsNextButtonDisabled(false);
}
Expand All @@ -52,7 +54,6 @@ function LoadingHeader() {
const { data } = useNewInfraFormContext();
return (
<section className="space-y-5 border-b border-theme-border-moderate pb-5">
<Warning />
<Box className="flex items-center justify-between gap-4 px-6 py-5">
<div className="flex items-start gap-3">
<CloudProviderIcon provider={data.provider!} className="h-6 w-6 shrink-0" />
Expand Down Expand Up @@ -132,15 +133,3 @@ function ItTakesLongerBox({ isReady }: { isReady: boolean }) {
</InfoBox>
);
}

function Warning() {
return (
<InfoBox
className="border-warning-300 bg-warning-50 text-text-sm text-warning-900"
intent="warning"
>
<strong>Please, do not leave this screen</strong> until the stack and the components are fully
created.
</InfoBox>
);
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import { useEffect } from "react";
import { useNewInfraFormContext } from "../../NewInfraFormContext";
import { useNewInfraWizardContext } from "../../NewInfraWizardContext";
import { WizardStepWrapper } from "../../Wizard";
import { ProvisioningStep } from "./ProvisioningStep";
import { DeployButtonPart } from "./ButtonStep";
import { ProvisioningStep } from "./ProvisioningStep";

export function DeployStep() {
return (
Expand All @@ -14,8 +13,7 @@ export function DeployStep() {
}

function DisplaySteps() {
const { isLoading } = useNewInfraWizardContext();
const { setIsNextButtonDisabled } = useNewInfraFormContext();
const { setIsNextButtonDisabled, isLoading } = useNewInfraFormContext();
useEffect(() => {
setIsNextButtonDisabled(true);
}, []);
Expand Down
4 changes: 2 additions & 2 deletions src/app/stacks/create/new-infrastructure/Steps/Provider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { InputHTMLAttributes, ReactNode, forwardRef, useEffect } from "react";
import { useForm } from "react-hook-form";
import { useNewInfraFormContext } from "../NewInfraFormContext";
import { WizardStepWrapper } from "../Wizard";
import { ProviderForm, providerSchema } from "./schemas";
import { ProviderForm, providerFormSchema } from "./schemas";

export function ProviderStep() {
const { formRef, setIsNextButtonDisabled, setData, data } = useNewInfraFormContext();
Expand All @@ -15,7 +15,7 @@ export function ProviderStep() {
handleSubmit,
formState: { isValid }
} = useForm<ProviderForm>({
resolver: zodResolver(providerSchema),
resolver: zodResolver(providerFormSchema),
defaultValues: { provider: data.provider }
});

Expand Down
8 changes: 5 additions & 3 deletions src/app/stacks/create/new-infrastructure/Steps/schemas.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { z } from "zod";

export const providerSchema = z.object({
provider: z.enum(["aws", "gcp"])
export const providerSchema = z.enum(["aws", "gcp"]);

export const providerFormSchema = z.object({
provider: providerSchema
});

export type ProviderForm = z.infer<typeof providerSchema>;
export type ProviderForm = z.infer<typeof providerFormSchema>;

export const configurationSchema = z.object({
region: z.string().trim().min(1),
Expand Down
34 changes: 11 additions & 23 deletions src/app/stacks/create/new-infrastructure/Wizard.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { routes } from "@/router/routes";
import { Box, Button } from "@zenml-io/react-component-library";
import { ReactNode } from "react";
import { Link, useNavigate, useSearchParams } from "react-router-dom";
import { useNavigate, useSearchParams } from "react-router-dom";
import { useNewInfraFormContext } from "./NewInfraFormContext";
import { useNewInfraWizardContext } from "./NewInfraWizardContext";
import { ConfigurationStep } from "./Steps/Configuration";
import { DeployStep } from "./Steps/Deploy";
import { ProviderStep } from "./Steps/Provider";
import { SuccessStep } from "./Steps/Success/SuccessStep";
import { clearWizardData } from "./persist";

export function CreateNewInfraWizard() {
const { currentStep } = useNewInfraWizardContext();
Expand Down Expand Up @@ -40,6 +41,7 @@ function NextButton() {
});

if (currentStep === maxSteps) {
clearWizardData();
navigate(isFromOnboarding ? routes.onboarding : routes.stacks.overview);
}
}
Expand All @@ -56,29 +58,16 @@ function NextButton() {
);
}

// function PrevButton() {
// const { setCurrentStep, currentStep } = useNewInfraWizardContext();

// function previousStep() {
// setCurrentStep((prev) => {
// if (prev > 1) {
// return prev - 1;
// }
// return prev;
// });
// }

// return (
// <Button disabled={currentStep === 1} onClick={previousStep} emphasis="subtle" size="md">
// Prev
// </Button>
// );
// }

function CancelButton() {
const navigate = useNavigate();

function cancel() {
clearWizardData();
navigate(routes.stacks.create.index);
}
return (
<Button asChild intent="secondary" size="md">
<Link to={routes.stacks.create.index}>Cancel</Link>
<Button onClick={() => cancel()} intent="secondary" size="md">
Cancel
</Button>
);
}
Expand All @@ -92,7 +81,6 @@ export function WizardStepWrapper({ children, title }: { children: ReactNode; ti
<div className="p-5">{children}</div>
<div className="flex items-center justify-end gap-2 border-t border-theme-border-moderate p-5">
<CancelButton />
{/* <PrevButton /> */}
<NextButton />
</div>
</Box>
Expand Down
Loading

0 comments on commit 9379d0c

Please sign in to comment.