Skip to content
This repository was archived by the owner on Apr 28, 2020. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 33 additions & 20 deletions src/components/Table/EditableDraggableTable.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,21 @@ class EditableDraggableTable extends React.Component {
}
}

onRowDelete = rowData => {
const { id } = rowData;
const editing = false;
const rows = cloneDeep(this.props.rows.filter(row => row.id !== id));

this.flagUpdate(rows, editing);
this.setState({ editing });

this.props.onChange(rows, {
type: ON_DELETE,
editing,
id,
});
};

// needed for refiring row renders
// eslint-disable-next-line no-return-assign
flagUpdate = (rows, editingInProgress) => rows.forEach(row => (row.editingInProgress = editingInProgress));
Expand Down Expand Up @@ -81,6 +96,7 @@ class EditableDraggableTable extends React.Component {
const rows = cloneDeep(this.props.rows);
const index = findIndex(rows, { id });

delete rows[index].newRow;
delete rows[index].backup;

this.flagUpdate(rows, editing);
Expand All @@ -94,22 +110,26 @@ class EditableDraggableTable extends React.Component {
},

onCancel: ({ rowData }) => {
const editing = false;
const { id } = rowData;
const rows = cloneDeep(this.props.rows);
const index = findIndex(rows, { id });
const index = findIndex(this.props.rows, { id });

rows[index] = cloneDeep(rows[index].backup);
delete rows[index].backup;
if (this.props.rows[index].newRow) {
this.onRowDelete(rowData);
} else {
const editing = false;
const rows = cloneDeep(this.props.rows);
rows[index] = cloneDeep(rows[index].backup);
delete rows[index].backup;

this.flagUpdate(rows, editing);
this.setState({ editing });
this.flagUpdate(rows, editing);
this.setState({ editing });

this.props.onChange(rows, {
type: ON_CANCEL,
id,
editing,
});
this.props.onChange(rows, {
type: ON_CANCEL,
id,
editing,
});
}
},

onChange: (value, { rowData, property }) => {
Expand All @@ -131,14 +151,7 @@ class EditableDraggableTable extends React.Component {
};

crudController = {
onDelete: ({ rowData }) => {
const { id } = rowData;
this.props.onChange(this.props.rows.filter(row => row.id !== id), {
type: ON_DELETE,
editing: false,
id,
});
},
onDelete: ({ rowData }) => this.onRowDelete(rowData),
};

getActionButton = (action, additionalData, id) => {
Expand Down
2 changes: 1 addition & 1 deletion src/components/Table/TableFactory.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const onChange = (rows, { editing, type, id, key, newValue }, onRowUpdate, onRow
break;
case ON_DELETE:
case ON_MOVE:
onRowDeleteOrMove(rows);
onRowDeleteOrMove(rows, editing);
break;
default:
// eslint-disable-next-line
Expand Down
16 changes: 10 additions & 6 deletions src/components/Wizard/CreateVmWizard/CreateVmWizard.js
Original file line number Diff line number Diff line change
Expand Up @@ -116,12 +116,15 @@ export class CreateVmWizard extends React.Component {

lastStepReached = () => this.state.activeStepIndex === this.getLastStepIndex();

onStepDataChanged = (tabKey, value, valid) => {
onStepDataChanged = (tabKey, value, valid, lockStep = false) => {
const validatedTabData = validateTabData(tabKey, value, valid);
this.safeSetState(state => ({
stepData: {
...state.stepData,
[tabKey]: validatedTabData,
[tabKey]: {
...validatedTabData,
lockStep,
},
},
}));
};
Expand Down Expand Up @@ -220,7 +223,7 @@ export class CreateVmWizard extends React.Component {
<LoadingTab {...loadingData}>
<NetworksTab
key={NETWORKS_TAB_KEY}
onChange={(value, valid) => this.onStepDataChanged(NETWORKS_TAB_KEY, value, valid)}
onChange={(value, valid, lockStep) => this.onStepDataChanged(NETWORKS_TAB_KEY, value, valid, lockStep)}
networkConfigs={this.props.networkConfigs}
networks={this.state.stepData[NETWORKS_TAB_KEY].value || []}
sourceType={sourceType}
Expand All @@ -246,7 +249,7 @@ export class CreateVmWizard extends React.Component {
<StorageTab
key={STORAGE_TAB_KEY}
initialStorages={this.state.stepData[STORAGE_TAB_KEY].value}
onChange={(value, valid) => this.onStepDataChanged(STORAGE_TAB_KEY, value, valid)}
onChange={(value, valid, lockStep) => this.onStepDataChanged(STORAGE_TAB_KEY, value, valid, lockStep)}
units={this.props.units}
sourceType={sourceType}
namespace={getVmSettingValue(this.state, NAMESPACE_KEY)}
Expand Down Expand Up @@ -278,6 +281,7 @@ export class CreateVmWizard extends React.Component {
const lastStepReached = this.lastStepReached();

const createVmText = this.props.createTemplate ? CREATE_VM_TEMPLATE : CREATE_VM;
const currentStepData = this.state.stepData[this.wizardStepsNewVM[this.state.activeStepIndex].key];

return (
<Wizard.Pattern
Expand All @@ -286,10 +290,10 @@ export class CreateVmWizard extends React.Component {
steps={this.wizardStepsNewVM}
activeStepIndex={this.state.activeStepIndex}
onStepChanged={this.onStepChanged}
previousStepDisabled={lastStepReached}
previousStepDisabled={currentStepData.lockStep ? true : lastStepReached}
cancelButtonDisabled={lastStepReached}
stepButtonsDisabled={lastStepReached}
nextStepDisabled={!this.state.stepData[this.wizardStepsNewVM[this.state.activeStepIndex].key].valid}
nextStepDisabled={currentStepData.lockStep ? true : !currentStepData.valid}
nextText={beforeLastStepReached ? createVmText : NEXT}
title={createVmText}
dialogClassName="modal-lg wizard-pf kubevirt-wizard kubevirt-create-vm-wizard"
Expand Down
26 changes: 16 additions & 10 deletions src/components/Wizard/CreateVmWizard/NetworksTab.js
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ export class NetworksTab extends React.Component {
super(props);
const rows = resolveInitialNetworks(props.networks, props.networkConfigs, props.namespace, props.sourceType);

this.publishResults(rows);
this.publishResults(rows, false);
this.state = {
// eslint-disable-next-line
nextId: Math.max(...rows.map(network => network.id || 0), 0) + 1,
Expand All @@ -140,7 +140,7 @@ export class NetworksTab extends React.Component {
};
}

publishResults = rows => {
publishResults = (rows, editing) => {
let valid = this.props.sourceType === PROVISION_SOURCE_PXE ? rows.some(row => row.isBootable) : true;
const nics = rows.map(
({ templateNetwork, rootNetwork, id, isBootable, name, mac, network, errors, networkType, binding }) => {
Expand Down Expand Up @@ -172,11 +172,12 @@ export class NetworksTab extends React.Component {
}
);

this.props.onChange(nics, valid);
this.props.onChange(nics, valid, editing);
};

onRowActivate = rows => {
this.setState({ rows, editing: true });
this.publishResults(rows, true);
};

onRowUpdate = (rows, updatedRowId, editing, property, newValue) => {
Expand All @@ -199,14 +200,13 @@ export class NetworksTab extends React.Component {

rowsChanged = (rows, editing) => {
resolveBootableNetwork(this.props.sourceType, rows);
this.publishResults(rows);
this.publishResults(rows, editing);
this.setState({ rows, editing });
};

createNic = () => {
this.setState(state => ({
nextId: state.nextId + 1,
rows: [
this.setState(state => {
const rows = [
...state.rows,
{
id: state.nextId,
Expand All @@ -217,9 +217,15 @@ export class NetworksTab extends React.Component {
mac: '',
network: '',
binding: '',
newRow: true,
},
],
}));
];
this.publishResults(rows, true);
return {
nextId: state.nextId + 1,
rows,
};
});
};

getColumns = () => {
Expand Down Expand Up @@ -354,7 +360,7 @@ export class NetworksTab extends React.Component {
state.rows.forEach(row => {
row.isBootable = row.id === newValue.value.id;
});
this.publishResults(state.rows);
this.publishResults(state.rows, state.editing);
return state.rows;
});
};
Expand Down
28 changes: 18 additions & 10 deletions src/components/Wizard/CreateVmWizard/StorageTab.js
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,7 @@ const resolveInitialStorages = (
return storages;
};

const publishResults = (rows, otherStorages, sourceType, publish) => {
const publishResults = (rows, otherStorages, sourceType, publish, editing) => {
let valid = !needsBootableDisk(rows, sourceType);

const storages = rows.map(
Expand Down Expand Up @@ -295,7 +295,7 @@ const publishResults = (rows, otherStorages, sourceType, publish) => {
}
);
storages.push(...otherStorages);
publish(storages, valid);
publish(storages, valid, editing);
};

export class StorageTab extends React.Component {
Expand All @@ -320,14 +320,16 @@ export class StorageTab extends React.Component {
editing: false,
};

publishResults(this.state.rows, this.state.otherStorages, sourceType, onChange);
publishResults(this.state.rows, this.state.otherStorages, sourceType, onChange, false);
}

onRowActivate = rows => {
const { sourceType, onChange } = this.props;
this.setState({
rows,
editing: true,
});
publishResults(rows, this.state.otherStorages, sourceType, onChange, true);
};

onRowUpdate = (rows, updatedRowId, editing) => {
Expand All @@ -348,27 +350,33 @@ export class StorageTab extends React.Component {
rowsChanged = (rows, editing) => {
const { sourceType, onChange } = this.props;
resolveBootability(rows, sourceType);
publishResults(rows, this.state.otherStorages, sourceType, onChange);
publishResults(rows, this.state.otherStorages, sourceType, onChange, editing);
this.setState({
rows,
editing,
});
};

create = storageType => {
this.setState(state => ({
nextId: state.nextId + 1,
rows: [
this.setState(state => {
const { sourceType, onChange } = this.props;
const rows = [
...state.rows,
{
id: state.nextId,
isBootable: false,
editable: true,
edit: true, // trigger immediate edit
storageType,
newRow: true,
},
],
}));
];
publishResults(rows, state.otherStorages, sourceType, onChange, true);
return {
nextId: state.nextId + 1,
rows,
};
});
};

getColumns = () => [
Expand Down Expand Up @@ -513,7 +521,7 @@ export class StorageTab extends React.Component {
});

const { sourceType, onChange } = this.props;
publishResults(state.rows, state.otherStorages, sourceType, onChange);
publishResults(state.rows, state.otherStorages, sourceType, onChange, state.editing);
return state.rows;
});
};
Expand Down
20 changes: 20 additions & 0 deletions src/components/Wizard/CreateVmWizard/tests/CreateVmWizard.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,26 @@ describe('<CreateVmWizard />', () => {
expect(component.find(WizardPattern).props().nextStepDisabled).toBeTruthy();
});

it('disables back/next step when requested', () => {
const component = mount(testCreateVmWizard());

component.instance().onStepDataChanged(VM_SETTINGS_TAB_KEY, validVmSettings, true);
component.instance().onStepChanged(1);
component.update();
expect(component.state().activeStepIndex).toEqual(1);
component.instance().onStepDataChanged(NETWORKS_TAB_KEY, null, true, true);
expect(component.state().stepData[NETWORKS_TAB_KEY].lockStep).toBeTruthy();
component.update();
expect(component.find(WizardPattern).props().nextStepDisabled).toBeTruthy();
expect(component.find(WizardPattern).props().previousStepDisabled).toBeTruthy();

component.instance().onStepDataChanged(NETWORKS_TAB_KEY, null, true, false);
component.update();
expect(component.state().stepData[NETWORKS_TAB_KEY].lockStep).toBeFalsy();
expect(component.find(WizardPattern).props().nextStepDisabled).toBeFalsy();
expect(component.find(WizardPattern).props().previousStepDisabled).toBeFalsy();
});

it('creates vm', () => {
createVm.mockReturnValueOnce(new Promise((resolve, reject) => resolve([{ result: 'VM created' }])));
testWalkThrough();
Expand Down
20 changes: 14 additions & 6 deletions src/components/Wizard/CreateVmWizard/tests/NetworksTab.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,13 @@ describe('<NetworksTab />', () => {
expect(getTableRows(component)).toHaveLength(0);
expect(onChange).toHaveBeenCalledTimes(1);
expect(onChange.mock.calls[0][1]).toBeFalsy();
expect(onChange.mock.calls[0][2]).toBeFalsy();

getNetworkButton(component).simulate('click');
expect(onChange).toHaveBeenCalledTimes(3);
expect(onChange.mock.calls[1][1]).toBeFalsy();
expect(onChange.mock.calls[1][2]).toBeTruthy();

const rows = getTableRows(component);
expect(rows).toHaveLength(1);
const columns = rows.find('td');
Expand Down Expand Up @@ -158,8 +163,9 @@ describe('<NetworksTab />', () => {

// add PXE-bootable network
component.instance().rowsChanged([pxeRow], false);
expect(onChange).toHaveBeenCalledTimes(2);
expect(onChange.mock.calls[1][1]).toBeTruthy();
expect(onChange).toHaveBeenCalledTimes(4);
expect(onChange.mock.calls[3][1]).toBeTruthy();
expect(onChange.mock.calls[3][2]).toBeFalsy();
component.update();

expect(
Expand All @@ -172,8 +178,9 @@ describe('<NetworksTab />', () => {

// add Pod network - not PXE bootable
component.instance().rowsChanged([podRow], false);
expect(onChange).toHaveBeenCalledTimes(3);
expect(onChange.mock.calls[2][1]).toBeFalsy();
expect(onChange).toHaveBeenCalledTimes(5);
expect(onChange.mock.calls[4][1]).toBeFalsy();
expect(onChange.mock.calls[4][2]).toBeFalsy();
component.update();

expect(
Expand All @@ -186,8 +193,9 @@ describe('<NetworksTab />', () => {

// add Pod network and PXE-bootable network
component.instance().rowsChanged([podRow, pxeRow], false);
expect(onChange).toHaveBeenCalledTimes(4);
expect(onChange.mock.calls[3][1]).toBeTruthy();
expect(onChange).toHaveBeenCalledTimes(6);
expect(onChange.mock.calls[5][1]).toBeTruthy();
expect(onChange.mock.calls[5][2]).toBeFalsy();
component.update();

expect(
Expand Down
Loading