Skip to content

Commit 385008a

Browse files
feat: new onboarding (#615)
1 parent 79eca5e commit 385008a

File tree

22 files changed

+497
-318
lines changed

22 files changed

+497
-318
lines changed

src/app/onboarding/ProductionSetup/Items.tsx

Lines changed: 25 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -1,106 +1,20 @@
1-
import { ChecklistItem } from "@/components/onboarding/ChecklistItem";
2-
import { CloudProvider, ProviderSelect } from "./ProviderSelect";
3-
import { HelpBox } from "@/components/fallback-pages/Helpbox";
4-
import { useState } from "react";
5-
import { getOnboardingItem } from "@/lib/onboarding";
6-
import { OnboardingChecklistItemName, OnboardingState } from "@/types/onboarding";
7-
import { getServiceConnectorStep } from "./ConnectorContent";
8-
import { getArtifactStoreStep } from "./ArtifactStore";
1+
import Plus from "@/assets/icons/plus.svg?react";
92
import { Codesnippet } from "@/components/CodeSnippet";
3+
import { HelpBox } from "@/components/fallback-pages/Helpbox";
4+
import { ChecklistItem } from "@/components/onboarding/ChecklistItem";
5+
import {} from "@/lib/onboarding";
6+
import { routes } from "@/router/routes";
7+
import { OnboardingStep } from "@/types/onboarding";
8+
import { Button } from "@zenml-io/react-component-library";
9+
import { Link } from "react-router-dom";
1010

11-
type Props = {
12-
onboardingState?: OnboardingState;
13-
active?: boolean;
14-
};
15-
16-
export function CreateServiceConnector({ onboardingState, active }: Props) {
17-
const [selectedProvider, setSelectedProvider] = useState<CloudProvider>("aws");
18-
const itemName: OnboardingChecklistItemName = "create_service_connector";
19-
const item = getOnboardingItem(onboardingState || {}, itemName);
20-
return (
21-
<ChecklistItem
22-
active={active}
23-
completed={!!item}
24-
title="Create a service connector"
25-
itemName={itemName}
26-
>
27-
<p className="mb-3">
28-
A service connector grants users of your ZenML server the ability to access components like
29-
your artifact store{" "}
30-
<LearnMoreLink href="https://docs.zenml.io/user-guide/production-guide/remote-storage#configuring-permissions-with-your-first-service-connector" />
31-
</p>
32-
<div className="space-y-5">
33-
<div className="space-y-1">
34-
<label
35-
htmlFor="artifact-store-provider"
36-
className="text-text-sm text-theme-text-secondary"
37-
>
38-
Select your cloud provider
39-
</label>
40-
<ProviderSelect
41-
id="artifact-store-provider"
42-
value={selectedProvider}
43-
setValue={setSelectedProvider}
44-
/>
45-
</div>
46-
{getServiceConnectorStep(selectedProvider)}
47-
<div>
48-
<HelpBox link="https://docs.zenml.io/user-guide/production-guide/remote-storage#configuring-permissions-with-your-first-service-connector" />
49-
</div>
50-
</div>
51-
</ChecklistItem>
52-
);
53-
}
54-
55-
export function CreateArtifactStore({ onboardingState, active }: Props) {
56-
const [selectedProvider, setSelectedProvider] = useState<CloudProvider>("aws");
57-
const itemName: OnboardingChecklistItemName = "create_remote_artifact_store";
58-
const item = getOnboardingItem(onboardingState || {}, itemName);
59-
60-
return (
61-
<ChecklistItem
62-
itemName={itemName}
63-
completed={!!item}
64-
title="Create an artifact store"
65-
active={active}
66-
>
67-
<p className="mb-3">
68-
Configuring a remote artifact store will version your pipeline's data directly in your cloud
69-
provider{" "}
70-
<LearnMoreLink href="https://docs.zenml.io/user-guide/production-guide/remote-storage" />
71-
</p>
72-
<div className="space-y-5">
73-
<div className="space-y-1">
74-
<label
75-
htmlFor="artifact-store-provider"
76-
className="text-text-sm text-theme-text-secondary"
77-
>
78-
Select your cloud provider
79-
</label>
80-
<ProviderSelect
81-
displayOther
82-
id="artifact-store-provider"
83-
value={selectedProvider}
84-
setValue={setSelectedProvider}
85-
/>
86-
</div>
87-
{getArtifactStoreStep(selectedProvider)}
88-
<div>
89-
<HelpBox link="https://docs.zenml.io/user-guide/production-guide/remote-storage" />
90-
</div>
91-
</div>
92-
</ChecklistItem>
93-
);
94-
}
95-
96-
export function CreateNewStack({ onboardingState, active }: Props) {
97-
const itemName: OnboardingChecklistItemName = "create_remote_stack";
98-
const item = getOnboardingItem(onboardingState || {}, itemName);
99-
11+
export function CreateNewStack({ completed, active, hasDownstreamStep }: OnboardingStep) {
12+
const link =
13+
routes.stacks.create.index + "?" + new URLSearchParams({ origin: "onboarding" }).toString();
10014
return (
10115
<ChecklistItem
102-
itemName={itemName}
103-
completed={!!item}
16+
hasDownstream={hasDownstreamStep}
17+
completed={completed}
10418
title="Create a new stack"
10519
active={active}
10620
>
@@ -109,40 +23,33 @@ export function CreateNewStack({ onboardingState, active }: Props) {
10923
<LearnMoreLink href="https://docs.zenml.io/user-guide/production-guide/understand-stacks" />
11024
</p>
11125
<div className="space-y-5">
112-
<div>
113-
<p className="mb-1 text-text-sm text-theme-text-secondary">
114-
Download the quickstart example to your local machine
115-
</p>
116-
<Codesnippet
117-
codeClasses="whitespace-pre-wrap"
118-
code="zenml stack register local_with_remote_storage -o default -a cloud_artifact_store"
119-
/>
26+
<div className="space-y-3">
27+
<p>Connect your Cloud to deploy your ZenML pipelines in a remote stack.</p>
28+
<Button className="w-fit" size="md" asChild>
29+
<Link className="flex" to={link}>
30+
<Plus className="h-5 w-5 shrink-0 fill-white" />
31+
Register a stack
32+
</Link>
33+
</Button>
12034
</div>
12135
<HelpBox link="https://docs.zenml.io/user-guide/production-guide/understand-stacks" />
12236
</div>
12337
</ChecklistItem>
12438
);
12539
}
12640

127-
export function RunNewPipeline({ active, onboardingState }: Props) {
128-
const itemName: OnboardingChecklistItemName = "run_remote_pipeline";
129-
const item = getOnboardingItem(onboardingState || {}, itemName);
130-
41+
export function RunNewPipeline({ active, completed, hasDownstreamStep }: OnboardingStep) {
13142
return (
13243
<ChecklistItem
133-
itemName={itemName}
134-
completed={!!item}
44+
hasDownstream={hasDownstreamStep}
45+
completed={completed}
13546
title="Run the pipeline in the new stack"
13647
active={active}
13748
>
13849
<div className="space-y-5">
13950
<div className="space-y-1">
14051
<p className="text-text-sm text-theme-text-secondary">Set the new stack</p>
141-
<Codesnippet
142-
wrap
143-
codeClasses="whitespace-pre-wrap"
144-
code="zenml stack set local_with_remote_storage"
145-
/>
52+
<Codesnippet wrap codeClasses="whitespace-pre-wrap" code="zenml stack set REMOTE_STACK" />
14653
</div>
14754
<div className="space-y-1">
14855
<p className="text-text-sm text-theme-text-secondary">Run the pipeline</p>

src/app/onboarding/ProductionSetup/index.tsx

Lines changed: 23 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
import ChevronDown from "@/assets/icons/chevron-down.svg?react";
22
import { Tick } from "@/components/Tick";
3-
import { useServerSettings } from "@/data/server/get-server-settings";
43
import { useServerInfo } from "@/data/server/info-query";
5-
import { PRODUCTION_SETUP_ITEMS } from "@/lib/constants";
6-
import { getOnboardingState, getProgress, getStarterSetupItems } from "@/lib/onboarding";
4+
import { useOnboarding } from "@/data/server/onboarding-state";
5+
import { getProductionSetup, getStarterSetup } from "@/lib/onboarding";
76
import { checkIsLocalServer } from "@/lib/server";
87
import {
98
Collapsible,
@@ -14,30 +13,26 @@ import {
1413
cn
1514
} from "@zenml-io/react-component-library";
1615
import { useState } from "react";
17-
import {
18-
CreateArtifactStore,
19-
CreateNewStack,
20-
CreateServiceConnector,
21-
RunNewPipeline
22-
} from "./Items";
16+
import { CreateNewStack, RunNewPipeline } from "./Items";
2317

2418
export function ProductionSetupChecklist() {
25-
const { isError, isPending, data } = useServerSettings({ throwOnError: true });
19+
const onboarding = useOnboarding({ refetchInterval: 5000 });
2620
const serverInfo = useServerInfo();
2721
const [open, setOpen] = useState(true);
2822

29-
if (isPending || serverInfo.isPending) return <Skeleton className="h-[200px] w-full" />;
30-
if (isError || serverInfo.isError) return null;
23+
if (onboarding.isPending || serverInfo.isPending)
24+
return <Skeleton className="h-[200px] w-full" />;
25+
if (onboarding.isError || serverInfo.isError) return null;
3126

32-
const STARTER_SETUP_ITEMS = getStarterSetupItems(
27+
const starterSetup = getStarterSetup(
28+
onboarding.data,
3329
checkIsLocalServer(serverInfo.data.deployment_type || "other")
3430
);
3531

36-
const onboardingState = getOnboardingState(data);
37-
const isStarterSetupFinished =
38-
getProgress(onboardingState, STARTER_SETUP_ITEMS) === STARTER_SETUP_ITEMS.length;
39-
const doneItems = getProgress(onboardingState, PRODUCTION_SETUP_ITEMS);
40-
const progress = (doneItems / PRODUCTION_SETUP_ITEMS.length) * 100;
32+
const { progress, totalItems, itemsDone, getItem } = getProductionSetup(onboarding.data);
33+
34+
const stackStep = getItem("stack_with_remote_orchestrator_created");
35+
const pipelineStep = getItem("pipeline_run_with_remote_orchestrator");
4136

4237
return (
4338
<>
@@ -53,7 +48,7 @@ export function ProductionSetupChecklist() {
5348
) : (
5449
<RadialProgress value={progress}>
5550
<span className="absolute text-text-xs font-semibold">
56-
{doneItems}/{PRODUCTION_SETUP_ITEMS.length}
51+
{itemsDone}/{totalItems}
5752
</span>
5853
</RadialProgress>
5954
)}
@@ -64,7 +59,7 @@ export function ProductionSetupChecklist() {
6459
<span className="text-text-md font-medium text-theme-text-secondary">(10 min)</span>
6560
</p>
6661
<p className="text-theme-text-secondary">
67-
{isStarterSetupFinished ? (
62+
{starterSetup.isFinished ? (
6863
"Level up your skills in a production setting."
6964
) : (
7065
<span className="text-primary-400">
@@ -83,23 +78,19 @@ export function ProductionSetupChecklist() {
8378
<CollapsibleContent className="border-t border-theme-border-moderate p-5">
8479
<ul className="divide-y divide-theme-border-moderate">
8580
<li className="py-5 first:pt-0 last:pb-0">
86-
<CreateServiceConnector
87-
onboardingState={onboardingState}
88-
active={isStarterSetupFinished}
81+
<CreateNewStack
82+
active={starterSetup.isFinished && stackStep.isActive}
83+
completed={stackStep.isCompleted}
84+
hasDownstreamStep={stackStep.hasDownStreamStep}
8985
/>
9086
</li>
9187
<li className="py-5 first:pt-0 last:pb-0">
92-
<CreateArtifactStore
93-
onboardingState={onboardingState}
94-
active={isStarterSetupFinished}
88+
<RunNewPipeline
89+
active={starterSetup.isFinished && pipelineStep.isActive}
90+
completed={pipelineStep.isCompleted}
91+
hasDownstreamStep={pipelineStep.hasDownStreamStep}
9592
/>
9693
</li>
97-
<li className="py-5 first:pt-0 last:pb-0">
98-
<CreateNewStack onboardingState={onboardingState} active={isStarterSetupFinished} />
99-
</li>
100-
<li className="py-5 first:pt-0 last:pb-0">
101-
<RunNewPipeline onboardingState={onboardingState} active={isStarterSetupFinished} />
102-
</li>
10394
</ul>
10495
</CollapsibleContent>
10596
</Collapsible>

src/app/onboarding/StarterSetup/Items.tsx

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,20 @@
1-
import { ChecklistItem } from "@/components/onboarding/ChecklistItem";
1+
import Help from "@/assets/icons/help.svg?react";
22
import { Codesnippet } from "@/components/CodeSnippet";
33
import { HelpBox } from "@/components/fallback-pages/Helpbox";
4-
import { Box, Skeleton, buttonVariants } from "@zenml-io/react-component-library";
5-
import Help from "@/assets/icons/help.svg?react";
6-
import { OnboardingChecklistItemName, OnboardingState } from "@/types/onboarding";
7-
import { getOnboardingItem } from "@/lib/onboarding";
4+
import { ChecklistItem } from "@/components/onboarding/ChecklistItem";
85
import { useServerInfo } from "@/data/server/info-query";
6+
import { OnboardingStep } from "@/types/onboarding";
7+
import { Box, Skeleton, buttonVariants } from "@zenml-io/react-component-library";
98

10-
type Props = {
11-
onboardingState?: OnboardingState;
12-
};
13-
export function ConnectZenMLStep({ onboardingState }: Props) {
9+
export function ConnectZenMLStep({ completed, hasDownstreamStep, active }: OnboardingStep) {
1410
const { data } = useServerInfo({ throwOnError: true });
15-
16-
const itemName = "connect_zenml";
17-
const item = getOnboardingItem(onboardingState || {}, itemName);
1811
return (
19-
<ChecklistItem itemName={itemName} completed={!!item} title="Connect to ZenML">
12+
<ChecklistItem
13+
active={active}
14+
hasDownstream={hasDownstreamStep}
15+
completed={completed}
16+
title="Connect to ZenML"
17+
>
2018
<div className="flex flex-col gap-5">
2119
<div>
2220
<p className="mb-1 text-text-sm text-theme-text-secondary">Install ZenML</p>
@@ -34,11 +32,14 @@ export function ConnectZenMLStep({ onboardingState }: Props) {
3432
);
3533
}
3634

37-
export function RunFirstPipeline({ onboardingState }: Props) {
38-
const itemName: OnboardingChecklistItemName = "run_first_pipeline";
39-
const item = getOnboardingItem(onboardingState || {}, itemName);
35+
export function RunFirstPipeline({ active, completed, hasDownstreamStep }: OnboardingStep) {
4036
return (
41-
<ChecklistItem itemName={itemName} completed={!!item} title="Run your first pipeline">
37+
<ChecklistItem
38+
active={active}
39+
hasDownstream={hasDownstreamStep}
40+
completed={completed}
41+
title="Run your first pipeline"
42+
>
4243
<div className="flex flex-col gap-5">
4344
<div>
4445
<p className="mb-1 text-text-sm text-theme-text-secondary">

0 commit comments

Comments
 (0)