-
Notifications
You must be signed in to change notification settings - Fork 30
[WIP] Implement Create VM Wizard component #4
Conversation
thanks! do you mind publishing the storybook? |
@ohadlevy where should I publish it ? github pages of my forked repo ? |
Seems to be best option. It will stay close to each PR. |
@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. |
1d5ea60
to
d261857
Compare
yeah, best is to use rawgit (so you can push multiple branches), have a
look at pf-react for the npm task (i think its storybook-deployer)
…On Tue, Aug 28, 2018 at 3:45 PM rawagner ***@***.***> wrote:
@mareklibra <https://github.com/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.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<kubevirt/web-ui#4 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/AABOxzGMxoQzKzA0vAGmMtRi6NSCsK6iks5uVTtpgaJpZM4WPdLt>
.
|
@ohadlevy thanks! Storybook is published at https://rawgit.com/rawagner/web-ui/create_VM_wizard_storybook/index.html |
do we have a group of UX developers so we can ping them to look at the
stroybook?
…On Tue, Aug 28, 2018 at 4:20 PM rawagner ***@***.***> wrote:
@ohadlevy <https://github.com/ohadlevy> thanks! Storybook is published at
https://rawgit.com/rawagner/web-ui/create_VM_wizard_storybook/index.html
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<kubevirt/web-ui#4 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/AABOxxXHlcl98q7JaNPcoaGnKFzS32THks5uVUOUgaJpZM4WPdLt>
.
|
@@ -0,0 +1,358 @@ | |||
import React from 'react'; |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@vojtechszocs @mareklibra any preference ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I prefer just .js
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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 😃
There was a problem hiding this comment.
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; | ||
} |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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}); |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please take some inspiration from
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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' |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
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') { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please consider using switch
There was a problem hiding this comment.
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; |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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>; |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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}> |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- applies also elsewhere
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done, hopefully everywhere
There was a problem hiding this comment.
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) => { |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
There was a problem hiding this 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 { |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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'; |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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){ |
There was a problem hiding this comment.
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
?
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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
.
There was a problem hiding this comment.
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; |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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(); |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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} |
There was a problem hiding this comment.
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} |
There was a problem hiding this comment.
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
.
There was a problem hiding this comment.
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'} />; |
There was a problem hiding this comment.
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 = { |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
3d5a0ab
to
45b6e0e
Compare
type: 'checkbox' | ||
}, | ||
createTemplate:{ | ||
title: 'Create new teplate from configuration', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo on 'template'
There was a problem hiding this comment.
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} |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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}> |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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 .
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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:{ |
There was a problem hiding this comment.
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
src/utils/forms/FormFactory.js
Outdated
</Col> | ||
</FormGroup>); | ||
}) | ||
} |
There was a problem hiding this comment.
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 ..
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
src/utils/forms/FormFactory.js
Outdated
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; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
just return;
is enough
There was a problem hiding this comment.
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.
src/k8s/request.js
Outdated
if(basicSettings.description){ | ||
vm.metadata.labels.description = basicSettings.description; | ||
} | ||
addFlavor(vm, basicSettings); |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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 :)
src/constants/index.js
Outdated
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' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
\n
</React.Fragment> | ||
); | ||
} | ||
} |
There was a problem hiding this comment.
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 ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we should, 👍
There was a problem hiding this comment.
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'; |
There was a problem hiding this comment.
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'
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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 = { |
There was a problem hiding this comment.
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 = { ... }
There was a problem hiding this comment.
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`; |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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; |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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}> |
There was a problem hiding this comment.
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"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
use Col component ?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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" /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
use Icon component?
There was a problem hiding this comment.
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> | ||
); | ||
} | ||
} |
There was a problem hiding this comment.
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 = [ |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sounds good, TODO
Agreed with others, this is looking great! A few overall comments:
|
note its used below, so I guess it should be used consistently.
…On Wed, Aug 29, 2018 at 5:26 PM suomiy ***@***.***> wrote:
***@***.**** commented on this pull request.
------------------------------
In src/components/wizards/new-vm/NewVmWizard.js
<kubevirt/web-ui#4 (comment)>:
> + render() {
+ let wizard;
+ if(this.state.createVM) {
+ wizard = <CreateVmWizard onHide={this.props.closeWizard} {...this.props}/>
+ } else if(this.state.importVM) {
+ wizard = <ImportVmWizard onHide={this.props.closeWizard} {...this.props}/>
+ }
+ return (
+ <React.Fragment>
+ <Wizard show onHide={this.props.closeWizard}>
+ <Wizard.Header title="Create Virtual Machine" onClose={this.props.closeWizard} />
+ <Wizard.Body>
+ <Wizard.Row>
+ <Wizard.Main>
+ <Wizard.Contents stepIndex={0} activeStepIndex={0} className="wizard-content">
+ <button className="btn btn-link wizard-button " onClick={this.openCreateVmWizard}>
there is, but I don't think it is needed so much. I just meant lines 33-40
altogether .
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<kubevirt/web-ui#4 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/AABOx-mnjdsstQsqWmXvrQtq6FF-8W9kks5uVqSTgaJpZM4WPdLt>
.
|
there is, but i still think its a better practice to get used to instead of
importing all of it.
…On Wed, Aug 29, 2018 at 5:36 PM Vojtech Szocs ***@***.***> wrote:
***@***.**** commented on this pull request.
------------------------------
In src/components/wizards/create-vm/CreateVmWizard.js
<kubevirt/web-ui#4 (comment)>:
> @@ -0,0 +1,228 @@
+import React from 'react';
+import {
+ Form,
+ Wizard
+} from 'patternfly-react';
+import './CreateVmWizard.css';
+import * as _ from 'lodash';
IIRC there are webpack plugins to address these kinds of optimization
issues, I will look into that later on.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<kubevirt/web-ui#4 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/AABOx-279HZf9SAL-aDEoAqzy9O93KVaks5uVqbygaJpZM4WPdLt>
.
|
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. |
not before tectonic migration please..
…On Wed, Aug 29, 2018 at 5:49 PM Vojtech Szocs ***@***.***> wrote:
***@***.**** commented on this pull request.
------------------------------
In src/components/wizards/new-vm/NewVmWizard.js
<kubevirt/web-ui#4 (comment)>:
> + let wizard;
+ if(this.state.createVM) {
+ wizard = <CreateVmWizard onHide={this.props.closeWizard} {...this.props}/>
+ } else if(this.state.importVM) {
+ wizard = <ImportVmWizard onHide={this.props.closeWizard} {...this.props}/>
+ }
+ return (
+ <React.Fragment>
+ <Wizard show onHide={this.props.closeWizard}>
+ <Wizard.Header title="Create Virtual Machine" onClose={this.props.closeWizard} />
+ <Wizard.Body>
+ <Wizard.Row>
+ <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">
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.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<kubevirt/web-ui#4 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/AABOxx4KVaujoCKgD17iLtJPqgxAdX1iks5uVqnlgaJpZM4WPdLt>
.
|
45b6e0e
to
cfb352b
Compare
No problem, I saw it in earlier version of Create VM design. It is now removed, less work for me :)
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..
I will, TODO |
cfb352b
to
38e09a0
Compare
d47120c
to
bb07399
Compare
Added some enzyme tests. @ohadlevy any suggestions on what should we use for code coverage metrics ? |
bb07399
to
959ac45
Compare
Pull Request Test Coverage Report for Build 40
💛 - Coveralls |
src/components/forms/FormControls.js
Outdated
onChange: PropTypes.func.isRequired | ||
}; | ||
|
||
export const DropdownControl = ({ fieldKey, value, choices, onChange }) => ( |
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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.
a7e08a8
to
a8ce6a8
Compare
import { DropdownControl } from './DropdownControl'; | ||
import { CheckboxControl } from './CheckboxControl'; | ||
|
||
export { TextAreaControl, TextControl, DropdownControl, CheckboxControl }; |
There was a problem hiding this comment.
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'; |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
2fb0ba4
to
190a137
Compare
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" |
There was a problem hiding this comment.
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?
190a137
to
8256c38
Compare
@rawagner thanks, it looks like there is a snapshot out of date + css linting errors in the tests. |
8256c38
to
fbf1b30
Compare
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). |
fbf1b30
to
527939a
Compare
Pull Request Test Coverage Report for Build 74
💛 - Coveralls |
deprecated by #27 |
storybook is published here https://rawgit.com/rawagner/web-ui/create_VM_wizard_storybook/index.html