瀏覽代碼

Merge pull request #422 from smiclea/options-loading

Improve Wizard additional options loading UI
Dorin Paslaru 6 年之前
父節點
當前提交
501bbb52ae

+ 9 - 4
src/components/atoms/AutocompleteInput/AutocompleteInput.jsx

@@ -53,10 +53,12 @@ const Wrapper = styled.div`
   border-radius: ${StyleProps.borderRadius};
   border-radius: ${StyleProps.borderRadius};
   cursor: ${props => props.disabled ? 'default' : 'pointer'};
   cursor: ${props => props.disabled ? 'default' : 'pointer'};
   transition: all ${StyleProps.animations.swift};
   transition: all ${StyleProps.animations.swift};
-  background: ${props => props.disabled ? Palette.grayscale[0] : 'white'};
+  background: ${props => props.disabled && !props.embedded ? Palette.grayscale[0] : 'white'};
 
 
   #dropdown-arrow-image {stroke: ${props => props.disabled ? Palette.grayscale[3] : Palette.black};}
   #dropdown-arrow-image {stroke: ${props => props.disabled ? Palette.grayscale[3] : Palette.black};}
   ${props => props.focus ? css`border-color: ${Palette.primary};` : ''}
   ${props => props.focus ? css`border-color: ${Palette.primary};` : ''}
+  ${props => props.disabledLoading ? StyleProps.animations.disabledLoading : ''}
+
 `
 `
 const Arrow = styled.div`
 const Arrow = styled.div`
   position: absolute;
   position: absolute;
@@ -75,6 +77,7 @@ type Props = {
   onChange: (value: string) => void,
   onChange: (value: string) => void,
   onClick?: () => void,
   onClick?: () => void,
   disabled?: boolean,
   disabled?: boolean,
+  disabledLoading?: boolean,
   width?: number,
   width?: number,
   large?: boolean,
   large?: boolean,
   onFocus?: () => void,
   onFocus?: () => void,
@@ -90,13 +93,15 @@ class AutocompleteInput extends React.Component<Props, State> {
   }
   }
 
 
   render() {
   render() {
+    let disabled = this.props.disabled || this.props.disabledLoading
     return (
     return (
       <Wrapper
       <Wrapper
         large={this.props.large}
         large={this.props.large}
         width={this.props.width}
         width={this.props.width}
         focus={this.state.textInputFocus}
         focus={this.state.textInputFocus}
         highlight={this.props.highlight}
         highlight={this.props.highlight}
-        disabled={this.props.disabled}
+        disabled={disabled}
+        disabledLoading={this.props.disabledLoading}
         embedded={this.props.embedded}
         embedded={this.props.embedded}
         innerRef={e => {
         innerRef={e => {
           if (this.props.customRef) {
           if (this.props.customRef) {
@@ -108,7 +113,7 @@ class AutocompleteInput extends React.Component<Props, State> {
       >
       >
         <TextInput
         <TextInput
           data-test-id="acInput-text"
           data-test-id="acInput-text"
-          disabled={this.props.disabled}
+          disabled={disabled}
           value={this.props.value}
           value={this.props.value}
           onChange={e => { this.props.onChange(e.target.value) }}
           onChange={e => { this.props.onChange(e.target.value) }}
           embedded
           embedded
@@ -125,7 +130,7 @@ class AutocompleteInput extends React.Component<Props, State> {
         />
         />
         <Arrow
         <Arrow
           data-test-id="acInput-arrow"
           data-test-id="acInput-arrow"
-          disabled={this.props.disabled}
+          disabled={disabled}
           dangerouslySetInnerHTML={{ __html: arrowImage }}
           dangerouslySetInnerHTML={{ __html: arrowImage }}
           onClick={this.props.onClick}
           onClick={this.props.onClick}
         />
         />

+ 5 - 1
src/components/atoms/AutocompleteInput/story.jsx

@@ -21,7 +21,7 @@ import AutocompleteInput from '.'
 type State = {
 type State = {
   value: string,
   value: string,
 }
 }
-class Wrapper extends React.Component<{}, State> {
+class Wrapper extends React.Component<any, State> {
   state = {
   state = {
     value: '',
     value: '',
   }
   }
@@ -30,6 +30,7 @@ class Wrapper extends React.Component<{}, State> {
     return (
     return (
       <AutocompleteInput
       <AutocompleteInput
         large
         large
+        disabledLoading={this.props.disabledLoading}
         value={this.state.value}
         value={this.state.value}
         onChange={value => { this.setState({ value }) }}
         onChange={value => { this.setState({ value }) }}
       />
       />
@@ -41,3 +42,6 @@ storiesOf('AutocompleteInput', module)
   .add('default', () => (
   .add('default', () => (
     <Wrapper />
     <Wrapper />
   ))
   ))
+  .add('disabled loading', () => (
+    <Wrapper disabledLoading />
+  ))

+ 14 - 3
src/components/atoms/DropdownButton/DropdownButton.jsx

@@ -45,6 +45,10 @@ const Label = styled.div`
 `
 `
 
 
 const getBackgroundColor = props => {
 const getBackgroundColor = props => {
+  if (props.embedded) {
+    return 'white'
+  }
+
   if (props.disabled) {
   if (props.disabled) {
     return Palette.grayscale[0]
     return Palette.grayscale[0]
   }
   }
@@ -130,6 +134,7 @@ const Wrapper = styled.div`
   &:hover ${Label} {
   &:hover ${Label} {
     color: ${props => props.disabled ? '' : props.embedded ? '' : 'white'};
     color: ${props => props.disabled ? '' : props.embedded ? '' : 'white'};
   }
   }
+  ${props => props.disabledLoading ? StyleProps.animations.disabledLoading : ''}
 `
 `
 const Arrow = styled.div`
 const Arrow = styled.div`
   position: absolute;
   position: absolute;
@@ -149,6 +154,7 @@ type Props = {
   arrowRef?: (ref: HTMLElement) => void,
   arrowRef?: (ref: HTMLElement) => void,
   className?: string,
   className?: string,
   disabled?: boolean,
   disabled?: boolean,
+  disabledLoading?: boolean,
   'data-test-id'?: string,
   'data-test-id'?: string,
   embedded?: boolean,
   embedded?: boolean,
   highlight?: boolean,
   highlight?: boolean,
@@ -157,10 +163,13 @@ type Props = {
 }
 }
 class DropdownButton extends React.Component<Props> {
 class DropdownButton extends React.Component<Props> {
   render() {
   render() {
+    let disabled = this.props.disabled || this.props.disabledLoading
     return (
     return (
       <Wrapper
       <Wrapper
         data-test-id={this.props['data-test-id'] || 'dropdownButton'}
         data-test-id={this.props['data-test-id'] || 'dropdownButton'}
         {...this.props}
         {...this.props}
+        disabled={disabled}
+        disabledLoading={this.props.disabledLoading}
         innerRef={e => {
         innerRef={e => {
           if (this.props.customRef) {
           if (this.props.customRef) {
             this.props.customRef(e)
             this.props.customRef(e)
@@ -168,14 +177,16 @@ class DropdownButton extends React.Component<Props> {
             this.props.innerRef(e)
             this.props.innerRef(e)
           }
           }
         }}
         }}
-        onClick={e => { if (!this.props.disabled && this.props.onClick) this.props.onClick(e) }}
+        onClick={e => {
+          if (!disabled && this.props.onClick) this.props.onClick(e)
+        }}
       >
       >
         <Label
         <Label
           {...this.props}
           {...this.props}
           onClick={() => { }}
           onClick={() => { }}
           innerRef={() => { }}
           innerRef={() => { }}
           data-test-id="dropdownButton-value"
           data-test-id="dropdownButton-value"
-          disabled={this.props.disabled}
+          disabled={disabled}
         >
         >
           {this.props.value}
           {this.props.value}
         </Label>
         </Label>
@@ -184,7 +195,7 @@ class DropdownButton extends React.Component<Props> {
           innerRef={ref => { if (this.props.arrowRef) this.props.arrowRef(ref) }}
           innerRef={ref => { if (this.props.arrowRef) this.props.arrowRef(ref) }}
           onClick={() => { }}
           onClick={() => { }}
           data-test-id=""
           data-test-id=""
-          disabled={this.props.disabled}
+          disabled={disabled}
           dangerouslySetInnerHTML={{ __html: arrowImage }}
           dangerouslySetInnerHTML={{ __html: arrowImage }}
         />
         />
       </Wrapper>
       </Wrapper>

+ 3 - 0
src/components/atoms/DropdownButton/story.jsx

@@ -26,6 +26,9 @@ storiesOf('DropdownButton', module)
   .add('disabled', () => (
   .add('disabled', () => (
     <DropdownButton disabled value="Dropdown Button" onClick={action('clicked')} />
     <DropdownButton disabled value="Dropdown Button" onClick={action('clicked')} />
   ))
   ))
+  .add('disabled loading', () => (
+    <DropdownButton disabledLoading value="Dropdown Button" onClick={action('clicked')} />
+  ))
   .add('secondary centered', () => (
   .add('secondary centered', () => (
     <DropdownButton secondary centered value="Dropdown Button" onClick={action('clicked')} />
     <DropdownButton secondary centered value="Dropdown Button" onClick={action('clicked')} />
   ))
   ))

+ 6 - 2
src/components/atoms/RadioInput/RadioInput.jsx

@@ -25,6 +25,7 @@ import checkedImage from './images/checked.svg'
 
 
 const Wrapper = styled.div`
 const Wrapper = styled.div`
   ${props => props.disabled ? 'opacity: 0.5;' : ''}
   ${props => props.disabled ? 'opacity: 0.5;' : ''}
+  ${props => props.disabledLoading ? StyleProps.animations.disabledLoading : ''}
 `
 `
 const LabelStyled = styled.label`
 const LabelStyled = styled.label`
   display: flex;
   display: flex;
@@ -53,14 +54,17 @@ const InputStyled = styled.input`
 
 
 type Props = {
 type Props = {
   label: string,
   label: string,
+  disabledLoading?: boolean,
+  disabled?: boolean,
 }
 }
 @observer
 @observer
 class RadioInput extends React.Component<Props> {
 class RadioInput extends React.Component<Props> {
   render() {
   render() {
+    let disabled = this.props.disabled || this.props.disabledLoading
     return (
     return (
-      <Wrapper {...this.props}>
+      <Wrapper {...this.props} disabled={disabled} disabledLoading={this.props.disabledLoading}>
         <LabelStyled>
         <LabelStyled>
-          <InputStyled type="radio" {...this.props} data-test-id="radioInput-input" />
+          <InputStyled type="radio" {...this.props} disabled={disabled} data-test-id="radioInput-input" />
           <Text data-test-id="radioInput-label">{this.props.label}</Text>
           <Text data-test-id="radioInput-label">{this.props.label}</Text>
         </LabelStyled>
         </LabelStyled>
       </Wrapper>
       </Wrapper>

+ 4 - 1
src/components/atoms/RadioInput/story.jsx

@@ -18,5 +18,8 @@ import RadioInput from '.'
 
 
 storiesOf('RadioInput', module)
 storiesOf('RadioInput', module)
   .add('default', () => (
   .add('default', () => (
-    <RadioInput label="Radio input" onChange={() => {}} />
+    <RadioInput label="Radio input" onChange={() => { }} />
+  ))
+  .add('disabled loading', () => (
+    <RadioInput label="Radio input" onChange={() => { }} disabledLoading />
   ))
   ))

+ 5 - 2
src/components/atoms/Switch/Switch.jsx

@@ -28,6 +28,7 @@ const Wrapper = styled.div`
   ${props => props.disabled ? 'opacity: 0.5;' : ''}
   ${props => props.disabled ? 'opacity: 0.5;' : ''}
   ${props => props.justifyContent ? `justify-content: ${props.justifyContent};` : ''}
   ${props => props.justifyContent ? `justify-content: ${props.justifyContent};` : ''}
   ${props => props.width ? `width: ${props.width};` : ''}
   ${props => props.width ? `width: ${props.width};` : ''}
+  ${props => props.disabledLoading ? StyleProps.animations.disabledLoading : ''}
 `
 `
 const InputWrapper = styled.div`
 const InputWrapper = styled.div`
   position: relative;
   position: relative;
@@ -116,6 +117,7 @@ type Props = {
   onChange: (checked: ?boolean) => void,
   onChange: (checked: ?boolean) => void,
   checked: boolean,
   checked: boolean,
   disabled: boolean,
   disabled: boolean,
+  disabledLoading: boolean,
   triState: boolean,
   triState: boolean,
   leftLabel: boolean,
   leftLabel: boolean,
   secondary: boolean,
   secondary: boolean,
@@ -154,7 +156,7 @@ class Switch extends React.Component<Props, State> {
   }
   }
 
 
   handleInputChange() {
   handleInputChange() {
-    if (this.props.disabled) {
+    if (this.props.disabled || this.props.disabledLoading) {
       return
       return
     }
     }
 
 
@@ -186,7 +188,7 @@ class Switch extends React.Component<Props, State> {
         big={this.props.big}
         big={this.props.big}
         height={this.props.height}
         height={this.props.height}
         secondary={this.props.secondary}
         secondary={this.props.secondary}
-        disabled={this.props.disabled}
+        disabled={this.props.disabled || this.props.disabledLoading}
         onClick={() => { this.handleInputChange() }}
         onClick={() => { this.handleInputChange() }}
         tabIndex={0}
         tabIndex={0}
         onKeyDown={evt => { this.handleKeyDown(evt) }}
         onKeyDown={evt => { this.handleKeyDown(evt) }}
@@ -235,6 +237,7 @@ class Switch extends React.Component<Props, State> {
     return (
     return (
       <Wrapper
       <Wrapper
         disabled={this.props.disabled}
         disabled={this.props.disabled}
+        disabledLoading={this.props.disabledLoading}
         style={this.props.style}
         style={this.props.style}
         width={this.props.width}
         width={this.props.width}
         justifyContent={this.props.justifyContent}
         justifyContent={this.props.justifyContent}

+ 1 - 0
src/components/atoms/Switch/story.jsx

@@ -42,6 +42,7 @@ class Wrapper extends React.Component {
 storiesOf('Switch', module)
 storiesOf('Switch', module)
   .add('default', () => <Wrapper />)
   .add('default', () => <Wrapper />)
   .add('disabled', () => <Wrapper disabled />)
   .add('disabled', () => <Wrapper disabled />)
+  .add('disabled loading', () => <Wrapper disabledLoading />)
   .add('secondary', () => <Wrapper secondary />)
   .add('secondary', () => <Wrapper secondary />)
   .add('tri-state', () => <Wrapper triState />)
   .add('tri-state', () => <Wrapper triState />)
   .add('colored', () => <Wrapper big />)
   .add('colored', () => <Wrapper big />)

+ 3 - 0
src/components/atoms/TextArea/TextArea.jsx

@@ -24,6 +24,7 @@ import requiredImage from './images/required.svg'
 
 
 const Wrapper = styled.div`
 const Wrapper = styled.div`
   position: relative;
   position: relative;
+  ${props => props.disabledLoading ? StyleProps.animations.disabledLoading : ''}
 `
 `
 const Required = styled.div`
 const Required = styled.div`
   position: absolute;
   position: absolute;
@@ -81,6 +82,8 @@ class TextArea extends React.Component<any> {
       <Wrapper>
       <Wrapper>
         <Input
         <Input
           {...this.props}
           {...this.props}
+          disabled={this.props.disabled || this.props.disabledLoading}
+          disabledLoading={this.props.disabledLoading}
           innerRef={r => {
           innerRef={r => {
             if (this.props.innerRef) {
             if (this.props.innerRef) {
               this.props.innerRef(r)
               this.props.innerRef(r)

+ 1 - 0
src/components/atoms/TextArea/story.jsx

@@ -20,3 +20,4 @@ import TextArea from '.'
 
 
 storiesOf('TextArea', module)
 storiesOf('TextArea', module)
   .add('default', () => <TextArea />)
   .add('default', () => <TextArea />)
+  .add('disabled loading', () => <TextArea disabledLoading />)

+ 9 - 5
src/components/atoms/TextInput/TextInput.jsx

@@ -24,6 +24,7 @@ import requiredImage from './images/required.svg'
 
 
 const Wrapper = styled.div`
 const Wrapper = styled.div`
   position: relative;
   position: relative;
+  ${props => props.disabledLoading ? StyleProps.animations.disabledLoading : ''}
 `
 `
 const Required = styled.div`
 const Required = styled.div`
   position: absolute;
   position: absolute;
@@ -69,9 +70,9 @@ const Input = styled.input`
     outline: none;
     outline: none;
   }
   }
   &:disabled {
   &:disabled {
-    color: ${Palette.grayscale[3]};
-    border-color: ${Palette.grayscale[0]};
-    background-color: ${Palette.grayscale[0]};
+    color: ${props => !props.embedded ? Palette.grayscale[3] : 'inherit'};
+    border-color: ${props => !props.embedded ? Palette.grayscale[0] : 'inherit'};
+    background-color: ${props => !props.embedded ? Palette.grayscale[0] : 'inherit'};
   }
   }
   &::placeholder {
   &::placeholder {
     color: ${Palette.grayscale[3]};
     color: ${Palette.grayscale[3]};
@@ -103,12 +104,14 @@ type Props = {
   height?: string,
   height?: string,
   'data-test-id'?: string,
   'data-test-id'?: string,
   required?: boolean,
   required?: boolean,
+  disabledLoading?: boolean,
 }
 }
 const TextInput = (props: Props) => {
 const TextInput = (props: Props) => {
-  const { _ref, value, onChange, showClose, onCloseClick } = props
+  const { _ref, value, onChange, showClose, onCloseClick, disabled, disabledLoading } = props
+  let actualDisabled = disabled || disabledLoading
   let input
   let input
   return (
   return (
-    <Wrapper data-test-id={props['data-test-id'] || 'textInput'}>
+    <Wrapper data-test-id={props['data-test-id'] || 'textInput'} disabledLoading={disabledLoading}>
       <Input
       <Input
         innerRef={ref => { input = ref; if (_ref) _ref(ref) }}
         innerRef={ref => { input = ref; if (_ref) _ref(ref) }}
         type="text"
         type="text"
@@ -116,6 +119,7 @@ const TextInput = (props: Props) => {
         onChange={onChange}
         onChange={onChange}
         data-test-id="textInput-input"
         data-test-id="textInput-input"
         {...props}
         {...props}
+        disabled={actualDisabled}
       />
       />
       {props.required ? <Required /> : null}
       {props.required ? <Required /> : null}
       <Close
       <Close

+ 6 - 0
src/components/atoms/TextInput/story.jsx

@@ -38,6 +38,12 @@ storiesOf('TextInput', module)
   .add('default', () => (
   .add('default', () => (
     <Wrapper><TextInput /></Wrapper>
     <Wrapper><TextInput /></Wrapper>
   ))
   ))
+  .add('disabled', () => (
+    <Wrapper><TextInput disabled /></Wrapper>
+  ))
+  .add('disabled loading', () => (
+    <Wrapper><TextInput disabledLoading /></Wrapper>
+  ))
   .add('required', () => (
   .add('required', () => (
     <Wrapper><TextInput required /></Wrapper>
     <Wrapper><TextInput required /></Wrapper>
   ))
   ))

+ 0 - 32
src/components/atoms/Tooltip/story.jsx

@@ -1,32 +0,0 @@
-/*
-Copyright (C) 2017  Cloudbase Solutions SRL
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU Affero General Public License as
-published by the Free Software Foundation, either version 3 of the
-License, or (at your option) any later version.
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU Affero General Public License for more details.
-You should have received a copy of the GNU Affero General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-import React from 'react'
-import { storiesOf } from '@storybook/react'
-import WizardOptionsField from '../../molecules/WizardOptionsField'
-
-import Tooltip from '.'
-
-storiesOf('Tooltip', module)
-  .add('default', () => (
-    <div>
-      <WizardOptionsField
-        name="separate_vm"
-        type="boolean"
-        value
-        onChange={() => { }}
-      />
-      <Tooltip />
-    </div>
-  ))

+ 2 - 0
src/components/molecules/AutocompleteDropdown/AutocompleteDropdown.jsx

@@ -120,6 +120,7 @@ type Props = {
   onInputChange?: (value: string, filteredItems: any[]) => void,
   onInputChange?: (value: string, filteredItems: any[]) => void,
   noItemsMessage?: string,
   noItemsMessage?: string,
   disabled?: boolean,
   disabled?: boolean,
+  disabledLoading?: boolean,
   width?: number,
   width?: number,
   dimNullValue?: boolean,
   dimNullValue?: boolean,
   highlight?: boolean,
   highlight?: boolean,
@@ -451,6 +452,7 @@ class AutocompleteDropdown extends React.Component<Props, State> {
           onFocus={() => { this.handleSearchInputChange(this.state.searchValue, true) }}
           onFocus={() => { this.handleSearchInputChange(this.state.searchValue, true) }}
           highlight={this.props.highlight}
           highlight={this.props.highlight}
           disabled={this.props.disabled}
           disabled={this.props.disabled}
+          disabledLoading={this.props.disabledLoading}
           embedded={this.props.embedded}
           embedded={this.props.embedded}
         />
         />
         {this.props.required ? <Required /> : null}
         {this.props.required ? <Required /> : null}

+ 1 - 0
src/components/molecules/Dropdown/Dropdown.jsx

@@ -194,6 +194,7 @@ type Props = {
   noItemsMessage: string,
   noItemsMessage: string,
   noSelectionMessage: string,
   noSelectionMessage: string,
   disabled: boolean,
   disabled: boolean,
+  disabledLoading: boolean,
   width: number,
   width: number,
   'data-test-id'?: string,
   'data-test-id'?: string,
   embedded?: boolean,
   embedded?: boolean,

+ 13 - 1
src/components/molecules/FieldInput/FieldInput.jsx

@@ -56,6 +56,7 @@ const Label = styled.div`
     display: flex;
     display: flex;
     align-items: center;
     align-items: center;
   `}
   `}
+  ${props => props.disabledLoading ? StyleProps.animations.disabledLoading : ''}
 `
 `
 const LabelText = styled.span``
 const LabelText = styled.span``
 const Asterisk = styled.div`
 const Asterisk = styled.div`
@@ -84,6 +85,7 @@ type Props = {
   password?: boolean,
   password?: boolean,
   highlight?: boolean,
   highlight?: boolean,
   disabled?: boolean,
   disabled?: boolean,
+  disabledLoading?: boolean,
   items?: any[],
   items?: any[],
   useTextArea?: boolean,
   useTextArea?: boolean,
   noSelectionMessage?: string,
   noSelectionMessage?: string,
@@ -104,6 +106,7 @@ class FieldInput extends React.Component<Props> {
         height={this.props.layout === 'page' ? 16 : 24}
         height={this.props.layout === 'page' ? 16 : 24}
         justifyContent={this.props.layout === 'page' ? 'flex-end' : ''}
         justifyContent={this.props.layout === 'page' ? 'flex-end' : ''}
         disabled={this.props.disabled}
         disabled={this.props.disabled}
+        disabledLoading={this.props.disabledLoading}
         triState={propss.triState}
         triState={propss.triState}
         checked={this.props.value}
         checked={this.props.value}
         onChange={checked => { if (this.props.onChange) this.props.onChange(checked) }}
         onChange={checked => { if (this.props.onChange) this.props.onChange(checked) }}
@@ -124,6 +127,7 @@ class FieldInput extends React.Component<Props> {
         placeholder={LabelDictionary.get(this.props.name)}
         placeholder={LabelDictionary.get(this.props.name)}
         disabled={this.props.disabled}
         disabled={this.props.disabled}
         required={this.props.layout === 'page' ? false : this.props.required}
         required={this.props.layout === 'page' ? false : this.props.required}
+        disabledLoading={this.props.disabledLoading}
       />
       />
     )
     )
   }
   }
@@ -142,6 +146,7 @@ class FieldInput extends React.Component<Props> {
         }}
         }}
         placeholder={LabelDictionary.get(this.props.name)}
         placeholder={LabelDictionary.get(this.props.name)}
         disabled={this.props.disabled}
         disabled={this.props.disabled}
+        disabledLoading={this.props.disabledLoading}
       />
       />
     )
     )
   }
   }
@@ -161,6 +166,7 @@ class FieldInput extends React.Component<Props> {
           }
           }
         }}
         }}
         hideRequiredSymbol={this.props.layout === 'page'}
         hideRequiredSymbol={this.props.layout === 'page'}
+        disabledLoading={this.props.disabledLoading}
       />
       />
     )
     )
   }
   }
@@ -174,6 +180,7 @@ class FieldInput extends React.Component<Props> {
         onChange={e => { console.log('changing', e); if (this.props.onChange) this.props.onChange(e.target.value) }}
         onChange={e => { console.log('changing', e); if (this.props.onChange) this.props.onChange(e.target.value) }}
         placeholder={LabelDictionary.get(this.props.name)}
         placeholder={LabelDictionary.get(this.props.name)}
         disabled={this.props.disabled}
         disabled={this.props.disabled}
+        disabledLoading={this.props.disabledLoading}
         required={this.props.required}
         required={this.props.required}
       />
       />
     )
     )
@@ -203,6 +210,7 @@ class FieldInput extends React.Component<Props> {
       width: this.props.width,
       width: this.props.width,
       selectedItem,
       selectedItem,
       items,
       items,
+      disabledLoading: this.props.disabledLoading,
       onChange: item => this.props.onChange && this.props.onChange(item.value),
       onChange: item => this.props.onChange && this.props.onChange(item.value),
     }
     }
 
 
@@ -240,6 +248,7 @@ class FieldInput extends React.Component<Props> {
         multipleSelection
         multipleSelection
         width={this.props.width}
         width={this.props.width}
         disabled={this.props.disabled}
         disabled={this.props.disabled}
+        disabledLoading={this.props.disabledLoading}
         noSelectionMessage="Choose values"
         noSelectionMessage="Choose values"
         noItemsMessage={this.props.noItemsMessage}
         noItemsMessage={this.props.noItemsMessage}
         items={items}
         items={items}
@@ -272,6 +281,7 @@ class FieldInput extends React.Component<Props> {
         items={items}
         items={items}
         onChange={item => { if (this.props.onChange) this.props.onChange(item.value) }}
         onChange={item => { if (this.props.onChange) this.props.onChange(item.value) }}
         disabled={this.props.disabled}
         disabled={this.props.disabled}
+        disabledLoading={this.props.disabledLoading}
         highlight={this.props.highlight}
         highlight={this.props.highlight}
         required={this.props.required}
         required={this.props.required}
       />
       />
@@ -285,6 +295,7 @@ class FieldInput extends React.Component<Props> {
         label={LabelDictionary.get(this.props.name)}
         label={LabelDictionary.get(this.props.name)}
         onChange={e => { if (this.props.onChange) this.props.onChange(e.target.checked) }}
         onChange={e => { if (this.props.onChange) this.props.onChange(e.target.checked) }}
         disabled={this.props.disabled}
         disabled={this.props.disabled}
+        disabledLoading={this.props.disabledLoading}
       />
       />
     )
     )
   }
   }
@@ -312,6 +323,7 @@ class FieldInput extends React.Component<Props> {
         placeholder={LabelDictionary.get(fieldName)}
         placeholder={LabelDictionary.get(fieldName)}
         highlight={this.props.highlight}
         highlight={this.props.highlight}
         disabled={this.props.disabled}
         disabled={this.props.disabled}
+        disabledLoading={this.props.disabledLoading}
         required={this.props.required}
         required={this.props.required}
       />
       />
     )
     )
@@ -356,7 +368,7 @@ class FieldInput extends React.Component<Props> {
     let marginRight = this.props.layout === 'modal' || description || this.props.required ? '24px' : 0
     let marginRight = this.props.layout === 'modal' || description || this.props.required ? '24px' : 0
 
 
     return (
     return (
-      <Label layout={this.props.layout}>
+      <Label layout={this.props.layout} disabledLoading={this.props.disabledLoading}>
         <LabelText style={{ marginRight }}>
         <LabelText style={{ marginRight }}>
           {this.props.label || LabelDictionary.get(this.props.name)}
           {this.props.label || LabelDictionary.get(this.props.name)}
         </LabelText>
         </LabelText>

+ 6 - 1
src/components/molecules/PropertiesTable/PropertiesTable.jsx

@@ -33,6 +33,7 @@ const Wrapper = styled.div`
   flex-direction: column;
   flex-direction: column;
   border: 1px solid ${Palette.grayscale[2]};
   border: 1px solid ${Palette.grayscale[2]};
   border-radius: ${StyleProps.borderRadius};
   border-radius: ${StyleProps.borderRadius};
+  ${props => props.disabledLoading ? StyleProps.animations.disabledLoading : ''}
 `
 `
 const Column = styled.div`
 const Column = styled.div`
   ${StyleProps.exactWidth('calc(50% - 24px)')}
   ${StyleProps.exactWidth('calc(50% - 24px)')}
@@ -65,6 +66,7 @@ type Props = {
   onChange: (property: Field, value: any) => void,
   onChange: (property: Field, value: any) => void,
   valueCallback: (property: Field) => any,
   valueCallback: (property: Field) => any,
   hideRequiredSymbol?: boolean,
   hideRequiredSymbol?: boolean,
+  disabledLoading?: boolean,
 }
 }
 @observer
 @observer
 class PropertiesTable extends React.Component<Props> {
 class PropertiesTable extends React.Component<Props> {
@@ -80,6 +82,7 @@ class PropertiesTable extends React.Component<Props> {
       <Switch
       <Switch
         data-test-id={`${baseId}-switch-${prop.name}`}
         data-test-id={`${baseId}-switch-${prop.name}`}
         secondary
         secondary
+        disabled={this.props.disabledLoading}
         triState={opts.triState}
         triState={opts.triState}
         height={16}
         height={16}
         checked={this.props.valueCallback(prop)}
         checked={this.props.valueCallback(prop)}
@@ -99,6 +102,7 @@ class PropertiesTable extends React.Component<Props> {
         onChange={e => { this.props.onChange(prop, e.target.value) }}
         onChange={e => { this.props.onChange(prop, e.target.value) }}
         placeholder={this.getName(prop.name)}
         placeholder={this.getName(prop.name)}
         required={typeof prop.required === 'boolean' && !this.props.hideRequiredSymbol ? prop.required : false}
         required={typeof prop.required === 'boolean' && !this.props.hideRequiredSymbol ? prop.required : false}
+        disabled={this.props.disabledLoading}
       />
       />
     )
     )
   }
   }
@@ -134,6 +138,7 @@ class PropertiesTable extends React.Component<Props> {
       width: 320,
       width: 320,
       selectedItem,
       selectedItem,
       items,
       items,
+      disabled: this.props.disabledLoading,
       onChange: item => this.props.onChange(prop, item.value),
       onChange: item => this.props.onChange(prop, item.value),
       required: typeof prop.required === 'boolean' && !this.props.hideRequiredSymbol ? prop.required : false,
       required: typeof prop.required === 'boolean' && !this.props.hideRequiredSymbol ? prop.required : false,
     }
     }
@@ -176,7 +181,7 @@ class PropertiesTable extends React.Component<Props> {
 
 
   render() {
   render() {
     return (
     return (
-      <Wrapper>
+      <Wrapper disabledLoading={this.props.disabledLoading}>
         {this.props.properties.map(prop => {
         {this.props.properties.map(prop => {
           return (
           return (
             <Row key={prop.name} data-test-id={`${baseId}-row-${prop.name}`}>
             <Row key={prop.name} data-test-id={`${baseId}-row-${prop.name}`}>

+ 7 - 1
src/components/molecules/PropertiesTable/story.jsx

@@ -12,6 +12,8 @@ You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 */
 
 
+// @flow
+
 import React from 'react'
 import React from 'react'
 import { storiesOf } from '@storybook/react'
 import { storiesOf } from '@storybook/react'
 import PropertiesTable from '.'
 import PropertiesTable from '.'
@@ -24,7 +26,7 @@ let properties = [
   { type: 'string', enum: ['a', 'b', 'c'], name: 'prop-4', label: 'String enum' },
   { type: 'string', enum: ['a', 'b', 'c'], name: 'prop-4', label: 'String enum' },
 ]
 ]
 
 
-class Wrapper extends React.Component {
+class Wrapper extends React.Component<any, any> {
   constructor() {
   constructor() {
     super()
     super()
     this.state = {}
     this.state = {}
@@ -47,6 +49,7 @@ class Wrapper extends React.Component {
           properties={properties}
           properties={properties}
           valueCallback={prop => this.valueCallback(prop)}
           valueCallback={prop => this.valueCallback(prop)}
           onChange={(prop, value) => { this.handleChange(prop, value) }}
           onChange={(prop, value) => { this.handleChange(prop, value) }}
+          disabledLoading={this.props.disabledLoading}
         />
         />
       </div>
       </div>
     )
     )
@@ -57,3 +60,6 @@ storiesOf('PropertiesTable', module)
   .add('default', () => (
   .add('default', () => (
     <Wrapper />
     <Wrapper />
   ))
   ))
+  .add('disabled loading', () => (
+    <Wrapper disabledLoading />
+  ))

+ 0 - 32
src/components/molecules/WizardBreadcrumbs/story.jsx

@@ -1,32 +0,0 @@
-/*
-Copyright (C) 2017  Cloudbase Solutions SRL
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU Affero General Public License as
-published by the Free Software Foundation, either version 3 of the
-License, or (at your option) any later version.
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU Affero General Public License for more details.
-You should have received a copy of the GNU Affero General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-import React from 'react'
-import { storiesOf } from '@storybook/react'
-import WizardBreadcrumbs from '.'
-import { wizardConfig } from '../../../config'
-
-storiesOf('WizardBreadcrumbs', module)
-  .add('replica', () => (
-    <WizardBreadcrumbs
-      selected={{ ...wizardConfig.pages[0] }}
-      wizardType="replica"
-    />
-  ))
-  .add('migration', () => (
-    <WizardBreadcrumbs
-      selected={{ ...wizardConfig.pages[0] }}
-      wizardType="migration"
-    />
-  ))

+ 3 - 2
src/components/organisms/EditReplica/EditReplica.jsx

@@ -395,11 +395,11 @@ class EditReplica extends React.Component<Props, State> {
   }
   }
 
 
   renderOptions(type: 'source' | 'destination') {
   renderOptions(type: 'source' | 'destination') {
-    let loading = type === 'source' ? (providerStore.sourceSchemaLoading || providerStore.sourceOptionsLoading) :
-      providerStore.destinationSchemaLoading || providerStore.destinationOptionsLoading
+    let loading = type === 'source' ? providerStore.sourceSchemaLoading : providerStore.destinationSchemaLoading
     if (loading) {
     if (loading) {
       return this.renderLoading(`Loading ${type === 'source' ? 'source' : 'target'} options ...`)
       return this.renderLoading(`Loading ${type === 'source' ? 'source' : 'target'} options ...`)
     }
     }
+    let optionsLoading = type === 'source' ? providerStore.sourceOptionsLoading : providerStore.destinationOptionsLoading
     let schema = type === 'source' ? providerStore.sourceSchema : providerStore.destinationSchema
     let schema = type === 'source' ? providerStore.sourceSchema : providerStore.destinationSchema
     let fields = this.props.type === 'replica' ? schema.filter(f => !f.readOnly) : schema
     let fields = this.props.type === 'replica' ? schema.filter(f => !f.readOnly) : schema
 
 
@@ -419,6 +419,7 @@ class EditReplica extends React.Component<Props, State> {
         availableHeight={384}
         availableHeight={384}
         useAdvancedOptions
         useAdvancedOptions
         layout="modal"
         layout="modal"
+        optionsLoading={optionsLoading}
       />
       />
     )
     )
   }
   }

+ 2 - 0
src/components/organisms/WizardOptions/WizardOptions.jsx

@@ -91,6 +91,7 @@ type Props = {
   onScrollableRef?: (ref: HTMLElement) => void,
   onScrollableRef?: (ref: HTMLElement) => void,
   availableHeight?: number,
   availableHeight?: number,
   layout?: 'page' | 'modal',
   layout?: 'page' | 'modal',
+  optionsLoading?: boolean,
 }
 }
 @observer
 @observer
 class WizardOptions extends React.Component<Props> {
 class WizardOptions extends React.Component<Props> {
@@ -196,6 +197,7 @@ class WizardOptions extends React.Component<Props> {
         width={this.props.fieldWidth || StyleProps.inputSizes.wizard.width}
         width={this.props.fieldWidth || StyleProps.inputSizes.wizard.width}
         label={field.label}
         label={field.label}
         nullableBoolean={field.nullableBoolean}
         nullableBoolean={field.nullableBoolean}
+        disabledLoading={this.props.optionsLoading}
         {...additionalProps}
         {...additionalProps}
       />
       />
     )
     )

+ 4 - 2
src/components/organisms/WizardPageContent/WizardPageContent.jsx

@@ -334,7 +334,8 @@ class WizardPageContent extends React.Component<Props, State> {
       case 'source-options':
       case 'source-options':
         body = (
         body = (
           <WizardOptions
           <WizardOptions
-            loading={this.props.providerStore.sourceSchemaLoading || this.props.providerStore.sourceOptionsLoading}
+            loading={this.props.providerStore.sourceSchemaLoading}
+            optionsLoading={this.props.providerStore.sourceOptionsLoading}
             fields={this.props.providerStore.sourceSchema}
             fields={this.props.providerStore.sourceSchema}
             onChange={this.props.onSourceOptionsChange}
             onChange={this.props.onSourceOptionsChange}
             data={this.props.wizardData.sourceOptions}
             data={this.props.wizardData.sourceOptions}
@@ -347,7 +348,8 @@ class WizardPageContent extends React.Component<Props, State> {
       case 'dest-options':
       case 'dest-options':
         body = (
         body = (
           <WizardOptions
           <WizardOptions
-            loading={this.props.providerStore.destinationSchemaLoading || this.props.providerStore.destinationOptionsLoading}
+            loading={this.props.providerStore.destinationSchemaLoading}
+            optionsLoading={this.props.providerStore.destinationOptionsLoading}
             selectedInstances={this.props.wizardData.selectedInstances}
             selectedInstances={this.props.wizardData.selectedInstances}
             fields={this.props.providerStore.destinationSchema}
             fields={this.props.providerStore.destinationSchema}
             onChange={this.props.onDestOptionsChange}
             onChange={this.props.onDestOptionsChange}

+ 7 - 0
src/components/styleUtils/StyleProps.js

@@ -42,6 +42,13 @@ const StyleProps = {
         to {transform: rotate(360deg);}
         to {transform: rotate(360deg);}
       }
       }
     `,
     `,
+    disabledLoading: css`
+      animation: opacityToggle 750ms linear infinite alternate-reverse;
+      @keyframes opacityToggle {
+        0% {opacity: 1;}
+        100% {opacity: 0.3;}
+      }
+    `,
   },
   },
 
 
   media: {
   media: {