Explorar el Código

Improve scrolling in endpoint modal

Scroll just the fields if the modal is too large.
Change Azure input to manual if a JSON config is pasted.
Sergiu Miclea hace 8 años
padre
commit
aa2b00f6e0

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

@@ -145,6 +145,8 @@ class NewModal extends React.Component {
         right: 'auto',
         transition: 'all 0.2s',
         opacity: 0,
+        display: 'flex',
+        flexDirection: 'column',
       },
     }
 

+ 5 - 0
src/components/organisms/Endpoint/Endpoint.jsx

@@ -39,6 +39,7 @@ const Wrapper = styled.div`
   display: flex;
   align-items: center;
   flex-direction: column;
+  min-height: 0;
 `
 const Status = styled.div`
   display: flex;
@@ -47,6 +48,7 @@ const Status = styled.div`
 `
 const StatusHeader = styled.div`
   display: flex;
+  align-items: center;
 `
 const StatusMessage = styled.div`
   margin-left: 8px;
@@ -74,6 +76,9 @@ const StatusError = styled.div`
 `
 const Content = styled.div`
   width: 100%;
+  display: flex;
+  flex-direction: column;
+  min-height: 0;
 `
 const LoadingWrapper = styled.div`
   display: flex;

+ 11 - 0
src/components/organisms/PageHeader/PageHeader.jsx

@@ -63,6 +63,8 @@ class PageHeader extends React.Component {
   static propTypes = {
     title: PropTypes.string.isRequired,
     onProjectChange: PropTypes.func,
+    onModalOpen: PropTypes.func,
+    onModalClose: PropTypes.func,
     projectStore: PropTypes.object,
     userStore: PropTypes.object,
     providerStore: PropTypes.object,
@@ -119,6 +121,9 @@ class PageHeader extends React.Component {
     switch (item.value) {
       case 'endpoint':
         ProviderActions.loadProviders()
+        if (this.props.onModalOpen) {
+          this.props.onModalOpen()
+        }
         this.setState({ showChooseProviderModal: true })
         break
       default:
@@ -130,6 +135,9 @@ class PageHeader extends React.Component {
   }
 
   handleCloseChooseProviderModal() {
+    if (this.props.onModalClose) {
+      this.props.onModalClose()
+    }
     this.setState({ showChooseProviderModal: false })
   }
 
@@ -142,6 +150,9 @@ class PageHeader extends React.Component {
   }
 
   handleCloseEndpointModal() {
+    if (this.props.onModalClose) {
+      this.props.onModalClose()
+    }
     this.setState({ showEndpointModal: false })
   }
 

+ 16 - 0
src/components/pages/ReplicasPage/ReplicasPage.jsx

@@ -68,6 +68,7 @@ class ReplicasPage extends React.Component {
     this.state = {
       showDeleteReplicaConfirmation: false,
       confirmationItems: null,
+      modalIsOpen: false,
     }
   }
 
@@ -165,7 +166,20 @@ class ReplicasPage extends React.Component {
     window.location.href = '/#/wizard/replica'
   }
 
+  handleModalOpen() {
+    this.setState({ modalIsOpen: true })
+  }
+
+  handleModalClose() {
+    this.setState({ modalIsOpen: false }, () => {
+      this.pollData()
+    })
+  }
+
   pollData() {
+    if (this.state.modalIsOpen) {
+      return
+    }
     ReplicaActions.getReplicas().promise.then(() => {
       this.pollTimeout = setTimeout(() => { this.pollData() }, requestPollTimeout)
     })
@@ -232,6 +246,8 @@ class ReplicasPage extends React.Component {
             <PageHeader
               title="Coriolis Replicas"
               onProjectChange={project => { this.handleProjectChange(project) }}
+              onModalOpen={() => { this.handleModalOpen() }}
+              onModalClose={() => { this.handleModalClose() }}
             />
           }
         />

+ 78 - 38
src/plugins/endpoint/azure/ContentPlugin.jsx

@@ -27,16 +27,18 @@ import {
   RadioInput,
 } from '../../../components'
 
-const Wrapper = styled.div``
+const Wrapper = styled.div`
+  display: flex;
+  flex-direction: column;
+  min-height: 0;
+`
 const Fields = styled.div`
   display: flex;
-  flex-wrap: wrap;
-  margin-left: -64px;
   margin-top: 32px;
-  position: relative;
+  flex-direction: column;
+  overflow: auto;
 `
 const FieldStyled = styled(EndpointField) `
-  margin-left: 64px;
   min-width: 224px;
   max-width: 224px;
   margin-bottom: 16px;
@@ -44,22 +46,29 @@ const FieldStyled = styled(EndpointField) `
 const RadioGroup = styled.div`
   width: 100%;
 `
+const CloudProfile = styled.div``
 const ConfigLabel = styled.div`
   font-size: 11px;
