Skip to content

Commit 9379d0c

Browse files
Merge pull request #633 from zenml-io/future
Release
2 parents c5cfcdb + f9ae065 commit 9379d0c

File tree

15 files changed

+287
-75
lines changed

15 files changed

+287
-75
lines changed
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import { InfoBox } from "@/components/Infobox";
2+
import { stackQueries } from "@/data/stacks";
3+
import { routes } from "@/router/routes";
4+
import { useQuery } from "@tanstack/react-query";
5+
import { Button, Skeleton } from "@zenml-io/react-component-library";
6+
import { Dispatch, SetStateAction, useEffect } from "react";
7+
import { Link } from "react-router-dom";
8+
import { clearWizardData, parseWizardData } from "./create/new-infrastructure/persist";
9+
10+
type Props = {
11+
setHasResumeableStack: Dispatch<SetStateAction<boolean>>;
12+
};
13+
14+
export function ResumeStackBanner({ setHasResumeableStack }: Props) {
15+
const { success, data } = parseWizardData();
16+
const stack = useQuery({
17+
...stackQueries.stackDeploymentStack({
18+
provider: data?.provider || "aws",
19+
stack_name: data?.stackName || "",
20+
date_start: data?.timestamp
21+
}),
22+
enabled: success,
23+
throwOnError: true
24+
});
25+
26+
useEffect(() => {
27+
if (stack.data) {
28+
clearWizardData();
29+
setHasResumeableStack(false);
30+
}
31+
}, [stack.data]);
32+
33+
if (!success) return null;
34+
35+
if (stack.isError) return null;
36+
if (stack.isPending) return <Skeleton className="h-[70px] w-full" />;
37+
38+
return (
39+
<InfoBox className="w-full">
40+
<section className="flex flex-wrap items-center justify-between gap-y-2">
41+
<div className="flex flex-wrap items-center gap-2">
42+
<p className="font-semibold">You have a Stack provision incomplete</p>
43+
<p className="text-text-sm">
44+
Return to the setup and finish the configuration on your cloud provider
45+
</p>
46+
</div>
47+
<div>
48+
<Button
49+
className="w-fit bg-theme-surface-primary"
50+
intent="primary"
51+
emphasis="subtle"
52+
asChild
53+
>
54+
<Link to={routes.stacks.create.newInfra}>
55+
<span>Review Stack</span>
56+
</Link>
57+
</Button>
58+
</div>
59+
</section>
60+
</InfoBox>
61+
);
62+
}

src/app/stacks/StackList.tsx

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,20 @@
1-
import { stackQueries } from "@/data/stacks";
2-
import Refresh from "@/assets/icons/refresh.svg?react";
31
import Plus from "@/assets/icons/plus.svg?react";
2+
import Refresh from "@/assets/icons/refresh.svg?react";
3+
import Pagination from "@/components/Pagination";
4+
import { SearchField } from "@/components/SearchField";
5+
import { stackQueries } from "@/data/stacks";
6+
import { routes } from "@/router/routes";
47
import { useQuery } from "@tanstack/react-query";
58
import { Button, DataTable, Skeleton } from "@zenml-io/react-component-library";
6-
import Pagination from "@/components/Pagination";
9+
import { useState } from "react";
10+
import { Link } from "react-router-dom";
711
import { getStackColumns } from "./columns";
12+
import { parseWizardData } from "./create/new-infrastructure/persist";
13+
import { ResumeStackBanner } from "./ResumeStackBanner";
814
import { useStacklistQueryParams } from "./service";
9-
import { SearchField } from "@/components/SearchField";
10-
import { Link } from "react-router-dom";
11-
import { routes } from "@/router/routes";
1215

