diff --git a/app/assets/ico/vendor/install-kubernetes.svg b/app/assets/ico/vendor/install-kubernetes.svg new file mode 100644 index 000000000..075065fb6 --- /dev/null +++ b/app/assets/ico/vendor/install-kubernetes.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/app/assets/ico/vendor/kaas-icon.svg b/app/assets/ico/vendor/kaas-icon.svg new file mode 100644 index 000000000..37d427eed --- /dev/null +++ b/app/assets/ico/vendor/kaas-icon.svg @@ -0,0 +1,4 @@ + + + + diff --git a/app/portainer/components/BoxSelector/index.ts b/app/portainer/components/BoxSelector/index.ts index 14115ea3d..95caaa132 100644 --- a/app/portainer/components/BoxSelector/index.ts +++ b/app/portainer/components/BoxSelector/index.ts @@ -14,6 +14,7 @@ const BoxSelectorReact = react2angular(BoxSelector, [ 'options', 'radioName', 'slim', + 'hiddenSpacingCount', ]); export const boxSelectorModule = angular diff --git a/app/react/components/BoxSelector/BoxSelector.tsx b/app/react/components/BoxSelector/BoxSelector.tsx index 624e30649..2a924263d 100644 --- a/app/react/components/BoxSelector/BoxSelector.tsx +++ b/app/react/components/BoxSelector/BoxSelector.tsx @@ -20,12 +20,14 @@ export type Props = Union & { radioName: string; options: ReadonlyArray> | Array>; slim?: boolean; + hiddenSpacingCount?: number; }; export function BoxSelector({ radioName, options, slim = false, + hiddenSpacingCount, ...props }: Props) { return ( @@ -47,6 +49,10 @@ export function BoxSelector({ slim={slim} /> ))} + {hiddenSpacingCount && + Array.from(Array(hiddenSpacingCount)).map((_, index) => ( + + ))} diff --git a/app/react/portainer/environments/wizard/EnvironmentTypeSelectView/EndpointTypeView.tsx b/app/react/portainer/environments/wizard/EnvironmentTypeSelectView/EndpointTypeView.tsx index f0fbd9b38..68b0a8cf5 100644 --- a/app/react/portainer/environments/wizard/EnvironmentTypeSelectView/EndpointTypeView.tsx +++ b/app/react/portainer/environments/wizard/EnvironmentTypeSelectView/EndpointTypeView.tsx @@ -8,19 +8,21 @@ import { useAnalytics } from '@/angulartics.matomo/analytics-services'; import { Button } from '@@/buttons'; import { PageHeader } from '@@/PageHeader'; import { Widget, WidgetBody, WidgetTitle } from '@@/Widget'; +import { FormSection } from '@@/form-components/FormSection'; import { useCreateEdgeDeviceParam } from '../hooks/useCreateEdgeDeviceParam'; +import { EnvironmentSelector } from './EnvironmentSelector'; import { - EnvironmentSelector, - EnvironmentSelectorValue, -} from './EnvironmentSelector'; -import { environmentTypes } from './environment-types'; + EnvironmentOptionValue, + existingEnvironmentTypes, + newEnvironmentTypes, +} from './environment-types'; export function EnvironmentTypeSelectView() { const createEdgeDevice = useCreateEdgeDeviceParam(); - const [types, setTypes] = useState([]); + const [types, setTypes] = useState([]); const { trackEvent } = useAnalytics(); const router = useRouter(); @@ -36,11 +38,34 @@ export function EnvironmentTypeSelectView() { - + + + + You can onboard different types of environments, select all + that apply. + + + Connect to existing environments + + + Set up new environments + + + startWizard()} @@ -59,6 +84,11 @@ export function EnvironmentTypeSelectView() { return; } + const environmentTypes = [ + ...existingEnvironmentTypes, + ...newEnvironmentTypes, + ]; + const steps = _.compact( types.map((id) => environmentTypes.find((eType) => eType.id === id)) ); diff --git a/app/react/portainer/environments/wizard/EnvironmentTypeSelectView/EnvironmentSelector.tsx b/app/react/portainer/environments/wizard/EnvironmentTypeSelectView/EnvironmentSelector.tsx index a484bf5ba..96155613e 100644 --- a/app/react/portainer/environments/wizard/EnvironmentTypeSelectView/EnvironmentSelector.tsx +++ b/app/react/portainer/environments/wizard/EnvironmentTypeSelectView/EnvironmentSelector.tsx @@ -1,17 +1,16 @@ import { BoxSelector } from '@@/BoxSelector'; -import { FormSection } from '@@/form-components/FormSection'; -import { environmentTypes } from './environment-types'; - -export type EnvironmentSelectorValue = typeof environmentTypes[number]['id']; +import { EnvironmentOption, EnvironmentOptionValue } from './environment-types'; interface Props { - value: EnvironmentSelectorValue[]; - onChange(value: EnvironmentSelectorValue[]): void; + value: EnvironmentOptionValue[]; + onChange(value: EnvironmentOptionValue[]): void; + options: EnvironmentOption[]; createEdgeDevice?: boolean; + hiddenSpacingCount?: number; } -const hasEdge: EnvironmentSelectorValue[] = [ +const hasEdge: EnvironmentOptionValue[] = [ 'dockerStandalone', 'dockerSwarm', 'kubernetes', @@ -21,31 +20,25 @@ export function EnvironmentSelector({ value, onChange, createEdgeDevice, + options, + hiddenSpacingCount, }: Props) { - const options = filterEdgeDevicesIfNeed(environmentTypes, createEdgeDevice); + const filteredOptions = filterEdgeDevicesIfNeed(options, createEdgeDevice); return ( - - - - You can onboard different types of environments, select all that - apply. - - - - - + ); } function filterEdgeDevicesIfNeed( - types: typeof environmentTypes, + types: EnvironmentOption[], createEdgeDevice?: boolean ) { if (!createEdgeDevice) { diff --git a/app/react/portainer/environments/wizard/EnvironmentTypeSelectView/environment-types.ts b/app/react/portainer/environments/wizard/EnvironmentTypeSelectView/environment-types.ts index e91c8d996..a289df49c 100644 --- a/app/react/portainer/environments/wizard/EnvironmentTypeSelectView/environment-types.ts +++ b/app/react/portainer/environments/wizard/EnvironmentTypeSelectView/environment-types.ts @@ -3,10 +3,27 @@ import Docker from '@/assets/ico/vendor/docker.svg?c'; import Kubernetes from '@/assets/ico/vendor/kubernetes.svg?c'; import Azure from '@/assets/ico/vendor/azure.svg?c'; import Nomad from '@/assets/ico/vendor/nomad.svg?c'; +import KaaS from '@/assets/ico/vendor/kaas-icon.svg?c'; +import InstallK8s from '@/assets/ico/vendor/install-kubernetes.svg?c'; -import KaaSIcon from './kaas-icon.svg?c'; +import { BoxSelectorOption } from '@@/BoxSelector'; -export const environmentTypes = [ +export type EnvironmentOptionValue = + | 'dockerStandalone' + | 'dockerSwarm' + | 'kubernetes' + | 'aci' + | 'nomad' + | 'kaas' + | 'k8sInstall'; + +export interface EnvironmentOption + extends BoxSelectorOption { + id: EnvironmentOptionValue; + value: EnvironmentOptionValue; +} + +export const existingEnvironmentTypes: EnvironmentOption[] = [ { id: 'dockerStandalone', value: 'dockerStandalone', @@ -49,23 +66,43 @@ export const environmentTypes = [ feature: FeatureId.NOMAD, disabledWhenLimited: true, }, +]; + +export const newEnvironmentTypes: EnvironmentOption[] = [ { id: 'kaas', value: 'kaas', - label: 'KaaS', - description: 'Provision a Kubernetes environment with a cloud provider', - icon: KaaSIcon, + label: 'Provision KaaS Cluster', + description: + "Provision a Kubernetes cluster via a cloud provider's Kubernetes as a Service", + icon: KaaS, iconType: 'logo', feature: FeatureId.KAAS_PROVISIONING, disabledWhenLimited: true, }, -] as const; + { + id: 'k8sInstall', + value: 'k8sInstall', + label: 'Create Kubernetes cluster', + description: 'Create a Kubernetes cluster on existing infrastructure', + icon: InstallK8s, + iconType: 'logo', + feature: FeatureId.K8SINSTALL, + disabledWhenLimited: true, + }, +]; -export const formTitles = { +export const environmentTypes = [ + ...existingEnvironmentTypes, + ...newEnvironmentTypes, +]; + +export const formTitles: Record = { dockerStandalone: 'Connect to your Docker Standalone environment', dockerSwarm: 'Connect to your Docker Swarm environment', kubernetes: 'Connect to your Kubernetes environment', aci: 'Connect to your ACI environment', nomad: 'Connect to your Nomad environment', kaas: 'Provision a KaaS environment', + k8sInstall: 'Create a Kubernetes cluster', }; diff --git a/app/react/portainer/environments/wizard/EnvironmentTypeSelectView/kaas-icon.svg b/app/react/portainer/environments/wizard/EnvironmentTypeSelectView/kaas-icon.svg deleted file mode 100644 index 61f7b621f..000000000 --- a/app/react/portainer/environments/wizard/EnvironmentTypeSelectView/kaas-icon.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/app/react/portainer/environments/wizard/EnvironmentsCreationView/EnvironmentsCreationView.tsx b/app/react/portainer/environments/wizard/EnvironmentsCreationView/EnvironmentsCreationView.tsx index bd78764ef..b1af1fd26 100644 --- a/app/react/portainer/environments/wizard/EnvironmentsCreationView/EnvironmentsCreationView.tsx +++ b/app/react/portainer/environments/wizard/EnvironmentsCreationView/EnvironmentsCreationView.tsx @@ -19,10 +19,10 @@ import { FormSection } from '@@/form-components/FormSection'; import { Icon } from '@@/Icon'; import { + EnvironmentOptionValue, environmentTypes, formTitles, } from '../EnvironmentTypeSelectView/environment-types'; -import { EnvironmentSelectorValue } from '../EnvironmentTypeSelectView/EnvironmentSelector'; import { WizardDocker } from './WizardDocker'; import { WizardAzure } from './WizardAzure'; @@ -138,7 +138,7 @@ export function EnvironmentCreationView() { } } -function useParamEnvironmentTypes(): EnvironmentSelectorValue[] { +function useParamEnvironmentTypes(): EnvironmentOptionValue[] { const { params: { envType }, } = useCurrentStateAndParams(); @@ -185,7 +185,7 @@ function useStepper( setCurrentStepIndex(currentStepIndex - 1); } - function getComponent(id: EnvironmentSelectorValue) { + function getComponent(id: EnvironmentOptionValue) { switch (id) { case 'dockerStandalone': case 'dockerSwarm': diff --git a/app/react/portainer/feature-flags/enums.ts b/app/react/portainer/feature-flags/enums.ts index df372429c..4c9efa8d6 100644 --- a/app/react/portainer/feature-flags/enums.ts +++ b/app/react/portainer/feature-flags/enums.ts @@ -38,5 +38,6 @@ export enum FeatureId { ENFORCE_DEPLOYMENT_OPTIONS = 'k8s-enforce-deployment-options', K8S_ADM_ONLY_USR_INGRESS_DEPLY = 'k8s-admin-only-ingress-deploy', K8S_ROLLING_RESTART = 'k8s-rolling-restart', + K8SINSTALL = 'k8s-install', K8S_ANNOTATIONS = 'k8s-annotations', } diff --git a/app/react/portainer/feature-flags/feature-flags.service.ts b/app/react/portainer/feature-flags/feature-flags.service.ts index b3943bcb2..a16559ab7 100644 --- a/app/react/portainer/feature-flags/feature-flags.service.ts +++ b/app/react/portainer/feature-flags/feature-flags.service.ts @@ -19,6 +19,7 @@ export async function init(edition: Edition) { [FeatureId.K8S_RESOURCE_POOL_STORAGE_QUOTA]: Edition.BE, [FeatureId.K8S_CREATE_FROM_KUBECONFIG]: Edition.BE, [FeatureId.KAAS_PROVISIONING]: Edition.BE, + [FeatureId.K8SINSTALL]: Edition.BE, [FeatureId.NOMAD]: Edition.BE, [FeatureId.ACTIVITY_AUDIT]: Edition.BE, [FeatureId.EXTERNAL_AUTH_LDAP]: Edition.BE,
+ You can onboard different types of environments, select all + that apply. +
+ Connect to existing environments +
Set up new environments
- You can onboard different types of environments, select all that - apply. -