Skip to content

Commit

Permalink
add support for dedicated cloud instances (#1371)
Browse files Browse the repository at this point in the history
  • Loading branch information
jsladerman authored Oct 2, 2024
1 parent 368691e commit 44d8184
Show file tree
Hide file tree
Showing 13 changed files with 267 additions and 114 deletions.
24 changes: 19 additions & 5 deletions www/src/components/create-cluster/CreateCluster.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import OnboardingCard from 'components/shell/onboarding/OnboardingCard'

import {
ConsoleInstanceStatus,
ConsoleInstanceType,
useConsoleInstanceQuery,
} from 'generated/graphql'

Expand All @@ -23,6 +24,7 @@ import usePersistedState from 'hooks/usePersistedState'
import { ConsoleCreationStatus } from './ConsoleCreationStatus'
import { CreateClusterActions } from './CreateClusterActions'
import {
CloudOption,
CreateClusterContext,
CreateClusterContextType,
CreateClusterStepKey,
Expand All @@ -31,6 +33,7 @@ import {
} from './CreateClusterWizard'

export const CUR_CREATE_CLUSTER_STEP_KEY = 'cur-create-cluster-step'
export const CLOUD_OPTION_KEY = 'cloud-option'
export const HOSTING_OPTION_KEY = 'hosting-option'
export const CUR_CONSOLE_INSTANCE_KEY = 'cur-console-instance-id'

Expand All @@ -39,18 +42,24 @@ export function CreateCluster() {
const navigate = useNavigate()
const [curStep, setCurStep] = usePersistedState<CreateClusterStepKey>(
CUR_CREATE_CLUSTER_STEP_KEY,
CreateClusterStepKey.HostingOptions
CreateClusterStepKey.ChooseCloud
)
const [hostingOption, setHostingOption] = usePersistedState<
'local' | 'cloud'
>(HOSTING_OPTION_KEY, 'local')
const [cloudOption, setCloudOption] = usePersistedState<CloudOption>(
CLOUD_OPTION_KEY,
'local'
)
const [hostingOption, setHostingOption] =
usePersistedState<ConsoleInstanceType>(
HOSTING_OPTION_KEY,
ConsoleInstanceType.Shared
)
const [finishEnabled, setFinishEnabled] = useState(false)
const [continueBtn, setContinueBtn] = useState<ReactElement | undefined>()
const [consoleInstanceId, setConsoleInstanceId] = usePersistedState<
Nullable<string>
>(CUR_CONSOLE_INSTANCE_KEY, null)

const steps = hostingOption === 'local' ? localSteps : cloudSteps
const steps = cloudOption === 'local' ? localSteps : cloudSteps
const curStepIndex = steps.findIndex((step) => step.key === curStep)

const { data, error } = useConsoleInstanceQuery({
Expand All @@ -66,6 +75,8 @@ export function CreateCluster() {
() => ({
curStep,
setCurStep,
cloudOption,
setCloudOption,
hostingOption,
setHostingOption,
finishEnabled,
Expand All @@ -85,6 +96,8 @@ export function CreateCluster() {
[
curStep,
setCurStep,
cloudOption,
setCloudOption,
hostingOption,
setHostingOption,
finishEnabled,
Expand Down Expand Up @@ -148,6 +161,7 @@ export function CreateCluster() {

export function clearCreateClusterState() {
localStorage.removeItem(`plural-${CUR_CREATE_CLUSTER_STEP_KEY}`)
localStorage.removeItem(`plural-${CLOUD_OPTION_KEY}`)
localStorage.removeItem(`plural-${HOSTING_OPTION_KEY}`)
localStorage.removeItem(`plural-${CUR_CONSOLE_INSTANCE_KEY}`)
}
Expand Down
20 changes: 13 additions & 7 deletions www/src/components/create-cluster/CreateClusterActions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import { useNavigate } from 'react-router-dom'

import { useBillingSubscription } from 'components/account/billing/BillingSubscriptionProvider'

import { ConsoleInstanceType } from 'generated/graphql'

import {
CreateClusterStepKey,
cloudSteps,
Expand All @@ -22,18 +24,22 @@ export function CreateClusterActions() {
const {
curStep,
setCurStep,
cloudOption,
hostingOption,
finishEnabled,
continueBtn,
consoleInstanceId,
} = useCreateClusterContext()

const { isPaidPlan, isTrialPlan, isTrialExpired } = useBillingSubscription()
const { isPaidPlan, isTrialPlan, isTrialExpired, isEnterprisePlan } =
useBillingSubscription()
const disableContinue =
hostingOption === 'cloud' &&
((!isPaidPlan && !isTrialPlan) || (isTrialPlan && isTrialExpired))
cloudOption === 'cloud' &&
((!isPaidPlan && !isTrialPlan) ||
(isTrialPlan && isTrialExpired) ||
(!isEnterprisePlan && hostingOption === ConsoleInstanceType.Dedicated))

const steps = hostingOption === 'local' ? localSteps : cloudSteps
const steps = cloudOption === 'local' ? localSteps : cloudSteps
const curStepIndex = steps.findIndex((step) => step.key === curStep)
const prevStep = steps[curStepIndex - 1]?.key
const nextStep = steps[curStepIndex + 1]?.key
Expand All @@ -42,13 +48,13 @@ export function CreateClusterActions() {
if (consoleInstanceId) {
localStorage.setItem(FINISHED_CONSOLE_INSTANCE_KEY, consoleInstanceId)
}
if (hostingOption === 'local') {
if (cloudOption === 'local') {
localStorage.setItem(FINISHED_LOCAL_CREATE_KEY, 'true')
}
clearCreateClusterState()
navigate(
`/overview/clusters/${
hostingOption === 'local' ? 'self-hosted' : 'plural-cloud'
cloudOption === 'local' ? 'self-hosted' : 'plural-cloud'
}`
)
}
Expand Down Expand Up @@ -76,7 +82,7 @@ export function CreateClusterActions() {
<Flex gap="medium">
{prevStep &&
!(
hostingOption === 'cloud' &&
cloudOption === 'cloud' &&
curStep === CreateClusterStepKey.InstallCli
) && (
<Button
Expand Down
33 changes: 23 additions & 10 deletions www/src/components/create-cluster/CreateClusterWizard.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,26 @@
import {
CliIcon,
CloudIcon,
GlobeIcon,
ListIcon,
ShieldOutlineIcon,
StepperSteps,
} from '@pluralsh/design-system'

import React, { ReactElement, createContext, useContext } from 'react'

import { ConsoleInstanceType } from 'generated/graphql'

import { AuthenticationStep } from './steps/AuthenticationStep'
import { ConfigureCloudInstanceStep } from './steps/ConfigureCloudInstanceStep'
import { DeployLocallyStep } from './steps/DeployLocallyStep'
import { HostingOptionsStep } from './steps/HostingOptionsStep'
import { ChooseCloudStep } from './steps/ChooseCloudStep'
import { InstallCliStep } from './steps/InstallCliStep'
import { ChooseHostingOptionStep } from './steps/ChooseHostingOptionStep'

export enum CreateClusterStepKey {
HostingOptions = 'hosting-options',
ChooseCloud = 'choose-cloud',
ChooseHostingOption = 'choose-hosting-option',
ConfigureCloudInstance = 'configure-cloud-instance',
InstallCli = 'install-cli',
Authentication = 'authentication',
Expand All @@ -28,11 +33,13 @@ type CreateClusterStep = Omit<StepperSteps[number], 'stepTitle' | 'key'> & {
component: React.ReactNode
}

type HostingOption = 'local' | 'cloud'
export type CloudOption = 'local' | 'cloud'

export type CreateClusterContextType = {
hostingOption: HostingOption
setHostingOption: (option: HostingOption) => void
cloudOption: CloudOption
setCloudOption: (option: CloudOption) => void
hostingOption: ConsoleInstanceType
setHostingOption: (option: ConsoleInstanceType) => void
curStep: CreateClusterStepKey
setCurStep: (step: CreateClusterStepKey) => void
finishEnabled: boolean
Expand Down Expand Up @@ -63,10 +70,10 @@ export const useCreateClusterContext = () => {

export const localSteps: CreateClusterStep[] = [
{
key: CreateClusterStepKey.HostingOptions,
key: CreateClusterStepKey.ChooseCloud,
stepTitle: 'Hosting options',
IconComponent: CloudIcon,
component: <HostingOptionsStep />,
component: <ChooseCloudStep />,
},
{
key: CreateClusterStepKey.InstallCli,
Expand All @@ -84,10 +91,16 @@ export const localSteps: CreateClusterStep[] = [

export const cloudSteps: CreateClusterStep[] = [
{
key: CreateClusterStepKey.HostingOptions,
stepTitle: 'Hosting options',
key: CreateClusterStepKey.ChooseCloud,
stepTitle: 'Choose cloud',
IconComponent: CloudIcon,
component: <HostingOptionsStep />,
component: <ChooseCloudStep />,
},
{
key: CreateClusterStepKey.ChooseHostingOption,
stepTitle: 'Choose hosting option',
IconComponent: GlobeIcon,
component: <ChooseHostingOptionStep />,
},
{
key: CreateClusterStepKey.ConfigureCloudInstance,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
import { Callout, CloudIcon, ConsoleIcon, Flex } from '@pluralsh/design-system'
import {
Callout,
Chip,
CloudIcon,
ConsoleIcon,
Flex,
} from '@pluralsh/design-system'
import { CloudOption } from 'components/shell/onboarding/sections/cloud/CloudOption'

import { useBillingSubscription } from 'components/account/billing/BillingSubscriptionProvider'

import { useTheme } from 'styled-components'

import { useCreateClusterContext } from '../CreateClusterWizard'

export function HostingOptionsStep() {
const theme = useTheme()
const { hostingOption, setHostingOption } = useCreateClusterContext()
import { CalloutLinkButton } from './ChooseHostingOptionStep'

export function ChooseCloudStep() {
const { cloudOption, setCloudOption } = useCreateClusterContext()
const { isPaidPlan, isTrialPlan, daysUntilTrialExpires, isTrialExpired } =
useBillingSubscription()
const isFreePlan = !isPaidPlan && !isTrialPlan
Expand All @@ -21,44 +26,47 @@ export function HostingOptionsStep() {
>
<Flex gap="large">
<CloudOption
selected={hostingOption === 'local'}
onClick={() => setHostingOption('local')}
icon={
<CloudIcon
size={40}
color={theme.colors['icon-light']}
/>
}
selected={cloudOption === 'local'}
onClick={() => setCloudOption('local')}
icon={<CloudIcon size={40} />}
chip={<Chip>Free Plan</Chip>}
header="Deploy Yourself"
description="Host your control plane in your own cloud."
/>
<CloudOption
selected={hostingOption === 'cloud'}
onClick={() => setHostingOption('cloud')}
icon={
<ConsoleIcon
size={40}
color={theme.colors['icon-light']}
/>
}
selected={cloudOption === 'cloud'}
onClick={() => setCloudOption('cloud')}
icon={<ConsoleIcon size={40} />}
chip={<Chip severity="info">Pro Plan</Chip>}
header="Use Plural Cloud"
description="Host your control plane in a Plural Cloud instance."
/>
</Flex>
{hostingOption === 'cloud' &&
{cloudOption === 'cloud' &&
(isFreePlan || (isTrialPlan && isTrialExpired) ? (
<Callout
severity="warning"
title="This option is not available on a free plan."
title="This option is only available on the Pro plan."
>
To use a Plural Cloud Instance for your cluster deployment, consider{' '}
<a
href="/account/billing"
target="_blank"
rel="noopener noreferrer"
<Flex
direction="column"
gap="medium"
>
upgrading your plan.
</a>
If you would like to create a shared cloud instance, please
upgrade to a Pro or Enterprise plan - or contact sales to learn
more.
<Flex gap="medium">
<CalloutLinkButton href="/account/billing">
Upgrade to Pro Plan
</CalloutLinkButton>
<CalloutLinkButton
secondary
href="https://plural.sh/contact-sales"
>
Contact sales
</CalloutLinkButton>
</Flex>
</Flex>
</Callout>
) : isTrialPlan ? (
<Callout
Expand Down
Loading

0 comments on commit 44d8184

Please sign in to comment.