1316
export function StackList() {
17+
const [hasResumeableStack, setResumeableStack] = useState(parseWizardData().success);
1418
const queryParams = useStacklistQueryParams();
1519
const { refetch, data } = useQuery({
1620
...stackQueries.stackList({ ...queryParams, sort_by: "desc:updated" }),
@@ -20,7 +24,7 @@ export function StackList() {
2024
return (
2125
<section className="p-5">
2226
<div className="flex flex-col gap-5">
23-
<div className="flex items-center justify-between">
27+
<div className="flex flex-wrap items-center justify-between gap-y-4">
2428
<SearchField searchParams={queryParams} />
2529
<div className="flex items-center justify-between gap-2">
2630
<Button intent="primary" emphasis="subtle" size="md" onClick={() => refetch()}>
@@ -36,6 +40,7 @@ export function StackList() {
3640
</div>
3741
</div>
3842
<div className="flex flex-col items-center gap-5">
43+
{hasResumeableStack && <ResumeStackBanner setHasResumeableStack={setResumeableStack} />}
3944
<div className="w-full">
4045
{data ? (
4146
<DataTable columns={getStackColumns()} data={data.items} />

src/app/stacks/columns.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ export function getStackColumns(): ColumnDef<Stack>[] {
2323
</Avatar>
2424
<div>
2525
<div className="flex items-center gap-1">
26-
<StackSheet stackId={id}>
26+
<StackSheet stackName={name} stackId={id}>
2727
<h2 className="text-text-md font-semibold">{name}</h2>
2828
</StackSheet>
2929
</div>

src/app/stacks/create/new-infrastructure/NewInfraFormContext.tsx

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { StackDeploymentProvider } from "@/types/stack";
22
import { Dispatch, SetStateAction, createContext, useContext, useRef, useState } from "react";
3+
import { parseWizardData } from "./persist";
34

45
type Data = {
56
provider?: StackDeploymentProvider;
@@ -15,14 +16,27 @@ type NewInfraFormType = {
1516
formRef: React.RefObject<HTMLFormElement>;
1617
setTimestamp: Dispatch<SetStateAction<string>>;
1718
timestamp: string;
19+
isLoading: boolean;
20+
setIsLoading: Dispatch<SetStateAction<boolean>>;
1821
};
1922

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

2225
export function NewInfraFormProvider({ children }: { children: React.ReactNode }) {
26+
const { success, data: parsedData } = parseWizardData();
27+
2328
const [isNextButtonDisabled, setIsNextButtonDisabled] = useState(false);
24-
const [data, setData] = useState<Data>({});
25-
const [timestamp, setTimestamp] = useState<string>("");
29+
const [isLoading, setIsLoading] = useState(success ? true : false);
30+
const [data, setData] = useState<Data>(
31+
success
32+
? {
33+
location: parsedData.location,
34+
provider: parsedData.provider,
35+
stackName: parsedData.stackName
36+
}
37+
: {}
38+
);
39+
const [timestamp, setTimestamp] = useState<string>(success ? parsedData.timestamp : "");
2640
const formRef = useRef<HTMLFormElement>(null);
2741

2842
return (
@@ -32,6 +46,8 @@ export function NewInfraFormProvider({ children }: { children: React.ReactNode }
3246
setIsNextButtonDisabled,
3347
data,
3448
setData,
49+
isLoading,
50+
setIsLoading,
3551
formRef,
3652
timestamp,
3753
setTimestamp

src/app/stacks/create/new-infrastructure/NewInfraWizardContext.tsx

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,21 @@ import { Dispatch, SetStateAction, createContext, useContext, useState } from "r
33
type NewInfraWizardType = {
44
currentStep: number;
55
setCurrentStep: Dispatch<SetStateAction<number>>;
6-
isLoading: boolean;
7-
setIsLoading: Dispatch<SetStateAction<boolean>>;
86
};
97

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

12-
export function NewInfraWizardProvider({ children }: { children: React.ReactNode }) {
13-
const [currentStep, setCurrentStep] = useState(1);
14-
const [isLoading, setIsLoading] = useState(false);
10+
export function NewInfraWizardProvider({
11+
children,
12+
initialStep = 1
13+
}: {
14+
children: React.ReactNode;
15+
initialStep?: number;
16+
}) {
17+
const [currentStep, setCurrentStep] = useState(initialStep);
1518

1619
return (
17-
<NewInfraWizardContext.Provider
18-
value={{ currentStep, setCurrentStep, isLoading, setIsLoading }}
19-
>
20+
<NewInfraWizardContext.Provider value={{ currentStep, setCurrentStep }}>
2021
{children}
2122
</NewInfraWizardContext.Provider>
2223
);

src/app/stacks/create/new-infrastructure/Steps/Deploy/ButtonStep.tsx

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ import { useQuery } from "@tanstack/react-query";
55
import { Button, Skeleton } from "@zenml-io/react-component-library";
66
import { stackQueries } from "../../../../../../data/stacks";
77
import { useNewInfraFormContext } from "../../NewInfraFormContext";
8-
import { useNewInfraWizardContext } from "../../NewInfraWizardContext";
98
import { GCPCodesnippet, GCPWarning } from "../../Providers/GCP";
9+
import { setWizardData } from "../../persist";
1010

1111
export function DeployButtonPart() {
1212
const { data } = useNewInfraFormContext();
@@ -36,9 +36,7 @@ type DeploymentButtonProps = {
3636
setTimestampBool?: boolean;
3737
};
3838
export function DeploymentButton({ setTimestampBool }: DeploymentButtonProps) {
39-
const { data, setTimestamp } = useNewInfraFormContext();
40-
41-
const { setIsLoading } = useNewInfraWizardContext();
39+
const { data, setTimestamp, setIsLoading } = useNewInfraFormContext();
4240

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

5957
function handleClick() {
60-
setTimestampBool && setTimestamp(new Date().toISOString().slice(0, -1)!);
58+
const timestamp = new Date().toISOString().slice(0, -1);
59+
setTimestampBool && setTimestamp(timestamp);
60+
setWizardData({
61+
location: data.location || "",
62+
provider: data.provider || "aws",
63+
stackName: data.stackName!,
64+
timestamp
65+
});
6166
setIsLoading(true);
6267
}
6368

src/app/stacks/create/new-infrastructure/Steps/Deploy/ProvisioningStep.tsx

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,9 @@ import { useEffect, useState } from "react";
99
import { useNewInfraFormContext } from "../../NewInfraFormContext";
1010
import { useNewInfraWizardContext } from "../../NewInfraWizardContext";
1111
import { CloudComponents } from "../../Providers";
12-
import { DeploymentButton } from "./ButtonStep";
1312
import { GCPCodesnippet } from "../../Providers/GCP";
13+
import { clearWizardData } from "../../persist";
14+
import { DeploymentButton } from "./ButtonStep";
1415

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

3334
useEffect(() => {
3435
if (stackData) {
36+
clearWizardData();
3537
setCurrentStep((prev) => prev + 1);
3638
setIsNextButtonDisabled(false);
3739
}
@@ -52,7 +54,6 @@ function LoadingHeader() {
5254
const { data } = useNewInfraFormContext();
5355
return (
5456
<section className="space-y-5 border-b border-theme-border-moderate pb-5">
55-
<Warning />
5657
<Box className="flex items-center justify-between gap-4 px-6 py-5">
5758
<div className="flex items-start gap-3">
5859
<CloudProviderIcon provider={data.provider!} className="h-6 w-6 shrink-0" />
@@ -132,15 +133,3 @@ function ItTakesLongerBox({ isReady }: { isReady: boolean }) {
132133
</InfoBox>
133134
);
134135
}
135-
136-
function Warning() {
137-
return (
138-
<InfoBox
139-
className="border-warning-300 bg-warning-50 text-text-sm text-warning-900"
140-
intent="warning"
141-
>
142-
<strong>Please, do not leave this screen</strong> until the stack and the components are fully
143-
created.
144-
</InfoBox>
145-
);
146-
}

src/app/stacks/create/new-infrastructure/Steps/Deploy/index.tsx

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
import { useEffect } from "react";
22
import { useNewInfraFormContext } from "../../NewInfraFormContext";
3-
import { useNewInfraWizardContext } from "../../NewInfraWizardContext";
43
import { WizardStepWrapper } from "../../Wizard";
5-
import { ProvisioningStep } from "./ProvisioningStep";
64
import { DeployButtonPart } from "./ButtonStep";
5+
import { ProvisioningStep } from "./ProvisioningStep";
76

87
export function DeployStep() {
98
return (
@@ -14,8 +13,7 @@ export function DeployStep() {
1413
}
1514

1615
function DisplaySteps() {
17-
const { isLoading } = useNewInfraWizardContext();
18-
const { setIsNextButtonDisabled } = useNewInfraFormContext();
16+
const { setIsNextButtonDisabled, isLoading } = useNewInfraFormContext();
1917
useEffect(() => {
2018
setIsNextButtonDisabled(true);
2119
}, []);

src/app/stacks/create/new-infrastructure/Steps/Provider.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { InputHTMLAttributes, ReactNode, forwardRef, useEffect } from "react";
55
import { useForm } from "react-hook-form";
66
import { useNewInfraFormContext } from "../NewInfraFormContext";
77
import { WizardStepWrapper } from "../Wizard";
8-
import { ProviderForm, providerSchema } from "./schemas";
8+
import { ProviderForm, providerFormSchema } from "./schemas";
99

1010
export function ProviderStep() {
1111
const { formRef, setIsNextButtonDisabled, setData, data } = useNewInfraFormContext();
@@ -15,7 +15,7 @@ export function ProviderStep() {
1515
handleSubmit,
1616
formState: { isValid }
1717
} = useForm<ProviderForm>({
18-
resolver: zodResolver(providerSchema),
18+
resolver: zodResolver(providerFormSchema),
1919
defaultValues: { provider: data.provider }
2020
});
2121

src/app/stacks/create/new-infrastructure/Steps/schemas.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
import { z } from "zod";
22

3-
export const providerSchema = z.object({
4-
provider: z.enum(["aws", "gcp"])
3+
export const providerSchema = z.enum(["aws", "gcp"]);
4+
5+
export const providerFormSchema = z.object({
6+
provider: providerSchema
57
});
68

7-
export type ProviderForm = z.infer<typeof providerSchema>;
9+
export type ProviderForm = z.infer<typeof providerFormSchema>;
810

911
export const configurationSchema = z.object({
1012
region: z.string().trim().min(1),

0 commit comments

Comments
 (0)