Преглед изворни кода

Disable update / create while options are loading

This disables the update button when editing a replica and the create
button when recreating a migration while options (source, destination,
network and storage) are being loaded.

Previously, the button would be disabled only if the user was on the
options panel for which the options was currently being loaded.

There's also now a loading indicator for each of the 4 panels, so the
user is informed which panel is still waiting for its options.
Sergiu Miclea пре 5 година
родитељ
комит
10d3a4942f

+ 15 - 1
src/components/molecules/Panel/Panel.tsx

@@ -16,6 +16,9 @@ import * as React from 'react'
 import styled, { css } from 'styled-components'
 import { observer } from 'mobx-react'
 import Palette from '../../styleUtils/Palette'
+import StyleProps from '../../styleUtils/StyleProps'
+
+import loadingImage from './images/loading.svg'
 
 const Wrapper = styled.div<any>`
   display: flex;
@@ -28,6 +31,7 @@ const Navigation = styled.div<any>`
   background-image: linear-gradient(rgba(200, 204, 215, 0.54), rgba(164, 170, 181, 0.54));
 `
 const NavigationItemDiv = styled.div<any>`
+  position: relative;
   height: 47px;
   border-bottom: 1px solid ${Palette.grayscale[2]};
   color: ${props => (props.disabled ? Palette.grayscale[3] : 'black')};
@@ -59,12 +63,22 @@ const ReloadButton = styled.div<any>`
   bottom: 42px;
   left: 32px;
 `
+const Loading = styled.span`
+  position: absolute;
+  top: 15px;
+  right: 8px;
+  width: 16px;
+  height: 16px;
+  background: url('${loadingImage}') center no-repeat;
+  ${StyleProps.animations.rotation}
+`
 
 export type NavigationItem = {
   label: string,
   value: string,
   disabled?: boolean,
   title?: string,
+  loading?: boolean,
 }
 
 export type Props = {
@@ -103,7 +117,7 @@ class Panel extends React.Component<Props> {
               data-test-id={`${TEST_ID}-navItem-${item.value}`}
               disabled={item.disabled}
               title={item.title}
-            >{item.label}
+            >{item.label}{item.loading ? <Loading /> : null}
             </NavigationItemDiv>
           ))}
         </Navigation>

+ 7 - 0
src/components/molecules/Panel/images/loading.svg

@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+  <g>
+    <circle stroke="#eee" fill="none"  stroke-width="2"  cx="8" cy="8" r="7"></circle>
+    <path stroke="white" d="M 15 8 A 7 7 0 0 0 8 1" fill="none"  stroke-width="2" />
+  </g>
+</svg>

+ 53 - 20
src/components/organisms/EditReplica/EditReplica.tsx

@@ -41,6 +41,7 @@ import type { Network, NetworkMap, SecurityGroup } from '../../../@types/Network
 import { providerTypes, migrationFields } from '../../../constants'
 import configLoader from '../../../utils/Config'
 import StyleProps from '../../styleUtils/StyleProps'
+import LoadingButton from '../../molecules/LoadingButton/LoadingButton'
 
 const PanelContent = styled.div<any>`
   display: flex;
@@ -321,17 +322,32 @@ class EditReplica extends React.Component<Props, State> {
   }
 
   isUpdateDisabled() {
-    const isLoadingDestOptions = this.state.selectedPanel === 'dest_options'
-      && (providerStore.destinationSchemaLoading || providerStore.destinationOptionsPrimaryLoading)
-    const isLoadingSourceOptions = this.state.selectedPanel === 'source_options'
-      && (providerStore.sourceSchemaLoading || providerStore.sourceOptionsPrimaryLoading)
-    const isLoadingNetwork = this.state.selectedPanel === 'network_mapping' && this.props.instancesDetailsLoading
-    const isLoadingStorage = this.state.selectedPanel === 'storage_mapping'
-      && (this.props.instancesDetailsLoading || endpointStore.storageLoading)
     const isDestFailed = this.props.type === 'replica' && this.state.destinationFailedMessage
-    return this.state.updateDisabled || isLoadingSourceOptions
-      || isLoadingDestOptions || isLoadingNetwork
-      || isLoadingStorage || isDestFailed
+    return this.state.updateDisabled || isDestFailed
+  }
+
+  isLoadingDestOptions() {
+    return providerStore.destinationSchemaLoading
+      || providerStore.destinationOptionsPrimaryLoading
+  }
+
+  isLoadingSourceOptions() {
+    return providerStore.sourceSchemaLoading
+      || providerStore.sourceOptionsPrimaryLoading
+  }
+
+  isLoadingNetwork() {
+    return this.props.instancesDetailsLoading
+  }
+
+  isLoadingStorage() {
+    return this.props.instancesDetailsLoading || endpointStore.storageLoading
+  }
+
+  isLoading() {
+    return this.isLoadingSourceOptions()
+      || this.isLoadingDestOptions() || this.isLoadingNetwork()
+      || this.isLoadingStorage()
   }
 
   parseReplicaData(environment: { [prop: string]: any } | null) {
@@ -608,13 +624,17 @@ class EditReplica extends React.Component<Props, State> {
             secondary
           >Cancel
           </Button>
-          <Button
-            large
-            onClick={() => { this.handleUpdateClick() }}
-            disabled={this.isUpdateDisabled()}
-          >
-            {this.props.type === 'replica' ? 'Update' : 'Create'}
-          </Button>
+          {this.isLoading() ? (
+            <LoadingButton>Loading ...</LoadingButton>
+          ) : (
+            <Button
+              large
+              onClick={() => { this.handleUpdateClick() }}
+              disabled={this.isUpdateDisabled()}
+            >
+              {this.props.type === 'replica' ? 'Update' : 'Create'}
+            </Button>
+          )}
         </Buttons>
       </PanelContent>
     )
@@ -638,13 +658,26 @@ class EditReplica extends React.Component<Props, State> {
         label: 'Source Options',
         disabled: this.state.sourceFailed,
         title: this.state.sourceFailed ? 'There are source platform errors, source options can\'t be updated' : '',
+        loading: this.isLoadingSourceOptions(),
+      },
+      {
+        value: 'dest_options',
+        label: 'Target Options',
+        loading: this.isLoadingDestOptions(),
+      },
+      {
+        value: 'network_mapping',
+        label: 'Network Mapping',
+        loading: this.isLoadingNetwork(),
       },
-      { value: 'dest_options', label: 'Target Options' },
-      { value: 'network_mapping', label: 'Network Mapping' },
     ]
 
     if (this.hasStorageMap()) {
-      navigationItems.push({ value: 'storage_mapping', label: 'Storage Mapping' })
+      navigationItems.push({
+        value: 'storage_mapping',
+        label: 'Storage Mapping',
+        loading: this.isLoadingStorage(),
+      })
     }
 
     return (