Skip to content
This repository has been archived by the owner on Apr 28, 2020. It is now read-only.

[WIP] Implement Create VM Wizard component #4

Closed
wants to merge 1 commit into from

Conversation

rawagner
Copy link
Contributor

@rawagner rawagner commented Aug 28, 2018

@ohadlevy
Copy link
Contributor

thanks! do you mind publishing the storybook?

@rawagner
Copy link
Contributor Author

@ohadlevy where should I publish it ? github pages of my forked repo ?

@mareklibra
Copy link
Contributor

github pages of my forked repo

Seems to be best option. It will stay close to each PR.
And we can maintain storybook for master.

@rawagner
Copy link
Contributor Author

@mareklibra OK, I will go with the github pages. Just be aware that github pages is using gh-pages or master branch. Which means you can have only one github page for repository. It will work for now, as I have only one PR but if I will have more open PRs I wont be able to host storybook for each of them.

@ohadlevy
Copy link
Contributor

ohadlevy commented Aug 28, 2018 via email

@rawagner
Copy link
Contributor Author

@ohadlevy
Copy link
Contributor

ohadlevy commented Aug 28, 2018 via email

@rawagner
Copy link
Contributor Author

@lizsurette

@@ -0,0 +1,358 @@
import React from 'react';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

are we using a convention adding .jsx extension to files with jsx or using .js extensions everywhere?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vojtechszocs @mareklibra any preference ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer just .js

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also prefer just .js for both React components and other JS code.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's simply because the presence of JSX expressions doesn't make the particular file special, JSX is transformed into JS anyway 😃

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 for just .js


.wizard-dropdown .caret {
float: right;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

missing newline + other files as well

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added newline to all files

]

