Skip to content

Commit

Permalink
Add a fast Create Plan page - step 1
Browse files Browse the repository at this point in the history
Changes:
1. transfer data from VM List screen to Create Plan page
   via console.context-provider
2. add immer library to keep data in the reducer immutable
3. add uuid library to generate random suffixes
4. use forms for the Create Plan page - similar to Create Provider

Signed-off-by: Radoslaw Szwajkowski <[email protected]>
  • Loading branch information
rszwajko committed Jan 16, 2024
1 parent be0c929 commit 1c385d6
Show file tree
Hide file tree
Showing 15 changed files with 621 additions and 4 deletions.
36 changes: 36 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions packages/eslint-plugin/cspell.wordlist.txt
Original file line number Diff line number Diff line change
Expand Up @@ -66,3 +66,4 @@ multiqueue
filesystems
bootloader
typeahead
immer
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"{{groupCount}} Groups": "{{groupCount}} Groups",
"{{name}} Details": "{{name}} Details",
"{{selectedLength}} hosts selected.": "{{selectedLength}} hosts selected.",
"{{vmCount}} VMs selected ": "{{vmCount}} VMs selected ",
"{{vmDone}} of {{vmCount}} VMs migrated": "{{vmDone}} of {{vmCount}} VMs migrated",
"24 hours": "24 hours",
"404: Not Found": "404: Not Found",
Expand Down Expand Up @@ -57,10 +58,13 @@
"Copied": "Copied",
"Copy": "Copy",
"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 and edit": "Create and edit",
"Create and start": "Create and start",
"Create by using the form or manually entering YAML or JSON definitions, Provider CR stores attributes that enable MTV to connect to and interact with the source and target providers.": "Create by using the form or manually entering YAML or JSON definitions, Provider CR stores attributes that enable MTV to connect to and interact with the source and target providers.",
"Create NetworkMap": "Create NetworkMap",
"Create new provider": "Create new provider",
"Create plan": "Create plan",
"Create Plan": "Create Plan",
"Create provider": "Create provider",
"Create Provider": "Create Provider",
"Create StorageMap": "Create StorageMap",
Expand Down Expand Up @@ -191,6 +195,7 @@
"Maximum number of concurrent VM migrations. Default value is 20.": "Maximum number of concurrent VM migrations. Default value is 20.",
"Message": "Message",
"Message: {{message}}": "Message: {{message}}",
"Migrate": "Migrate",
"Migrating virtualization workloads is a multi-step process. <2>Learn more</2>.": "Migrating virtualization workloads is a multi-step process. <2>Learn more</2>.",
"Migration network maps are used to map network interfaces between source and target virtualization providers, at least one source and one target provider must be available in order to create a migration storage map, <2>Learn more</2>.": "Migration network maps are used to map network interfaces between source and target virtualization providers, at least one source and one target provider must be available in order to create a migration storage map, <2>Learn more</2>.",
"Migration networks maps are used to map network interfaces between source and target workloads.": "Migration networks maps are used to map network interfaces between source and target workloads.",
Expand Down Expand Up @@ -281,6 +286,7 @@
"Password": "Password",
"Path": "Path",
"Persistent TPM/EFI": "Persistent TPM/EFI",
"Plan name": "Plan name",
"Plans": "Plans",
"Plans for virtualization": "Plans for virtualization",
"Please choose a NetworkAttachmentDefinition for default data transfer.": "Please choose a NetworkAttachmentDefinition for default data transfer.",
Expand Down
5 changes: 4 additions & 1 deletion packages/forklift-console-plugin/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,18 +52,21 @@
"@types/jsonpath": "^0.2.0",
"copy-webpack-plugin": "^11.0.0",
"css-loader": "^6.7.1",
"immer": "^10.0.3",
"mini-svg-data-uri": "^1.4.4",
"react-linkify": "^1.0.0-alpha",
"style-loader": "^3.3.1",
"terser-webpack-plugin": "^5.3.6",
"ts-loader": "^9.3.1",
"tsconfig-paths-webpack-plugin": "^4.0.0",
"typescript": "^4.7.4",
"use-immer": "^0.9.0",
"uuid": "^9.0.1",
"webpack": "^5.79.0",
"webpack-cli": "^5.0.2",
"webpack-dev-server": "^4.7.4"
},
"msw": {
"workerDirectory": "dist"
}
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
import { ProviderModel, ProviderModelGroupVersionKind } from '@kubev2v/types';
import {
PlanModel,
PlanModelGroupVersionKind,
ProviderModel,
ProviderModelGroupVersionKind,
} from '@kubev2v/types';
import { EncodedExtension } from '@openshift/dynamic-plugin-sdk';
import {
ContextProvider,
CreateResource,
ModelMetadata,
ResourceDetailsPage,
Expand All @@ -13,6 +19,10 @@ export const exposedModules: ConsolePluginMetadata['exposedModules'] = {
ProvidersListPage: './modules/Providers/views/list/ProvidersListPage',
ProviderDetailsPage: './modules/Providers/views/details/ProviderDetailsPage',
ProvidersCreatePage: './modules/Providers/views/create/ProvidersCreatePage',
ProvidersCreateVmMigrationContext:
'./modules/Providers/views/migrate/ProvidersCreateVmMigrationContext',
ProvidersCreateVmMigrationPage:
'./modules/Providers/views/migrate/ProvidersCreateVmMigrationPage',
};

export const extensions: EncodedExtension[] = [
Expand Down Expand Up @@ -71,4 +81,23 @@ export const extensions: EncodedExtension[] = [
...ProviderModel,
},
} as EncodedExtension<CreateResource>,
{
type: 'console.context-provider',
properties: {
provider: { $codeRef: 'ProvidersCreateVmMigrationContext.CreateVmMigrationProvider' },
useValueHook: {
$codeRef: 'ProvidersCreateVmMigrationContext.useCreateVmMigrationContextValue',
},
},
} as EncodedExtension<ContextProvider>,
{
type: 'console.resource/create',
properties: {
component: {
$codeRef: 'ProvidersCreateVmMigrationPage',
},
model: PlanModelGroupVersionKind,
...PlanModel,
},
} as EncodedExtension<CreateResource>,
];
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// @index(['./*', /style/g], f => `export * from '${f.path}';`)
export * from './planTemplate';
export * from './providerTemplate';
export * from './secretTemplate';
// @endindex
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { V1beta1Plan } from '@kubev2v/types';

