Skip to content

Commit

Permalink
Merge pull request #1222 from yaacov/allow-to-create-new-namespaces
Browse files Browse the repository at this point in the history
🐾 Allow to create new namespaces
  • Loading branch information
yaacov authored Jun 18, 2024
2 parents 98c61c0 + 335ea3c commit 8482a13
Show file tree
Hide file tree
Showing 5 changed files with 76 additions and 131 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@
"Create a migration plan and select VMs from the source provider for migration.": "Create a migration plan and select VMs from the source provider for migration.",
"Create migration plan": "Create migration plan",
"Create NetworkMap": "Create NetworkMap",
"Create new namespace:": "Create new namespace:",
"Create new provider": "Create new provider",
"Create Plan": "Create Plan",
"Create provider": "Create provider",
Expand Down Expand Up @@ -144,8 +145,6 @@
"Edit provider web UI link": "Edit provider web UI link",
"Edit Snapshot polling interval (seconds)": "Edit Snapshot polling interval (seconds)",
"Edit StorageMap": "Edit StorageMap",
"Edit target namespace": "Edit target namespace",
"Edit target provider": "Edit target provider",
"Edit URL": "Edit URL",
"Edit VDDK init image": "Edit VDDK init image",
"Empty": "Empty",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@ export interface FilterableSelectProps {
noResultFoundLabel?: ReactNode;
/** Label to display for the option to create a new item */
createNewOptionLabel?: ReactNode;
/** Indicates that the element is perceivable but disabled, so it is not editable or otherwise operable. */
isDisabled?: boolean;
/** Indicates if the menu should be without the outer box-shadow */
isPlain?: boolean;
/** Indicates if the menu should be scrollable */
isScrollable?: boolean;
}

