Skip to content

Commit

Permalink
feat: new onboarding (#615)
Browse files Browse the repository at this point in the history
  • Loading branch information
Cahllagerfeld authored Jul 12, 2024
1 parent 79eca5e commit 385008a
Show file tree
Hide file tree
Showing 22 changed files with 497 additions and 318 deletions.
143 changes: 25 additions & 118 deletions src/app/onboarding/ProductionSetup/Items.tsx
Original file line number Diff line number Diff line change
@@ -1,106 +1,20 @@
import { ChecklistItem } from "@/components/onboarding/ChecklistItem";
import { CloudProvider, ProviderSelect } from "./ProviderSelect";
import { HelpBox } from "@/components/fallback-pages/Helpbox";
import { useState } from "react";
import { getOnboardingItem } from "@/lib/onboarding";
import { OnboardingChecklistItemName, OnboardingState } from "@/types/onboarding";
import { getServiceConnectorStep } from "./ConnectorContent";
import { getArtifactStoreStep } from "./ArtifactStore";
import Plus from "@/assets/icons/plus.svg?react";
import { Codesnippet } from "@/components/CodeSnippet";
import { HelpBox } from "@/components/fallback-pages/Helpbox";
import { ChecklistItem } from "@/components/onboarding/ChecklistItem";
import {} from "@/lib/onboarding";
import { routes } from "@/router/routes";
import { OnboardingStep } from "@/types/onboarding";
import { Button } from "@zenml-io/react-component-library";
import { Link } from "react-router-dom";

type Props = {
onboardingState?: OnboardingState;
active?: boolean;
};

export function CreateServiceConnector({ onboardingState, active }: Props) {
const [selectedProvider, setSelectedProvider] = useState<CloudProvider>("aws");
const itemName: OnboardingChecklistItemName = "create_service_connector";
const item = getOnboardingItem(onboardingState || {}, itemName);
return (
<ChecklistItem
active={active}
completed={!!item}
title="Create a service connector"
itemName={itemName}
>
<p className="mb-3">
A service connector grants users of your ZenML server the ability to access components like
your artifact store{" "}
<LearnMoreLink href="https://docs.zenml.io/user-guide/production-guide/remote-storage#configuring-permissions-with-your-first-service-connector" />
</p>
<div className="space-y-5">
<div className="space-y-1">
<label
htmlFor="artifact-store-provider"
className="text-text-sm text-theme-text-secondary"
>
Select your cloud provider
</label>
<ProviderSelect
id="artifact-store-provider"
value={selectedProvider}
setValue={setSelectedProvider}
/>
</div>
{getServiceConnectorStep(selectedProvider)}
<div>
<HelpBox link="https://docs.zenml.io/user-guide/production-guide/remote-storage#configuring-permissions-with-your-first-service-connector" />
</div>
</div>
</ChecklistItem>
);
}

export function CreateArtifactStore({ onboardingState, active }: Props) {
const [selectedProvider, setSelectedProvider] = useState<CloudProvider>("aws");
const itemName: OnboardingChecklistItemName = "create_remote_artifact_store";
const item = getOnboardingItem(onboardingState || {}, itemName);

return (
<ChecklistItem
itemName={itemName}
completed={!!item}
title="Create an artifact store"
active={active}
>
<p className="mb-3">
Configuring a remote artifact store will version your pipeline's data directly in your cloud
provider{" "}
<LearnMoreLink href="https://docs.zenml.io/user-guide/production-guide/remote-storage" />
</p>
<div className="space-y-5">
<div className="space-y-1">
<label
htmlFor="artifact-store-provider"
className="text-text-sm text-theme-text-secondary"
>
Select your cloud provider
</label>
<ProviderSelect
displayOther
id="artifact-store-provider"
value={selectedProvider}
setValue={setSelectedProvider}
/>
</div>
{getArtifactStoreStep(selectedProvider)}
<div>
<HelpBox link="https://docs.zenml.io/user-guide/production-guide/remote-storage" />
</div>
</div>
</ChecklistItem>
);
}

export function CreateNewStack({ onboardingState, active }: Props) {
const itemName: OnboardingChecklistItemName = "create_remote_stack";
const item = getOnboardingItem(onboardingState || {}, itemName);

export function CreateNewStack({ completed, active, hasDownstreamStep }: OnboardingStep) {
const link =
routes.stacks.create.index + "?" + new URLSearchParams({ origin: "onboarding" }).toString();
return (
<ChecklistItem
itemName={itemName}
completed={!!item}
hasDownstream={hasDownstreamStep}
completed={completed}
title="Create a new stack"
active={active}
>
Expand All @@ -109,40 +23,33 @@ export function CreateNewStack({ onboardingState, active }: Props) {
<LearnMoreLink href="https://docs.zenml.io/user-guide/production-guide/understand-stacks" />
</p>
<div className="space-y-5">
<div>
<p className="mb-1 text-text-sm text-theme-text-secondary">
Download the quickstart example to your local machine
</p>
<Codesnippet
codeClasses="whitespace-pre-wrap"
code="zenml stack register local_with_remote_storage -o default -a cloud_artifact_store"
/>
<div className="space-y-3">
<p>Connect your Cloud to deploy your ZenML pipelines in a remote stack.</p>
<Button className="w-fit" size="md" asChild>
<Link className="flex" to={link}>
<Plus className="h-5 w-5 shrink-0 fill-white" />
Register a stack
</Link>
</Button>
</div>
<HelpBox link="https://docs.zenml.io/user-guide/production-guide/understand-stacks" />
</div>
</ChecklistItem>
);
}

export function RunNewPipeline({ active, onboardingState }: Props) {
const itemName: OnboardingChecklistItemName = "run_remote_pipeline";
const item = getOnboardingItem(onboardingState || {}, itemName);

export function RunNewPipeline({ active, completed, hasDownstreamStep }: OnboardingStep) {
return (
<ChecklistItem
itemName={itemName}
completed={!!item}
hasDownstream={hasDownstreamStep}
completed={completed}
title="Run the pipeline in the new stack"
active={active}
>
<div className="space-y-5">
<div className="space-y-1">
<p className="text-text-sm text-theme-text-secondary">Set the new stack</p>
<Codesnippet
wrap
codeClasses="whitespace-pre-wrap"
code="zenml stack set local_with_remote_storage"
/>
<Codesnippet wrap codeClasses="whitespace-pre-wrap" code="zenml stack set REMOTE_STACK" />
</div>
<div className="space-y-1">
<p className="text-text-sm text-theme-text-secondary">Run the pipeline</p>
Expand Down
55 changes: 23 additions & 32 deletions src/app/onboarding/ProductionSetup/index.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import ChevronDown from "@/assets/icons/chevron-down.svg?react";
import { Tick } from "@/components/Tick";
import { useServerSettings } from "@/data/server/get-server-settings";
import { useServerInfo } from "@/data/server/info-query";
import { PRODUCTION_SETUP_ITEMS } from "@/lib/constants";
import { getOnboardingState, getProgress, getStarterSetupItems } from "@/lib/onboarding";
import { useOnboarding } from "@/data/server/onboarding-state";
import { getProductionSetup, getStarterSetup } from "@/lib/onboarding";
import { checkIsLocalServer } from "@/lib/server";
import {
Collapsible,
Expand All @@ -14,30 +13,26 @@ import {
cn
} from "@zenml-io/react-component-library";
import { useState } from "react";
import {
CreateArtifactStore,
CreateNewStack,
CreateServiceConnector,
RunNewPipeline
} from "./Items";
import { CreateNewStack, RunNewPipeline } from "./Items";

export function ProductionSetupChecklist() {
const { isError, isPending, data } = useServerSettings({ throwOnError: true });
const onboarding = useOnboarding({ refetchInterval: 5000 });
const serverInfo = useServerInfo();
const [open, setOpen] = useState(true);

if (isPending || serverInfo.isPending) return <Skeleton className="h-[200px] w-full" />;
if (isError || serverInfo.isError) return null;
if (onboarding.isPending || serverInfo.isPending)
return <Skeleton className="h-[200px] w-full" />;
if (onboarding.isError || serverInfo.isError) return null;

const STARTER_SETUP_ITEMS = getStarterSetupItems(
const starterSetup = getStarterSetup(
onboarding.data,
checkIsLocalServer(serverInfo.data.deployment_type || "other")
);

const onboardingState = getOnboardingState(data);
const isStarterSetupFinished =
getProgress(onboardingState, STARTER_SETUP_ITEMS) === STARTER_SETUP_ITEMS.length;
const doneItems = getProgress(onboardingState, PRODUCTION_SETUP_ITEMS);
const progress = (doneItems / PRODUCTION_SETUP_ITEMS.length) * 100;
const { progress, totalItems, itemsDone, getItem } = getProductionSetup(onboarding.data);

const stackStep = getItem("stack_with_remote_orchestrator_created");
const pipelineStep = getItem("pipeline_run_with_remote_orchestrator");

return (
<>
Expand All @@ -53,7 +48,7 @@ export function ProductionSetupChecklist() {
) : (
<RadialProgress value={progress}>
<span className="absolute text-text-xs font-semibold">
{doneItems}/{PRODUCTION_SETUP_ITEMS.length}
{itemsDone}/{totalItems}
</span>
</RadialProgress>
)}
Expand All @@ -64,7 +59,7 @@ export function ProductionSetupChecklist() {
<span className="text-text-md font-medium text-theme-text-secondary">(10 min)</span>
</p>
<p className="text-theme-text-secondary">
{isStarterSetupFinished ? (
{starterSetup.isFinished ? (
"Level up your skills in a production setting."
) : (
<span className="text-primary-400">
Expand All @@ -83,23 +78,19 @@ export function ProductionSetupChecklist() {
<CollapsibleContent className="border-t border-theme-border-moderate p-5">
<ul className="divide-y divide-theme-border-moderate">
<li className="py-5 first:pt-0 last:pb-0">
<CreateServiceConnector
onboardingState={onboardingState}
active={isStarterSetupFinished}
<CreateNewStack
active={starterSetup.isFinished && stackStep.isActive}
completed={stackStep.isCompleted}
hasDownstreamStep={stackStep.hasDownStreamStep}
/>
</li>
<li className="py-5 first:pt-0 last:pb-0">
<CreateArtifactStore
onboardingState={onboardingState}
active={isStarterSetupFinished}
<RunNewPipeline
active={starterSetup.isFinished && pipelineStep.isActive}
completed={pipelineStep.isCompleted}
hasDownstreamStep={pipelineStep.hasDownStreamStep}
/>
</li>
<li className="py-5 first:pt-0 last:pb-0">
<CreateNewStack onboardingState={onboardingState} active={isStarterSetupFinished} />
</li>
<li className="py-5 first:pt-0 last:pb-0">
<RunNewPipeline onboardingState={onboardingState} active={isStarterSetupFinished} />
</li>
</ul>
</CollapsibleContent>
</Collapsible>
Expand Down
35 changes: 18 additions & 17 deletions src/app/onboarding/StarterSetup/Items.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,20 @@
import { ChecklistItem } from "@/components/onboarding/ChecklistItem";
import Help from "@/assets/icons/help.svg?react";
import { Codesnippet } from "@/components/CodeSnippet";
import { HelpBox } from "@/components/fallback-pages/Helpbox";
import { Box, Skeleton, buttonVariants } from "@zenml-io/react-component-library";
import Help from "@/assets/icons/help.svg?react";
import { OnboardingChecklistItemName, OnboardingState } from "@/types/onboarding";
import { getOnboardingItem } from "@/lib/onboarding";
import { ChecklistItem } from "@/components/onboarding/ChecklistItem";
import { useServerInfo } from "@/data/server/info-query";
import { OnboardingStep } from "@/types/onboarding";
import { Box, Skeleton, buttonVariants } from "@zenml-io/react-component-library";

type Props = {
onboardingState?: OnboardingState;
};
export function ConnectZenMLStep({ onboardingState }: Props) {
export function ConnectZenMLStep({ completed, hasDownstreamStep, active }: OnboardingStep) {
const { data } = useServerInfo({ throwOnError: true });

const itemName = "connect_zenml";
const item = getOnboardingItem(onboardingState || {}, itemName);
return (
<ChecklistItem itemName={itemName} completed={!!item} title="Connect to ZenML">
<ChecklistItem
active={active}
hasDownstream={hasDownstreamStep}
completed={completed}
title="Connect to ZenML"
>
<div className="flex flex-col gap-5">
<div>
<p className="mb-1 text-text-sm text-theme-text-secondary">Install ZenML</p>
Expand All @@ -34,11 +32,14 @@ export function ConnectZenMLStep({ onboardingState }: Props) {
);
}

export function RunFirstPipeline({ onboardingState }: Props) {
const itemName: OnboardingChecklistItemName = "run_first_pipeline";
const item = getOnboardingItem(onboardingState || {}, itemName);
export function RunFirstPipeline({ active, completed, hasDownstreamStep }: OnboardingStep) {
return (
<ChecklistItem itemName={itemName} completed={!!item} title="Run your first pipeline">
<ChecklistItem
active={active}
hasDownstream={hasDownstreamStep}
completed={completed}
title="Run your first pipeline"
>
<div className="flex flex-col gap-5">
<div>
<p className="mb-1 text-text-sm text-theme-text-secondary">
Expand Down
Loading

0 comments on commit 385008a

Please sign in to comment.