export const planTemplate: V1beta1Plan = {
apiVersion: 'forklift.konveyor.io/v1beta1',
kind: 'Plan',
metadata: {
name: undefined,
namespace: undefined,
},
spec: {
map: {},
targetNamespace: '',
},
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import React, { FC } from 'react';
import { useHistory } from 'react-router';
import { getResourceUrl } from 'src/modules/Providers/utils';
import { useCreateVmMigrationData } from 'src/modules/Providers/views/migrate';
import { useForkliftTranslation } from 'src/utils/i18n';

import { PlanModelRef, V1beta1Provider } from '@kubev2v/types';
import { Button, ToolbarItem } from '@patternfly/react-core';

import { VmData } from './VMCellProps';

export const MigrationAction: FC<{
selectedVms: VmData[];
provider: V1beta1Provider;
}> = ({ selectedVms, provider }) => {
const { t } = useForkliftTranslation();
const history = useHistory();
const namespace = provider?.metadata?.namespace;
const planListURL = getResourceUrl({
reference: PlanModelRef,
namespace,
namespaced: namespace !== undefined,
});
const { setData } = useCreateVmMigrationData();
return (
<ToolbarItem>
<Button
variant="secondary"
onClick={() => {
setData({ selectedVms, provider });
history.push(`${planListURL}/~new`);
}}
isDisabled={!selectedVms?.length}
>
{t('Migrate')}
</Button>
</ToolbarItem>
);
};
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { FC, useState } from 'react';
import { RouteComponentProps } from 'react-router-dom';
import { withIdBasedSelection } from 'src/components/page/withSelection';
import { GlobalActionWithSelection, withIdBasedSelection } from 'src/components/page/withSelection';
import { ProviderData } from 'src/modules/Providers/utils';
import { useForkliftTranslation } from 'src/utils/i18n';

Expand All @@ -16,6 +16,7 @@ import { Concern } from '@kubev2v/types';

import { useInventoryVms } from '../utils/useInventoryVms';

import { MigrationAction } from './MigrationAction';
import { VmData } from './VMCellProps';

export interface ProviderVirtualMachinesListProps extends RouteComponentProps {
Expand All @@ -29,8 +30,10 @@ export interface ProviderVirtualMachinesListProps extends RouteComponentProps {
pageId: string;
}

export const toId = (item: VmData) =>
item.vm.providerType === 'openshift' ? item.vm.uid : item.vm.id;
const PageWithSelection = withIdBasedSelection<VmData>({
toId: (item: VmData) => (item.vm.providerType === 'openshift' ? item.vm.uid : item.vm.id),
toId,
canSelect: (item: VmData) => !!item,
});

Expand All @@ -47,6 +50,16 @@ export const ProviderVirtualMachinesList: FC<ProviderVirtualMachinesListProps> =
const [userSettings] = useState(() => loadUserSettings({ pageId }));

const [vmData, loading] = useInventoryVms(obj, loaded, loadError);
const actions: FC<GlobalActionWithSelection<VmData>>[] = [
({ selectedIds }) => (
<MigrationAction
{...{
provider: obj?.provider,
selectedVms: vmData.filter((data) => selectedIds.includes(toId(data))),
}}
/>
),
];

return (
<PageWithSelection
Expand All @@ -62,6 +75,7 @@ export const ProviderVirtualMachinesList: FC<ProviderVirtualMachinesListProps> =
features: EnumFilter,
}}
extraSupportedMatchers={[concernsMatcher, featuresMatcher]}
GlobalActionToolbarItems={actions}
/>
);
};
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import React, { useState } from 'react';
import { useForkliftTranslation } from 'src/utils/i18n';

