Skip to content

Commit

Permalink
[WIP] CNV-23376: Create new page for InstanceTypes VM creation flow
Browse files Browse the repository at this point in the history
Signed-off-by: Aviv Turgeman <aturgema@redhat.com>
  • Loading branch information
avivtur committed Dec 22, 2022
1 parent 2932b63 commit 19ae73f
Show file tree
Hide file tree
Showing 15 changed files with 337 additions and 8 deletions.
7 changes: 6 additions & 1 deletion console-extensions.json
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,12 @@
{
"type": "console.page/route",
"properties": {
"path": ["/k8s/ns/:ns/templatescatalog", "/k8s/all-namespaces/templatescatalog"],
"path": [
"/k8s/ns/:ns/templatescatalog",
"/k8s/all-namespaces/templatescatalog",
"/k8s/ns/:ns/templatescatalog/instanceTypes",
"/k8s/all-namespaces/templatescatalog/instanceTypes"
],
"component": {
"$codeRef": "TemplatesCatalog"
}
Expand Down
10 changes: 10 additions & 0 deletions locales/en/plugin__kubevirt-plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@
"Active users": "Active users",
"Activity": "Activity",
"Add affinity rule": "Add affinity rule",
"Add bootable Volume": "Add bootable Volume",
"Add Config Map, Secret or Service Account": "Add Config Map, Secret or Service Account",
"Add configuration": "Add configuration",
"Add disk": "Add disk",
Expand Down Expand Up @@ -250,6 +251,7 @@
"Create MigrationPolicy": "Create MigrationPolicy",
"Create new secret": "Create new secret",
"Create new sysprep": "Create new sysprep",
"Create new VirtualMachine": "Create new VirtualMachine",
"Create project": "Create project",
"Create Template": "Create Template",
"Create Virtual Machine": "Create Virtual Machine",
Expand Down Expand Up @@ -322,6 +324,8 @@
"Detach sysprep": "Detach sysprep",
"Details": "Details",
"Detected file extension is {{fileNameExtension}}": "Detected file extension is {{fileNameExtension}}",
"Developer preview": "Developer preview",
"Developer preview features are not intended to be used in production environments. The clusters deployed with the developer preview features are considered to be development clusters and are not supported through the Red Hat Customer Portal case management system.": "Developer preview features are not intended to be used in production environments. The clusters deployed with the developer preview features are considered to be development clusters and are not supported through the Red Hat Customer Portal case management system.",
"Device name": "Device name",
"DIC": "DIC",
"Disconnect": "Disconnect",
Expand Down Expand Up @@ -411,6 +415,7 @@
"Follow guided documentation to build applications and familiarize yourself with key features.": "Follow guided documentation to build applications and familiarize yourself with key features.",
"Form view": "Form view",
"From": "From",
"From bootable Volume": "From bootable Volume",
"From catalog": "From catalog",
"Gateway address": "Gateway address",
"General": "General",
Expand Down Expand Up @@ -446,6 +451,7 @@
"Info": "Info",
"installation iso of Microsoft Windows 10 ": "installation iso of Microsoft Windows 10 ",
"Installed version": "Installed version",
"InstanceTypes": "InstanceTypes",
"Interface": "Interface",
"Interface Type": "Interface Type",
"Invalid certificate, please visit the following URL and approve it": "Invalid certificate, please visit the following URL and approve it",
Expand Down Expand Up @@ -776,10 +782,13 @@
"Select a resource": "Select a resource",
"Select an available secret": "Select an available secret",
"Select an existing persistent volume claim already available on the cluster and clone it.": "Select an existing persistent volume claim already available on the cluster and clone it.",
"Select an option from which to create a VirtualMachine.": "Select an option from which to create a VirtualMachine.",
"Select an option to create a VirtualMachine": "Select an option to create a VirtualMachine",
"Select boot source": "Select boot source",
"Select bootable Volume": "Select bootable Volume",
"Select console type": "Select console type",
"Select DataSource to use for automatic image upload.": "Select DataSource to use for automatic image upload.",
"Select InstanceType": "Select InstanceType",
"Select Nodes that must have all the following expressions.": "Select Nodes that must have all the following expressions.",
"Select workloads that must have all the following expressions.": "Select workloads that must have all the following expressions.",
"Selected StorageClass is different from the default StorageClass": "Selected StorageClass is different from the default StorageClass",
Expand Down Expand Up @@ -873,6 +882,7 @@
"Template provider": "Template provider",
"Template: {{templateDisplayName}}": "Template: {{templateDisplayName}}",
"Templates": "Templates",
"Templates catalog": "Templates catalog",
"Templates project": "Templates project",
"Templates provided by {{providerName}} are not editable.": "Templates provided by {{providerName}} are not editable.",
"Terms": "Terms",
Expand Down
4 changes: 2 additions & 2 deletions src/views/catalog/Catalog.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import * as React from 'react';
import { Route, Switch } from 'react-router-dom';

import CreateVMHorizontalNav from './CreateVMHorizontalNav/CreateVMHorizontalNav';
import CustomizeVirtualMachine from './customize/CustomizeVirtualMachine';
import TemplatesCatalog from './templatescatalog/TemplatesCatalog';
import { WizardVMContextProvider } from './utils/WizardVMContext';
import Wizard from './wizard/Wizard';

Expand All @@ -24,7 +24,7 @@ const Catalog: React.FC = () => {
]}
component={Wizard}
/>
<Route component={TemplatesCatalog} />
<Route component={CreateVMHorizontalNav} />
</Switch>
</WizardVMContextProvider>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
.create-vm-instance-type-section {
padding: var(--pf-global--spacer--md);
&__step {
font-size: var(--pf-global--FontSize--xl);
height: var(--pf-global--spacer--xl);
width: var(--pf-global--spacer--xl);
margin-right: var(--pf-global--spacer--md);
background-color: var(--pf-global--BackgroundColor--200);
color: var(--pf-global--Color--dark-100);
border-radius: 50%;
display: inline-grid;
align-items: center;
text-align: center;
}
&__step.current {
background-color: var(--pf-global--primary-color--100);
color: var(--pf-global--Color--light-100);
font-weight: bolder;
}
&__header {
font-size: var(--pf-global--FontSize--xl);
}
&__header.current {
color: var(--pf-global--primary-color--100);
font-weight: bolder;
}
&__add-volume-btn {
padding-right: var(--pf-global--spacer--sm);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import React, { FC, useState } from 'react';
import { RouteComponentProps } from 'react-router-dom';

import { t } from '@kubevirt-utils/hooks/useKubevirtTranslation';
import { Card, Divider, Grid, GridItem, List } from '@patternfly/react-core';

import CreateVMFooter from './components/CreateVMFooter/CreateVMFooter';
import SectionListItem from './components/SectionListItem/SectionListItem';
import { INSTANCE_TYPES_SECTIONS } from './constants';

import './CreateFromInstanceType.scss';

const CreateFromInstanceType: FC<RouteComponentProps<{ ns: string }>> = () => {
const sectionState = useState<INSTANCE_TYPES_SECTIONS>(INSTANCE_TYPES_SECTIONS.SELECT_VOLUME);
return (
<>
<Grid className="co-dashboard-body">
<GridItem>
<Card>
<List isPlain>
<SectionListItem
headerText={t('Select bootable Volume')}
sectionKey={INSTANCE_TYPES_SECTIONS.SELECT_VOLUME}
sectionState={sectionState}
>
<div>Placeholder for BootableVolumesTable</div>
</SectionListItem>
<Divider inset={{ default: 'insetLg' }} />
<SectionListItem
headerText={t('Select InstanceType')}
sectionKey={INSTANCE_TYPES_SECTIONS.SELECT_INSTANCE_TYPE}
sectionState={sectionState}
>
<div>Placeholder for InstanceTypesCards</div>
</SectionListItem>
<Divider inset={{ default: 'insetLg' }} />
<SectionListItem
headerText={t('VirtualMachine details')}
sectionKey={INSTANCE_TYPES_SECTIONS.VM_DETAILS}
sectionState={sectionState}
>
<div>Placeholder for VMReviewDetails</div>
</SectionListItem>
</List>
</Card>
</GridItem>
</Grid>
<CreateVMFooter />
</>
);
};

export default CreateFromInstanceType;
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.create-vm-instance-type-footer {
padding: var(--pf-global--spacer--lg);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import React, { FC, useState } from 'react';

import { useKubevirtTranslation } from '@kubevirt-utils/hooks/useKubevirtTranslation';
import {
Button,
ButtonVariant,
Checkbox,
Split,
SplitItem,
Stack,
StackItem,
} from '@patternfly/react-core';

import './CreateVMFooter.scss';

const CreateVMFooter: FC = () => {
const { t } = useKubevirtTranslation();
const [startVM, setStartVM] = useState(true);
return (
<footer className="create-vm-instance-type-footer">
<Stack hasGutter>
<StackItem>
<Checkbox
id="start-after-create-checkbox"
isChecked={startVM}
onChange={setStartVM}
label={t('Start this VirtualMachine after creation')}
/>
</StackItem>
<StackItem>
<Split hasGutter>
<SplitItem>
<Button variant={ButtonVariant.primary}>{t('Quick create VirtualMachine')}</Button>
</SplitItem>
<SplitItem>
<Button variant={ButtonVariant.link}>{t('Cancel')}</Button>
</SplitItem>
</Split>
</StackItem>
</Stack>
</footer>
);
};

export default CreateVMFooter;
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import React, { FC } from 'react';
import classNames from 'classnames';

import { INSTANCE_TYPES_SECTIONS } from '@catalog/CreateFromInstanceTypes/constants';
import { useKubevirtTranslation } from '@kubevirt-utils/hooks/useKubevirtTranslation';
import { Button, ButtonVariant, ListItem, Split, SplitItem } from '@patternfly/react-core';

type SectionListItemProps = {
sectionKey: INSTANCE_TYPES_SECTIONS;
headerText: string;
sectionState: [
INSTANCE_TYPES_SECTIONS,
React.Dispatch<React.SetStateAction<INSTANCE_TYPES_SECTIONS>>,
];
};

const SectionListItem: FC<SectionListItemProps> = ({
sectionKey,
headerText,
sectionState: [currentSection, setCurrentSection],
children,
}) => {
const { t } = useKubevirtTranslation();
const currentSectionClass = currentSection === sectionKey && 'current';
return (
<ListItem
onClick={() => setCurrentSection(sectionKey)}
className="create-vm-instance-type-section"
>
<Split className="create-vm-instance-type-section__add-volume-btn">
<SplitItem
className={classNames('create-vm-instance-type-section__step', currentSectionClass)}
>
{sectionKey}
</SplitItem>
<SplitItem
className={classNames('create-vm-instance-type-section__header', currentSectionClass)}
>
{headerText}
</SplitItem>
{sectionKey === INSTANCE_TYPES_SECTIONS.SELECT_VOLUME && (
<>
<SplitItem isFilled />
<SplitItem>
<Button variant={ButtonVariant.secondary}>{t('Add bootable Volume')}</Button>
</SplitItem>
</>
)}
</Split>
{children}
</ListItem>
);
};

export default SectionListItem;
5 changes: 5 additions & 0 deletions src/views/catalog/CreateFromInstanceTypes/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export enum INSTANCE_TYPES_SECTIONS {
SELECT_VOLUME = 1,
SELECT_INSTANCE_TYPE = 2,
VM_DETAILS = 3,
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
.create-vm-horizontal-nav{
.pf-c-tabs__item {
margin-right: var(--pf-global--spacer--xl);
}

.pf-c-tab-content {
height: 100%;
}
}
68 changes: 68 additions & 0 deletions src/views/catalog/CreateVMHorizontalNav/CreateVMHorizontalNav.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import React, { FC, useState } from 'react';
import { RouteComponentProps } from 'react-router-dom';

import CreateFromInstanceType from '@catalog/CreateFromInstanceTypes/CreateFromInstanceType';
import TemplatesCatalog from '@catalog/templatescatalog/TemplatesCatalog';
import { ALL_NAMESPACES } from '@kubevirt-utils/hooks/constants';
import { useKubevirtTranslation } from '@kubevirt-utils/hooks/useKubevirtTranslation';
import { Stack, StackItem, Tab, Tabs, Title } from '@patternfly/react-core';
import { CatalogIcon, ImageIcon } from '@patternfly/react-icons';

import CreateVMTabTitle from './components/CreateVMTabTitle/CreateVMTabTitle';
import { CREATE_VM_TAB } from './constants';

import './CreateVMHorizontalNav.scss';

const CreateVMHorizontalNav: FC<RouteComponentProps<{ ns: string }>> = ({
history,
location,
match,
}) => {
const { t } = useKubevirtTranslation();
const [currentTab, setCurrentTab] = useState<CREATE_VM_TAB>(
location.pathname.includes(CREATE_VM_TAB.INSTANCE_TYPES)
? CREATE_VM_TAB.INSTANCE_TYPES
: CREATE_VM_TAB.CATALOG,
);

const handleTabClick = (
event: React.MouseEvent<any> | React.KeyboardEvent | MouseEvent,
tabIndex: CREATE_VM_TAB,
) => {
setCurrentTab(tabIndex);
history.push(
`/k8s/${
match?.params?.ns ? `ns/${match?.params?.ns}` : ALL_NAMESPACES
}/templatescatalog${tabIndex}`,
);
};

return (
<div className="create-vm-horizontal-nav">
<div className="pf-c-page__main-breadcrumb">
<Stack hasGutter className="co-m-pane__heading">
<StackItem>
<Title headingLevel="h1">{t('Create new VirtualMachine')}</Title>
</StackItem>
<StackItem>{t('Select an option from which to create a VirtualMachine.')}</StackItem>
</Stack>
</div>
<Tabs usePageInsets activeKey={currentTab} onSelect={handleTabClick}>
<Tab
eventKey={CREATE_VM_TAB.CATALOG}
title={<CreateVMTabTitle Icon={CatalogIcon} titleText={t('Templates catalog')} />}
>
<TemplatesCatalog match={match} location={location} history={history} />
</Tab>
<Tab
eventKey={CREATE_VM_TAB.INSTANCE_TYPES}
title={<CreateVMTabTitle Icon={ImageIcon} titleText={t('InstanceTypes')} badge />}
>
<CreateFromInstanceType match={match} location={location} history={history} />
</Tab>
</Tabs>
</div>
);
};

export default CreateVMHorizontalNav;
Loading

0 comments on commit 19ae73f

Please sign in to comment.