-  margin-top: -10px;
   color: ${Palette.grayscale[3]};
-  position: absolute;
-  bottom: -4px;
-  left: 64px;
+  margin-top: -10px;
 `
 const Buttons = styled.div`
   display: flex;
   justify-content: space-between;
   width: 100%;
   margin-top: 32px;
+  flex-shrink: 0;
+`
+const Row = styled.div`
+  display: flex;
+  flex-shrink: 0;
+  justify-content: space-between;
 `
 const CustomConfigWrapper = styled.div`
   width: 100%;
+  display: flex;
+  flex-direction: column;
+  min-height: 0;
 `
 const CustomConfigTitle = styled.div`
   text-align: center;
@@ -72,6 +81,7 @@ const CustomInputType = styled.div`
 `
 const PasteField = styled.div`
   margin-top: 32px;
+  overflow: auto;
 `
 const PasteFieldLabel = styled.div`
   font-size: 10px;
@@ -91,6 +101,24 @@ const CustomTypes = {
   json: 'json',
 }
 
+const fieldNameMapper = {
+  activeDirectory: 'active_directory_url',
+  activeDirectoryDataLakeResourceId: 'active_directory_data_lake_resource_id',
+  activeDirectoryGraphResourceId: 'active_directory_graph_resource_id',
+  activeDirectoryResourceId: 'active_directory_resource_id',
+  batchResourceId: 'batch_resource_endpoint',
+  gallery: 'gallery_endpoint',
+  management: 'management_endpoint',
+  resourceManager: 'resource_manager_endpoint',
+  sqlManagement: 'sql_management_endpoint',
+  vmImageAliasDoc: 'vm_image_alias_doc',
+  azureDatalakeAnalyticsCatalogAndJobEndpoint: 'azure_datalake_analytics_catalog_and_job_endpoint',
+  azureDatalakeStoreFileSystemEndpoint: 'azure_datalake_store_file_system_endpoint',
+  keyvaultDns: 'keyvault_dns',
+  sqlServerHostname: 'sql_server_hostname',
+  storageEndpoint: 'storage_endpoint',
+}
+
 class ContentPlugin extends React.Component {
   static propTypes = {
     connectionInfoSchema: PropTypes.array,
@@ -181,24 +209,6 @@ class ContentPlugin extends React.Component {
       return
     }
 
-    const fieldNameMapper = {
-      activeDirectory: 'active_directory_url',
-      activeDirectoryDataLakeResourceId: 'active_directory_data_lake_resource_id',
-      activeDirectoryGraphResourceId: 'active_directory_graph_resource_id',
-      activeDirectoryResourceId: 'active_directory_resource_id',
-      batchResourceId: 'batch_resource_endpoint',
-      gallery: 'gallery_endpoint',
-      management: 'management_endpoint',
-      resourceManager: 'resource_manager_endpoint',
-      sqlManagement: 'sql_management_endpoint',
-      vmImageAliasDoc: 'vm_image_alias_doc',
-      azureDatalakeAnalyticsCatalogAndJobEndpoint: 'azure_datalake_analytics_catalog_and_job_endpoint',
-      azureDatalakeStoreFileSystemEndpoint: 'azure_datalake_store_file_system_endpoint',
-      keyvaultDns: 'keyvault_dns',
-      sqlServerHostname: 'sql_server_hostname',
-      storageEndpoint: 'storage_endpoint',
-    }
-
     let updatedFields = []
     const setValue = (object, key) => {
       if (object[key]) {
@@ -214,6 +224,17 @@ class ContentPlugin extends React.Component {
     this.props.handleFieldsChange(updatedFields)
   }
 
+  handleJsonPaste() {
+    if (this.pasteTimeout) {
+      clearTimeout(this.pasteTimeout)
+      this.pasteTimeout = null
+    }
+
+    this.pasteTimeout = setTimeout(() => {
+      this.setState({ customType: CustomTypes.manual })
+    }, 1000)
+  }
+
   renderField(field, customProps) {
     return (
       <FieldStyled
@@ -230,6 +251,25 @@ class ContentPlugin extends React.Component {
     )
   }
 
+  renderFieldGroup(fields) {
+    const rows = []
+    let lastField
+    fields.forEach((field, i) => {
+      const currentField = this.renderField(field)
+      if (i % 2 !== 0) {
+        rows.push((
+          <Row key={field.name}>
+            {lastField}
+            {currentField}
+          </Row>
+        ))
+      }
+      lastField = currentField
+    })
+
+    return rows
+  }
+
   renderCustomPage() {
     if (this.state.currentPage !== Pages.custom) {
       return null
@@ -240,9 +280,7 @@ class ContentPlugin extends React.Component {
     if (this.state.customType === CustomTypes.manual) {
       fields = (
         <Fields>
-          {this.props.connectionInfoSchema.find(f => f.name === 'cloud_profile').custom_cloud_fields.map(field =>
-            this.renderField(field)
-          )}
+          {this.renderFieldGroup(this.props.connectionInfoSchema.find(f => f.name === 'cloud_profile').custom_cloud_fields)}
         </Fields>
       )
     } else {
@@ -256,6 +294,7 @@ class ContentPlugin extends React.Component {
               placeholder="Paste JSON output here"
               value={this.state.jsonConfig}
               onChange={e => { this.handleJsonConfigChange(e.target.value) }}
+              onPaste={() => { this.handleJsonPaste() }}
             />
           </PasteFieldInput>
         </PasteField>
@@ -294,9 +333,7 @@ class ContentPlugin extends React.Component {
 
     const fields = this.props.connectionInfoSchema
 
-    let renderedFields = fields.filter(f => f.name !== 'login_type' && f.name !== 'cloud_profile').map(field =>
-      this.renderField(field)
-    )
+    let renderedFields = this.renderFieldGroup(fields.filter(f => f.name !== 'login_type' && f.name !== 'cloud_profile'))
 
     let loginTypeField = fields.find(f => f.name === 'login_type')
 
@@ -311,16 +348,19 @@ class ContentPlugin extends React.Component {
       </RadioGroup>
     ))
 
-    renderedFields = renderedFields.concat(loginTypeField.items.find(f => f.name === this.props.getFieldValue(loginTypeField)).fields.map(field =>
-      this.renderField(field)
-    ))
+    renderedFields = renderedFields.concat(this.renderFieldGroup(loginTypeField.items.find(f => f.name === this.props.getFieldValue(loginTypeField)).fields))
 
-    renderedFields.push(this.renderField(fields.find(f => f.name === 'cloud_profile')))
+    const cloudProfileWrapper = (
+      <CloudProfile key="cloudProfile">
+        {this.renderField(fields.find(f => f.name === 'cloud_profile'))}
+        {this.renderAdditionalConfigLabel()}
+      </CloudProfile>
+    )
+    renderedFields.push(cloudProfileWrapper)
 
     return (
       <Fields>
         {renderedFields}
-        {this.renderAdditionalConfigLabel()}
       </Fields>
     )
   }

+ 39 - 17
src/plugins/endpoint/default/ContentPlugin.jsx

@@ -18,15 +18,18 @@ import PropTypes from 'prop-types'
 
 import { EndpointField, Button, LoadingButton } from '../../../components'
 
-const Wrapper = styled.div``
+const Wrapper = styled.div`
+  display: flex;
+  flex-direction: column;
+  min-height: 0;
+`
 const Fields = styled.div`
   display: flex;