/**
Expand All @@ -48,6 +54,9 @@ export const FilterableSelect: React.FunctionComponent<FilterableSelectProps> =
placeholder = 'Select item',
noResultFoundLabel = 'No results found',
createNewOptionLabel = 'Create new option:',
isDisabled = false,
isPlain = false,
isScrollable = false,
}) => {
const [isOpen, setIsOpen] = React.useState(false);
const [selectedItem, setSelectedItem] = React.useState<string>(value);
Expand Down Expand Up @@ -265,6 +274,9 @@ export const FilterableSelect: React.FunctionComponent<FilterableSelectProps> =
setInputValue(selectedItem);
}}
toggle={toggle}
aria-disabled={isDisabled}
isPlain={isPlain}
isScrollable={isScrollable}
>
<SelectList>
{selectOptions.map((option, index) => (
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, { ReactNode, useState } from 'react';
import { FilterableSelect } from 'src/components';
import SectionHeading from 'src/components/headers/SectionHeading';
import { useForkliftTranslation } from 'src/utils/i18n';
import { isProviderLocalOpenshift } from 'src/utils/resources';

import { FormGroupWithHelpText } from '@kubev2v/common';
import {
Expand Down Expand Up @@ -141,8 +141,6 @@ export const PlansCreateForm = ({
} = state;

const [isNameEdited, setIsNameEdited] = useState(true);
const [isTargetProviderEdited, setIsTargetProviderEdited] = useState(false);
const [isTargetNamespaceEdited, setIsTargetNamespaceEdited] = useState(false);

const networkMessages = buildNetworkMessages(t);
const storageMessages = buildStorageMessages(t);
Expand Down Expand Up @@ -215,124 +213,71 @@ export const PlansCreateForm = ({
className="forklift--create-vm-migration-plan--section-header"
/>

{isTargetProviderEdited ||
validation.targetProvider === 'error' ||
!plan.spec.provider?.destination ? (
<Form isWidthLimited>
<FormGroupWithHelpText
label={t('Target provider')}
isRequired
fieldId="targetProvider"
validated={validation.targetProvider}
helperTextInvalid={
availableProviders.filter(getIsTarget).length === 0
? t('No provider is available')
: t('The chosen provider is no longer available.')
}
>
<FormSelect
value={plan.spec.provider?.destination?.name}
onChange={(value) => dispatch(setPlanTargetProvider(value))}
validated={validation.targetProvider}
id="targetProvider"
isDisabled={flow.editingDone}
>
{[
<FormSelectOption
key="placeholder"
value={''}
label={t('Select a provider')}
isPlaceholder
isDisabled
/>,
...availableProviders
.filter(getIsTarget)
.map((provider, index) => (
<FormSelectOption
key={provider?.metadata?.name || index}
value={provider?.metadata?.name}
label={provider?.metadata?.name ?? provider?.metadata?.uid ?? String(index)}
/>
)),
]}
</FormSelect>
</FormGroupWithHelpText>
</Form>
) : (
<EditableDescriptionItem
title={t('Target provider')}
content={
<ResourceLink
name={plan.spec.provider?.destination?.name}
namespace={plan.spec.provider?.destination?.namespace}
groupVersionKind={ProviderModelGroupVersionKind}
/>
<Form isWidthLimited>
<FormGroupWithHelpText
label={t('Target provider')}
isRequired
fieldId="targetProvider"
validated={validation.targetProvider}
helperTextInvalid={
availableProviders.filter(getIsTarget).length === 0
? t('No provider is available')
: t('The chosen provider is no longer available.')
}
ariaEditLabel={t('Edit target provider')}
onEdit={() => setIsTargetProviderEdited(true)}
isDisabled={flow.editingDone}
/>
)}
{isTargetNamespaceEdited ||
validation.targetNamespace === 'error' ||
!plan.spec.targetNamespace ? (
<Form isWidthLimited>
<FormGroupWithHelpText
label={t('Target namespace')}
isRequired
id="targetNamespace"
validated={validation.targetNamespace}
>
<FormSelect
value={plan.spec.provider?.destination?.name}
onChange={(value) => dispatch(setPlanTargetProvider(value))}
id="targetProvider"
isDisabled={flow.editingDone}
>
<FormSelect
value={plan.spec.targetNamespace}
onChange={(value) => dispatch(setPlanTargetNamespace(value))}
validated={validation.targetNamespace}
id="targetNamespace"
isDisabled={flow.editingDone}
>
{[
<FormSelectOption
key="placeholder"
value={''}
label={t('Select a namespace')}
isPlaceholder
isDisabled
/>,
...availableTargetNamespaces.map((ns, index) => (
{[
<FormSelectOption
key="placeholder"
value={''}
label={t('Select a provider')}
isPlaceholder
isDisabled
/>,
...availableProviders
.filter(getIsTarget)
.map((provider, index) => (
<FormSelectOption
key={ns?.name || index}
value={ns?.name}
label={ns?.name ?? String(index)}
isDisabled={
namespacesUsedBySelectedVms.includes(ns?.name) &&
plan.spec.provider?.destination?.name === plan.spec.provider.source.name
}
key={provider?.metadata?.name || index}
value={provider?.metadata?.name}
label={provider?.metadata?.name ?? provider?.metadata?.uid ?? String(index)}
/>
)),
]}
</FormSelect>
</FormGroupWithHelpText>
</Form>
) : (
<EditableDescriptionItem
title={t('Target namespace')}
content={
<ResourceLink
name={plan.spec.targetNamespace}
namespace=""
groupVersionKind={{ kind: 'Namespace', version: 'v1', group: '' }}
linkTo={isProviderLocalOpenshift(
availableProviders.find(
(p) => p?.metadata?.name === plan.spec.provider?.destination?.name,
),
)}
/>
}
ariaEditLabel={t('Edit target namespace')}
onEdit={() => setIsTargetNamespaceEdited(true)}
isDisabled={flow.editingDone}
/>
)}
]}
</FormSelect>
</FormGroupWithHelpText>
</Form>

<Form isWidthLimited>
<FormGroupWithHelpText
label={t('Target namespace')}
isRequired
id="targetNamespace"
validated={validation.targetNamespace}
placeholder={t('Select a namespace')}
>
<FilterableSelect
selectOptions={availableTargetNamespaces.map((ns) => ({
itemId: ns?.name,
isDisabled:
namespacesUsedBySelectedVms.includes(ns?.name) &&
plan.spec.provider?.destination?.name === plan.spec.provider.source.name,
children: ns?.name,
}))}
value={plan.spec.targetNamespace}
onSelect={(value) => dispatch(setPlanTargetNamespace(value as string))}
isDisabled={flow.editingDone}
isScrollable
canCreate
createNewOptionLabel={t('Create new namespace:')}
/>
</FormGroupWithHelpText>
</Form>

<SectionHeading
text={t('Storage and network mappings')}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { Draft } from 'immer';
import { DefaultRow, ResourceFieldFactory, RowProps, withTr } from '@kubev2v/common';
import {
IoK8sApimachineryPkgApisMetaV1ObjectMeta,
OpenShiftNamespace,
OVirtNicProfile,
ProviderType,
V1beta1Plan,
Expand Down Expand Up @@ -55,16 +54,8 @@ export const validatePlanName = (name: string, existingPlans: V1beta1Plan[]) =>
? 'success'
: 'error';

export const validateTargetNamespace = (
namespace: string,
availableNamespaces: OpenShiftNamespace[],
alreadyInUseBySelectedVms: boolean,
) =>
validateK8sName(namespace) &&
availableNamespaces?.find((n) => n.name === namespace) &&
!alreadyInUseBySelectedVms
? 'success'
: 'error';
export const validateTargetNamespace = (namespace: string, alreadyInUseBySelectedVms: boolean) =>
!!namespace && validateK8sName(namespace) && !alreadyInUseBySelectedVms ? 'success' : 'error';

export const setTargetProvider = (
draft: Draft<CreateVmMigrationPageState>,
Expand Down Expand Up @@ -114,7 +105,6 @@ export const setTargetNamespace = (
plan.spec.targetNamespace = targetNamespace;
draft.validation.targetNamespace = validateTargetNamespace(
targetNamespace,
draft.existingResources.targetNamespaces,
alreadyInUseBySelectedVms({
namespace: targetNamespace,
namespacesUsedBySelectedVms,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,6 @@ const handlers: {

validation.targetNamespace = validateTargetNamespace(
plan.spec.targetNamespace,
availableTargetNamespaces,
alreadyInUse(plan.spec.targetNamespace),
);
if (validation.targetNamespace === 'success') {
Expand Down

0 comments on commit 8482a13

Please sign in to comment.