import { ProviderModelGroupVersionKind } from '@kubev2v/types';
import { ResourceLink } from '@openshift-console/dynamic-plugin-sdk';
import { DescriptionList, Form, FormGroup, TextInput } from '@patternfly/react-core';

import { DetailsItem } from '../../utils';

import { PageAction, setPlanName } from './actions';
import { CreateVmMigrationPageState } from './reducer';

export const PlansCreateForm = ({
state: { newPlan: plan, validation },
dispatch,
}: {
state: CreateVmMigrationPageState;
dispatch: (action: PageAction<unknown, unknown>) => void;
}) => {
const { t } = useForkliftTranslation();
const [isNameEdited, setIsNameEdited] = useState(false);
return (
<DescriptionList
className="forklift-create-provider-edit-section"
columnModifier={{
default: '1Col',
}}
>
{isNameEdited ? (
<Form>
<FormGroup
label={t('Plan name')}
isRequired
fieldId="planName"
validated={validation.name}
>
<TextInput
isRequired
type="text"
id="planName"
value={plan.metadata.name}
validated={validation.name}
onChange={(value) => dispatch(setPlanName(value?.trim() ?? '', []))}
/>
</FormGroup>
</Form>
) : (
<DetailsItem
title={t('Plan name')}
content={plan.metadata.name}
onEdit={() => setIsNameEdited(true)}
/>
)}
<DetailsItem
title={t('Source provider')}
content={
<ResourceLink
name={plan?.spec?.provider?.source?.name}
namespace={plan?.spec?.provider?.source?.namespace}
groupVersionKind={ProviderModelGroupVersionKind}
/>
}
/>
<DetailsItem
title={t('{{vmCount}} VMs selected ', { vmCount: plan.spec.vms.length })}
content={''}
/>
</DescriptionList>
);
};
Loading

0 comments on commit 1c385d6

Please sign in to comment.