openWizard = () => {
this.setState({show: true});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NewVMWizard has to call this to change its own inner behaviour which is too complicated IMO. I would simply render or not render the component if it is openned or not. I think it is just enough to pass onClose callback to the NewVMWizard component which we can call from CreateVMWizard/ImportVMWizard. Then it is possible to simplify the code in NewVMWizard a bit.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess what bothers me the most that there are 3 possible wizzards in the component and the prop callbacks are tangled to the component. Is it possible to make it somehow simpler?

I guess we could make the component lifecycle dependent only on the props or make it standalone.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed it to what @suomiy suggested. Just render or not render at all. Is is the preferred way ?

export const os = [
{
name: 'Alpine Linux 3.5',
value: 'alpinelinux3.5'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe rename value to id?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

renamed to id.

}

closeWizard = () => {
this.setState(defaultState);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there will not be a need for this if we use the no component approach discussed in NewVMWizard.stories.js + you can return the defaultState to constructor

}
let child = null;
const valid = _.get(this.state.basicSettings[key], 'valid', null);
if (this.basicSettings[key].type === 'text') {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please consider using switch

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

render: () => <Form horizontal>
{Object.keys(this.basicSettings).map(key => {
if (this.basicSettings[key].isVisible && this.basicSettings[key].isVisible(this.state.basicSettings) === false){
return null;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can be undefined,
let child; also

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

</ButtonGroup>;
}
if (this.basicSettings[key].type === 'checkbox') {
child = <Checkbox checked={_.get(this.state.basicSettings[key], 'value', false)} onChange={event => this.onFormChange(event.target.checked, key)}>{this.basicSettings[key].title}</Checkbox>;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please put props on new lines for better readability

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

if (this.basicSettings[key].type === 'checkbox') {
child = <Checkbox checked={_.get(this.state.basicSettings[key], 'value', false)} onChange={event => this.onFormChange(event.target.checked, key)}>{this.basicSettings[key].title}</Checkbox>;
}
return <FormGroup key={key} validationState={valid ? 'error' : null}>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please use brackets () and put FormGroup on the newline. IMO it is more readable because of the same spacing

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • applies also elsewhere

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done, hopefully everywhere

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this is also the syntax form preferred by patternfly-react project.

}
]

createVM = (basicSettings, network, storage) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would rather see this in another file and give it a data in stable format. Maybe some file like requests.js ? Then it would create final data structure vm.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, I moved it to k8s/request.js

Copy link
Contributor

@vojtechszocs vojtechszocs left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks OK in general.

Code style should be close to patternfly-react.

Components should be isolated in terms of CSS if we really care about true reusability (i.e. use CSS modules). We can improve that later on.

@@ -0,0 +1,7 @@
.wizard-dropdown {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd suggest to follow CamelCase convention like CreateVmWizard.css etc.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, I'd suggest using code style with 2 spaces used for indentation, both in CSS and JS.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@@ -0,0 +1,366 @@
import React from 'react';
import { Form, FormControl, Col, ButtonGroup, DropdownButton, MenuItem, Checkbox, FormGroup, ControlLabel, HelpBlock, Wizard } from 'patternfly-react';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In future, very long imports (past X chars) should be written as

import {
  a,
  b,
  c
} from 'foo'

just like in other projects.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done


onFormChange = (newValue, target) => {
let valid = null;
if (this.basicSettings[target].required && newValue.trim().length === 0){
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are using this.basicSettings because we don't need component re-render when it changes, right?

What's the intended relation between this.basicSettings and this.state.basicSettings ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this.basicSettings represents fields of form (type, label, validation). this.state.basicSettings represents actual values that are changing based on user input (value, validation message). Maybe I should rename one of them to avoid confusion

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see, I'd rename them to better reflect their purpose, i.e. this.basicStepFields and this.state.basicStepValues or similar.

I'd use the word "step" since it's the grouping concept that puts multiple form fields together, from visual/user perspective.

...this.state.basicSettings,
[target]: {
value: newValue,
valid: valid
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can use ES6 object property shorthand syntax - valid instead of valid: valid.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

}

onFormChange = (newValue, target) => {
let valid = null;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To avoid confusion with wizardValid being a boolean, can we call this validMsg or similar?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

renamed to validMsg


closeWizard = () => {
this.setState(defaultState);
this.props.closeWizard();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If closeWizard is meant to be a callback prop, please call it onClose instead.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, patternfly-react Wizard already provides onExited callback prop that executes when the modal finishes its fade-out transition, I'd suggest using that instead.

show={this.props.show}
onHide={this.closeWizard}
onClose={this.closeWizard}
steps={this.wizardStepsNewVM}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

steps is where the vast majority of wizard UI & logic lives.

I think that in future, we should find a better representation, I recall talking with patternfly-react folks about allowing steps to be represented as React components, instead of plain JS array.

render() {
return <Wizard.Pattern
show={this.props.show}
onHide={this.closeWizard}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wizard's onClose is triggered when you click the "X" button in top right corner. WizardPattern implements it for us, but doesn't expose it as a prop, so onClose should be removed here.

As for onHide, this is a function that WizardPattern calls like so:

onHide(onFinalStep) // true or false, whether we are on the final step

TL;DR I'd just keep the onHide and remove onClose.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

onClose removed

activeStepIndex={this.state.activeStepIndex}
onStepChanged={index => this.onStepChanged(index)}
nextStepDisabled={!this.state.wizardValid}
nextText={this.state.activeStepIndex === 2 ? 'Create Virtual Machine':'Next'} />;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As for JSX expressions, please use one of these forms (in-line with patternfly-react):

<Example foo={bar} />

// lots of props
<Example
  foo={bar}
/>

<Example foo={bar}>
  <AnotherExample />
</Example>

// lots of props
<Example
  foo={bar}
>
  <AnotherExample />
</Example>


export class StorageTable extends React.Component {

state = {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can use this form in CreateVmWizard component too.

Let's be consistent with how we initialize component's state, using ES6 class fields sounds good to me.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, class fields it is.

@rawagner rawagner force-pushed the create_VM_wizard branch 8 times, most recently from 3d5a0ab to 45b6e0e Compare August 29, 2018 12:16
type: 'checkbox'
},
createTemplate:{
title: 'Create new teplate from configuration',

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo on 'template'

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

<React.Fragment>
<Button onClick={this.openWizard}>Open New VM Wizard</Button>
{this.state.show ? <NewVmWizard
closeWizard={this.closeWizard}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think onClose would be more fitting

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, in React world, onSomething is a standard convention for callback props.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

renamed to onHide

<Wizard.Row>
<Wizard.Main>
<Wizard.Contents stepIndex={0} activeStepIndex={0} className="wizard-content">
<button className="btn btn-link wizard-button " onClick={this.openCreateVmWizard}>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could make a component out of this

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there is a pf-react Button Component?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there is, but I don't think it is needed so much. I just meant lines 33-40 altogether .

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will use Button from pf-react and also extract the whole 'button with icon and label' to separate component

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, let's reuse patternfly-react's Button if possible.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved to separate component ButtonWithIcon which is using Button, Icon and Col pf-react components

values: this.props.flavors.concat([{name:'Custom'}]),
required: true
},
memory:{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please better validation for memory/cpu/URL

</Col>
</FormGroup>);
})
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

newline - better to setup an IDE to do it for you ..

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

export const FormFactory = (props) => {
return Object.keys(props.fields).map(key => {
if (props.fields[key].isVisible && props.fields[key].isVisible(props.fieldsValues) === false){
return undefined;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just return; is enough

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this results in eslint warning. Anyways I avoided it by filtering the fields which are not visible and than map only the visible fields.

if(basicSettings.description){
vm.metadata.labels.description = basicSettings.description;
}
addFlavor(vm, basicSettings);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think few newlines here and there add to the readability, but that is just my opinion.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added a few new lines here and there :)

export const API_VERSION='kubevirt.io/v1alpha2'
export const VM_KIND='VirtualMachine'
export const OS_LABEL='kubevirt.io/os'
export const FLAVOR_LABEL='kubevirt.io/flavor'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

\n

</React.Fragment>
);
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we using React Proptypes in this project or not ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should, 👍

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Of course we should use them 😃 maybe not right now, since we're prototyping our first complex wizard component, but we should use them at some point.

Wizard
} from 'patternfly-react';
import './CreateVmWizard.css';
import * as _ from 'lodash';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please don't import the entire lodash, instead do:

import get from 'lodash/get'

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IIRC there are webpack plugins to address these kinds of optimization issues, I will look into that later on.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changed all import * as _ from 'lodash to more precise ones (get/has etc)


export class CreateVmWizard extends React.Component {

state = {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should this be:

const state = { ... }

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no, it should not. It is a class property which is not 'prefixed' with const

onFormChange = (newValue, target) => {
let validMsg = null;
if (this.formFields[target].required && newValue.trim().length === 0){
validMsg = `${this.formFields[target].title} is required`;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is not i18n friendly, @vojtechszocs add to the list of project infra?

overall, i feel this should probably live outside of the component in some i18n or forms related code?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is not i18n friendly, @vojtechszocs add to the list of project infra?

Added that to the list of infra tasks.

We should use the standard ICU message format. In ovirt-engine-ui-extensions project, we're using intl-messageformat - every localized message is a function that accepts zero or more parameters, returning a localized string.

overall, i feel this should probably live outside of the component in some i18n or forms related code?

Yes, i18n is another concern and should be put into its dedicated module.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will wait for infra updates then

const requiredKeys = Object.keys(this.formFields).filter(key => this.isFieldRequired(key, values));
const requiredKeysInValues = Object.keys(values).filter(key => this.isFieldRequired(key, values));
if(requiredKeys.length !== requiredKeysInValues.length){
wizardValid = false;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i wonder if using something like finaly-form or formik would save us some effort here.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @ohadlevy for the links!

finaly-form is React agnostic, implements observer pattern to subscribe to form/field changes and allows their updates.

formik is React specific, and from quickly looking at their examples, is geared towards HTML <form> handling, i.e. the case when you use DOM form/field elements directly.

<Wizard.Row>
<Wizard.Main>
<Wizard.Contents stepIndex={0} activeStepIndex={0} className="wizard-content">
<button className="btn btn-link wizard-button " onClick={this.openCreateVmWizard}>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there is a pf-react Button Component?

<Wizard.Main>
<Wizard.Contents stepIndex={0} activeStepIndex={0} className="wizard-content">
<button className="btn btn-link wizard-button " onClick={this.openCreateVmWizard}>
<div className="col-md-12">
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use Col component ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup, we should use patternfly-react's Grid, Row and Col components instead of plain HTML/CSS markup.

Also, at some point, we'll transition to patternfly-react v4 which will implement its own grid system.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pf-react Button, Col and Icon used instead

<Wizard.Contents stepIndex={0} activeStepIndex={0} className="wizard-content">
<button className="btn btn-link wizard-button " onClick={this.openCreateVmWizard}>
<div className="col-md-12">
<span className="pficon-virtual-machine fa-5x" />
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use Icon component?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vojtechszocs @mareklibra do you think it is better to use components or simple classes ?

</React.Fragment>
);
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should, 👍

show: false
}

storageClasses = [
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe move to a fixture files? could be reused in tests?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sounds good, TODO

@lizsurette
Copy link

@rawagner

Agreed with others, this is looking great! A few overall comments:

  • When the user selects a provision source, what do you think about removing the indentation for any fields that are added? I think it will read better if they are inline. (Similar to how the fields show when the Enable cloud-init box is checked.

  • Would it be possible to split the OS field into Operating System and Version? I got some feedback that this list could get super long if we leave it as one. Of course this would mean that depending on which OS is selected, the versions would need to be updated.

  • Although it might be annoying to need two different styles, could we tighten up the padding between the check box options at the bottom of the Basic Settings steps? Maybe just allow them to live within one form-group if possible?

@ohadlevy
Copy link
Contributor

ohadlevy commented Aug 29, 2018 via email

@ohadlevy
Copy link
Contributor

ohadlevy commented Aug 29, 2018 via email

@atiratree
Copy link
Contributor

Would it be possible to split the OS field into Operating System and Version? I got some feedback that this list could get super long if we leave it as one. Of course this would mean that depending on which OS is selected, the versions would need to be updated.

It makes sense, but I would leave it until we know that we get this kind of information from the API - which will be preset os labels.

@ohadlevy
Copy link
Contributor

ohadlevy commented Aug 29, 2018 via email

@rawagner
Copy link
Contributor Author

@lizsurette

When the user selects a provision source, what do you think about removing the indentation for any fields that are added? I think it will read better if they are inline. (Similar to how the fields show when the Enable cloud-init box is checked.

No problem, I saw it in earlier version of Create VM design. It is now removed, less work for me :)

Would it be possible to split the OS field into Operating System and Version? I got some feedback that this list could get super long if we leave it as one. Of course this would mean that depending on which OS is selected, the versions would need to be updated.

as @suomiy said, lets wait for API updates, we will change it then. I agree that if we should list all possible values into one dropdrown, it would be a huge one..

Although it might be annoying to need two different styles, could we tighten up the padding between the check box options at the bottom of the Basic Settings steps? Maybe just allow them to live within one form-group if possible?

I will, TODO

@rawagner
Copy link
Contributor Author

rawagner commented Sep 4, 2018

Added some enzyme tests.

@ohadlevy any suggestions on what should we use for code coverage metrics ?

@ohadlevy
Copy link
Contributor

ohadlevy commented Sep 4, 2018

@coveralls
Copy link

coveralls commented Sep 4, 2018

Pull Request Test Coverage Report for Build 40

  • 146 of 161 (90.68%) changed or added relevant lines in 15 files are covered.
  • No unchanged relevant lines lost coverage.
  • Overall coverage increased (+67.8%) to 85.95%

Changes Missing Coverage Covered Lines Changed/Added Lines %
src/components/buttons/ButtonWithIcon.js 2 3 66.67%
src/components/forms/Dropdown.js 4 5 80.0%
src/k8s/request.js 54 57 94.74%
src/components/wizards/import-vm/ImportVmWizard.js 1 5 20.0%
src/components/wizards/create-vm/CreateVmWizard.js 32 38 84.21%
Totals Coverage Status
Change from base Build 37: 67.8%
Covered Lines: 148
Relevant Lines: 168

💛 - Coveralls

onChange: PropTypes.func.isRequired
};

export const DropdownControl = ({ fieldKey, value, choices, onChange }) => (
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I personally prefer a component in a file, it makes it easier to find, maybe just change them to forms/textArea, forms/checkBox etc, would be trivial to find ?

@@ -0,0 +1,186 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've found that snapshots over 50 lines is usually ignored, if some of the internal snaps are already part of other snapshots maybe they could be avoided?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reduced to < 50 lines.NewVmWizard.test.js.snap still has 66 lines but I do not see a way to reduce it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've found that snapshots over 50 lines is usually ignored, if some of the internal snaps are already part of other snapshots maybe they could be avoided?

This is true for snapshots and other files too. If it looks big and complex, people are less inclined to review and maintain it, until it breaks the build or application itself.

This has already been discussed on patternfly-react project, see my comment on Enzyme & snapshot testing.

In particular:

as @dmiller9911 pointed out, snapshots shouldn't include fully-resolved HTML tree, otherwise you'll end up with big snapshots and it's hard to differentiate the actual component's HTML bits

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reduced to < 50 lines. NewVmWizard.test.js.snap still has 66 lines but I do not see a way to reduce it.

Snapshot of NewVmWizard component should include virtual DOM of the component itself. It should not include fully-resolved HTML tree.

@rawagner rawagner force-pushed the create_VM_wizard branch 4 times, most recently from a7e08a8 to a8ce6a8 Compare September 4, 2018 14:15
import { DropdownControl } from './DropdownControl';
import { CheckboxControl } from './CheckboxControl';

export { TextAreaControl, TextControl, DropdownControl, CheckboxControl };
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can also use the following syntax:

export { TextAreaControl } from './TextAreaControl';

validMsg = this.basicFormFields[target].validate(newValue);
}
if (this.basicFormFields[target].required && newValue.trim().length === 0) {
validMsg = 'is required';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if we should do something with the strings to make it easier later on to i18n.

Copy link
Contributor Author

@rawagner rawagner Sep 5, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe we could address that in followup patch ? :) Im not sure what solution for i18n we will want to use. It would be nice to keep aligned with openshift console but they do not have any i18n yet.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The openshift/console project (frontend part) currently doesn't seem to use any i18n mechanism, there are English strings hardcoded in their components.

I'd like to avoid adding complexity until we really need it. For now, I would focus on writing simple, reusable components (and break down bigger components into smaller bits for that matter) along with associated .test.js and .stories.js files.

@rawagner rawagner force-pushed the create_VM_wizard branch 4 times, most recently from 2fb0ba4 to 190a137 Compare September 6, 2018 07:41
@rawagner
Copy link
Contributor Author

rawagner commented Sep 6, 2018

Latest PR updates code coverage configuration to exclude *.stories.js files

package.json Outdated
@@ -79,7 +82,8 @@
"jest": {
"collectCoverage": true,
"collectCoverageFrom": [
"src/**/*.{js,jsx,mjs}"
"src/**/*.{js,jsx,mjs}",
"!src/**/*.stories.js"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 maybe we can just PR this right away?

@ohadlevy
Copy link
Contributor

ohadlevy commented Sep 6, 2018

@rawagner thanks, it looks like there is a snapshot out of date + css linting errors in the tests.

@vojtechszocs
Copy link
Contributor

I've got some infra changes coming up that will help formalize the project structure and conventions, including tools for validation and consistent usage of other tools (like using one Babel config for webpack, Jest and Storybook).

@atiratree
Copy link
Contributor

I refactored FormFactory.js, FormControls and CreateVmWizard.js in the followup. So if somebody notices something in there, we can discuss it in #10 :) and proceed with merging this PR.

@coveralls
Copy link

coveralls commented Sep 18, 2018

Pull Request Test Coverage Report for Build 74

  • 146 of 161 (90.68%) changed or added relevant lines in 15 files are covered.
  • No unchanged relevant lines lost coverage.
  • Overall coverage decreased (-10.8%) to 89.224%

Changes Missing Coverage Covered Lines Changed/Added Lines %
src/components/buttons/ButtonWithIcon.js 2 3 66.67%
src/components/forms/Dropdown.js 4 5 80.0%
src/k8s/request.js 54 57 94.74%
src/components/wizards/import-vm/ImportVmWizard.js 1 5 20.0%
src/components/wizards/create-vm/CreateVmWizard.js 32 38 84.21%
Totals Coverage Status
Change from base Build 72: -10.8%
Covered Lines: 147
Relevant Lines: 162

💛 - Coveralls

@rawagner
Copy link
Contributor Author

deprecated by #27

@rawagner rawagner closed this Sep 25, 2018
@rawagner rawagner deleted the create_VM_wizard branch September 27, 2018 13:40
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

7 participants