diff --git a/sass/components/Form/form-group.scss b/sass/components/Form/form-group.scss
index 1d4f87ede..bfc71d9e7 100644
--- a/sass/components/Form/form-group.scss
+++ b/sass/components/Form/form-group.scss
@@ -19,6 +19,16 @@
margin-bottom: 23px;
}
+.kubevirt-form-group__field--with-addendum {
+ width: calc(100% - 2.5em);
+ display: inline-block;
+}
+
+.kubevirt-form-group__addendum {
+ margin-left: 0.5em;
+ width: 2em;
+}
+
.kubevirt-form-group__field-help .popover {
max-width: 400px;
}
diff --git a/src/components/CreateDiskRow/CreateDiskRow.js b/src/components/CreateDiskRow/CreateDiskRow.js
index e3602ec40..ab0e12347 100644
--- a/src/components/CreateDiskRow/CreateDiskRow.js
+++ b/src/components/CreateDiskRow/CreateDiskRow.js
@@ -47,6 +47,7 @@ const getDiskColumns = (storage, storageClasses, LoadingComponent) => {
required: true,
title: 'Size',
disabled: storage.creating,
+ addendum: 'Gi',
},
bus: {
id: 'disk-bus',
diff --git a/src/components/CreateDiskRow/fixtures/CreateDiskRow.fixture.js b/src/components/CreateDiskRow/fixtures/CreateDiskRow.fixture.js
index 1f2544107..0c6b43e10 100644
--- a/src/components/CreateDiskRow/fixtures/CreateDiskRow.fixture.js
+++ b/src/components/CreateDiskRow/fixtures/CreateDiskRow.fixture.js
@@ -1,4 +1,5 @@
import { CreateDiskRow } from '../CreateDiskRow';
+import { storageClasses } from '../../Wizard/CreateVmWizard/fixtures/CreateVmWizard.fixture';
export default {
component: CreateDiskRow,
@@ -7,7 +8,7 @@ export default {
onChange: () => {},
onAccept: () => {},
onCancel: () => {},
- storageClasses: [],
+ storageClasses,
LoadingComponent: () => null,
},
};
diff --git a/src/components/CreateDiskRow/tests/__snapshots__/CreateDiskRow.test.js.snap b/src/components/CreateDiskRow/tests/__snapshots__/CreateDiskRow.test.js.snap
index edcfedd86..2eee79512 100644
--- a/src/components/CreateDiskRow/tests/__snapshots__/CreateDiskRow.test.js.snap
+++ b/src/components/CreateDiskRow/tests/__snapshots__/CreateDiskRow.test.js.snap
@@ -26,6 +26,7 @@ exports[` renders correctly 1`] = `
"validate": [Function],
},
"size": Object {
+ "addendum": "Gi",
"disabled": undefined,
"id": "disk-size",
"required": true,
@@ -33,9 +34,14 @@ exports[` renders correctly 1`] = `
"type": "positive-number",
},
"storageClass": Object {
- "choices": Array [],
- "defaultValue": "--- No Storage Class Available ---",
- "disabled": true,
+ "choices": Array [
+ "nfs",
+ "iscsi",
+ "glusterfs",
+ "azuredisk",
+ ],
+ "defaultValue": "--- Select Storage Class ---",
+ "disabled": false,
"id": "disk-storage-class",
"type": "dropdown",
},
diff --git a/src/components/Dialog/CloneDialog/tests/CloneDialog.test.js b/src/components/Dialog/CloneDialog/tests/CloneDialog.test.js
index 5de554a11..1d5671cf0 100644
--- a/src/components/Dialog/CloneDialog/tests/CloneDialog.test.js
+++ b/src/components/Dialog/CloneDialog/tests/CloneDialog.test.js
@@ -30,11 +30,10 @@ const startVm = (component, checked) => setCheckbox(component.find('#start-vm').
const clickCloneVm = component => clickButton(component, 'Clone Virtual Machine');
-const getNameValidation = component =>
- component
- .find(HelpBlock)
- .at(0)
- .text();
+const getNameValidation = component => {
+ const wrapper = component.find(HelpBlock).at(0);
+ return wrapper.exists() ? wrapper.text() : null;
+};
const selectNamespace = (component, namespace) => {
const namespaceDropdown = component.find('#namespace-dropdown');
@@ -89,19 +88,19 @@ describe('', () => {
};
const component = mount(testCloneDialog([vm1, vm2]));
- expect(getNameValidation(component)).toEqual('');
+ expect(getNameValidation(component)).toEqual(null);
setVmName(component, getName(vm1));
expect(getNameValidation(component)).toEqual(`Name ${VIRTUAL_MACHINE_EXISTS}`);
selectNamespace(component, getNamespace(vm2));
- expect(getNameValidation(component)).toEqual('');
+ expect(getNameValidation(component)).toEqual(null);
setVmName(component, getName(vm2));
expect(getNameValidation(component)).toEqual(`Name ${VIRTUAL_MACHINE_EXISTS}`);
setVmName(component, 'othername');
- expect(getNameValidation(component)).toEqual('');
+ expect(getNameValidation(component)).toEqual(null);
});
it('calls clone when clicked on finish', async () => {
diff --git a/src/components/Form/Checkbox.js b/src/components/Form/Checkbox.js
index ae9ae0dfb..a12e0bbd1 100644
--- a/src/components/Form/Checkbox.js
+++ b/src/components/Form/Checkbox.js
@@ -4,12 +4,13 @@ import { Checkbox as PfCheckbox, noop } from 'patternfly-react';
import { checkboxHandler } from './utils';
-export const Checkbox = ({ id, title, disabled, checked, onChange, onBlur }) => (
+export const Checkbox = ({ id, title, disabled, checked, onChange, onBlur, className }) => (
{title}
@@ -21,6 +22,7 @@ Checkbox.defaultProps = {
checked: false,
onChange: noop,
onBlur: noop,
+ className: undefined,
disabled: false,
};
@@ -30,5 +32,6 @@ Checkbox.propTypes = {
checked: PropTypes.bool,
onChange: PropTypes.func,
onBlur: PropTypes.func,
+ className: PropTypes.string,
disabled: PropTypes.bool,
};
diff --git a/src/components/Form/Dropdown.js b/src/components/Form/Dropdown.js
index c7ab9a861..a5f9b6de1 100644
--- a/src/components/Form/Dropdown.js
+++ b/src/components/Form/Dropdown.js
@@ -1,15 +1,16 @@
import React from 'react';
import PropTypes from 'prop-types';
+import classNames from 'classnames';
import { ButtonGroup, DropdownButton, MenuItem, noop, Tooltip, OverlayTrigger } from 'patternfly-react';
-export const Dropdown = ({ id, value, disabled, onChange, choices, withTooltips }) => {
+export const Dropdown = ({ id, value, disabled, onChange, choices, className, withTooltips }) => {
const title = typeof value === 'object' ? value.name || value.id : value;
return (
{
value={isControlled ? value || '' : undefined}
defaultValue={isControlled ? undefined : defaultValue}
onBlur={onBlur}
- className={className}
onChange={onChange}
+ className={className}
disabled={disabled}
/>
);
@@ -54,6 +54,7 @@ export const getFormElement = props => {
checked={isControlled ? value || false : undefined}
onBlur={onBlur}
onChange={onChange}
+ className={className}
disabled={disabled}
/>
);
@@ -66,6 +67,7 @@ export const getFormElement = props => {
defaultValue={isControlled ? undefined : defaultValue}
onBlur={onBlur}
onChange={onChange}
+ className={className}
positive
disabled={disabled}
/>
@@ -78,7 +80,14 @@ export const getFormElement = props => {
);
case CUSTOM:
return (
-
+
);
case PASSWORD:
return (
@@ -90,6 +99,7 @@ export const getFormElement = props => {
onBlur={onBlur}
onChange={onChange}
disabled={disabled}
+ className={className}
type="password"
/>
);
@@ -102,6 +112,7 @@ export const getFormElement = props => {
defaultValue={isControlled ? undefined : defaultValue}
onBlur={onBlur}
onChange={onChange}
+ className={className}
disabled={disabled}
/>
);
@@ -167,17 +178,23 @@ const getFormGroups = ({ fields, fieldsValues, onFormChange, textPosition, label
const values = fieldsValues[key];
const validation = get(values, 'validation');
const value = get(values, 'value');
- const hasValidationMessage = !!get(validation, 'message');
+ const validationMessage = get(validation, 'message');
+ const hasValidationMessage = !!validationMessage;
+ const hasAddendum = !!field.addendum;
const child = getFormElement({
...field,
value,
isControlled: true,
onChange: newValue => onChange(fields, fieldsValues, newValue, key, onFormChange),
+ className: classNames(field.className, {
+ 'kubevirt-form-group__field--with-addendum': hasAddendum,
+ }),
});
- const label = horizontal &&
- field.title && (
+ let label;
+ if (horizontal && field.title) {
+ label = (
{field.type !== 'checkbox' && (
@@ -189,6 +206,7 @@ const getFormGroups = ({ fields, fieldsValues, onFormChange, textPosition, label
)}
);
+ }
return (
{child}
- {get(validation, 'message')}
+ {hasAddendum && {field.addendum}}
+ {hasValidationMessage && {validationMessage}}
);
diff --git a/src/components/Form/Integer.js b/src/components/Form/Integer.js
index 6a08931b0..ce81c6fc1 100644
--- a/src/components/Form/Integer.js
+++ b/src/components/Form/Integer.js
@@ -56,7 +56,7 @@ const isInputValid = (allowedKeys, keyCode, targetValue, additionalValidation) =
return false;
};
-export const Integer = ({ id, value, disabled, defaultValue, onChange, onBlur, positive, nonNegative }) => {
+export const Integer = ({ id, value, disabled, defaultValue, onChange, onBlur, positive, nonNegative, className }) => {
let allowedKeys;
let validRegex;
let fixAfterValue;
@@ -116,6 +116,7 @@ export const Integer = ({ id, value, disabled, defaultValue, onChange, onBlur, p
defaultValue={defaultValue}
onBlur={eventValueHandler(onBlur)}
onChange={eventValueHandler(onChange)}
+ className={className}
disabled={disabled}
/>
);
@@ -128,6 +129,7 @@ Integer.defaultProps = {
onBlur: noop,
positive: false,
nonNegative: false, // is ignored when positive == true
+ className: undefined,
disabled: false,
};
@@ -139,5 +141,6 @@ Integer.propTypes = {
onBlur: PropTypes.func,
positive: PropTypes.bool,
nonNegative: PropTypes.bool,
+ className: PropTypes.string,
disabled: PropTypes.bool,
};
diff --git a/src/components/Form/Text.js b/src/components/Form/Text.js
index 7fe7e8d59..f7fb6917e 100644
--- a/src/components/Form/Text.js
+++ b/src/components/Form/Text.js
@@ -4,7 +4,7 @@ import { FormControl, noop } from 'patternfly-react';
import { eventValueHandler } from './utils';
-export const Text = ({ id, value, disabled, defaultValue, onChange, onBlur, type }) => (
+export const Text = ({ id, value, disabled, defaultValue, onChange, onBlur, type, className }) => (
);
@@ -23,6 +24,7 @@ Text.defaultProps = {
onChange: noop,
onBlur: noop,
disabled: false,
+ className: undefined,
type: 'text', // or password
};
@@ -32,6 +34,7 @@ Text.propTypes = {
defaultValue: PropTypes.string,
onChange: PropTypes.func,
onBlur: PropTypes.func,
+ className: PropTypes.string,
disabled: PropTypes.bool,
type: PropTypes.string,
};
diff --git a/src/components/Form/tests/__snapshots__/FormFactory.test.js.snap b/src/components/Form/tests/__snapshots__/FormFactory.test.js.snap
index d3bfb50ba..6ed504a12 100644
--- a/src/components/Form/tests/__snapshots__/FormFactory.test.js.snap
+++ b/src/components/Form/tests/__snapshots__/FormFactory.test.js.snap
@@ -172,6 +172,7 @@ exports[` renders correctly 1`] = `
className="col-sm-5"
>
renders correctly 1`] = `
>
renders correctly 1`] = `
/>
-
-
-
@@ -253,6 +248,7 @@ exports[` renders correctly 1`] = `
className="col-sm-5"
>
renders correctly 1`] = `
>
renders correctly 1`] = `
/>
-
-
-
@@ -334,6 +324,7 @@ exports[` renders correctly 1`] = `
className="col-sm-5"
>
renders correctly 1`] = `
>
renders correctly 1`] = `
/>
-
-
-
@@ -634,13 +619,6 @@ exports[` renders correctly 1`] = `
-
-
-
@@ -663,6 +641,7 @@ exports[` renders correctly 1`] = `
className="col-sm-5"
>
renders correctly 1`] = `
>
renders correctly 1`] = `
/>
-
-
-
@@ -729,6 +702,7 @@ exports[` renders correctly 1`] = `
>
renders correctly 1`] = `
renders correctly 1`] = `
-
-
-
@@ -816,15 +784,9 @@ exports[` renders correctly 1`] = `
className="col-sm-5"
>
-
-
-
diff --git a/src/components/Wizard/CreateVmWizard/strings.js b/src/components/Wizard/CreateVmWizard/strings.js
index e8d5e0359..36d6bbf00 100644
--- a/src/components/Wizard/CreateVmWizard/strings.js
+++ b/src/components/Wizard/CreateVmWizard/strings.js
@@ -45,7 +45,7 @@ export const ERROR_NO_STORAGE_CLASS_SELECTED = 'Storage Class not selected';
export const ERROR_NO_STORAGE_SELECTED = 'No storage is selected';
export const ERROR_STORAGE_NOT_VALID = 'Selected storage is not valid';
export const ERROR_DISK_NOT_FOUND = 'Disk configuration not found';
-export const HEADER_SIZE = 'Size (GB)';
+export const HEADER_SIZE = 'Size (Gi)';
export const HEADER_STORAGE_CLASS = 'Storage Class';
export const REMOVE_DISK_BUTTON = 'Remove Disk';
export const ATTACH_DISK_BUTTON = 'Attach Disk';
diff --git a/src/components/Wizard/CreateVmWizard/tests/NetworksTab.test.js b/src/components/Wizard/CreateVmWizard/tests/NetworksTab.test.js
index 9336414e6..26debca12 100644
--- a/src/components/Wizard/CreateVmWizard/tests/NetworksTab.test.js
+++ b/src/components/Wizard/CreateVmWizard/tests/NetworksTab.test.js
@@ -168,7 +168,7 @@ describe('', () => {
.find(Dropdown)
.props().value
).toEqual('pxe-net');
- expect(component.find(HelpBlock).text()).toEqual('');
+ expect(component.find(HelpBlock)).toHaveLength(0);
// add Pod network - not PXE bootable
component.instance().rowsChanged([podRow], false);
@@ -196,7 +196,7 @@ describe('', () => {
.find(Dropdown)
.props().value
).toEqual('pxe-net');
- expect(component.find(HelpBlock).text()).toEqual('');
+ expect(component.find(HelpBlock)).toHaveLength(0);
});
it('does not require bootable network for non-PXE image sources', () => {
diff --git a/src/components/Wizard/CreateVmWizard/tests/__snapshots__/StorageTab.test.js.snap b/src/components/Wizard/CreateVmWizard/tests/__snapshots__/StorageTab.test.js.snap
index 81b47c31e..bcf6cc800 100644
--- a/src/components/Wizard/CreateVmWizard/tests/__snapshots__/StorageTab.test.js.snap
+++ b/src/components/Wizard/CreateVmWizard/tests/__snapshots__/StorageTab.test.js.snap
@@ -37,7 +37,7 @@ exports[` renders correctly 1`] = `
},
Object {
"header": Object {
- "label": "Size (GB)",
+ "label": "Size (Gi)",
"props": Object {
"style": Object {
"width": "23%",