-  flex-wrap: wrap;
-  margin-left: -64px;
   margin-top: 32px;
+  flex-direction: column;
+  overflow: auto;
 `
 const FieldStyled = styled(EndpointField)`
-  margin-left: 64px;
   min-width: 224px;
   max-width: 224px;
   margin-bottom: 16px;
@@ -36,6 +39,12 @@ const Buttons = styled.div`
   justify-content: space-between;
   width: 100%;
   margin-top: 32px;
+  flex-shrink: 0;
+`
+const Row = styled.div`
+  display: flex;
+  flex-shrink: 0;
+  justify-content: space-between;
 `
 
 class ContentPlugin extends React.Component {
@@ -56,6 +65,7 @@ class ContentPlugin extends React.Component {
   componentDidMount() {
     this.props.onRef(this)
   }
+
   componentWillUnmount() {
     this.props.onRef(undefined)
   }
@@ -73,22 +83,34 @@ class ContentPlugin extends React.Component {
   }
 
   renderFields() {
-    const renderedFields = this.props.connectionInfoSchema.map(field => (
-      <FieldStyled
-        {...field}
-        large
-        disabled={this.props.disabled}
-        key={field.name}
-        password={field.name === 'password'}
-        highlight={this.props.invalidFields.findIndex(fn => fn === field.name) > -1}
-        value={this.props.getFieldValue(field)}
-        onChange={value => { this.props.handleFieldChange(field, value) }}
-      />
-    ))
+    const rows = []
+    let lastField
+    this.props.connectionInfoSchema.forEach((field, i) => {
+      const currentField = (
+        <FieldStyled
+          {...field}
+          large
+          disabled={this.props.disabled}
+          password={field.name === 'password'}
+          highlight={this.props.invalidFields.findIndex(fn => fn === field.name) > -1}
+          value={this.props.getFieldValue(field)}
+          onChange={value => { this.props.handleFieldChange(field, value) }}
+        />
+      )
+      if (i % 2 !== 0) {
+        rows.push((
+          <Row key={field.name}>
+            {lastField}
+            {currentField}
+          </Row>
+        ))
+      }
+      lastField = currentField
+    })
 
     return (
       <Fields>
-        {renderedFields}
+        {rows}
       </Fields>
     )
   }