Преглед на файлове

Add source properties info to replica details page

Replica and migration details page now displays source properties
information.
Previously, only target properties information was displayed.
Sergiu Miclea преди 6 години
родител
ревизия
56030ce1fa

+ 4 - 0
src/components/atoms/PasswordValue/PasswordValue.jsx

@@ -48,6 +48,7 @@ const Value = styled.span`
 
 
 type Props = {
 type Props = {
   value: string,
   value: string,
+  onShow?: () => void,
 }
 }
 type State = {
 type State = {
   show: boolean,
   show: boolean,
@@ -59,6 +60,9 @@ class PasswordValue extends React.Component<Props, State> {
   }
   }
 
 
   handleShowClick() {
   handleShowClick() {
+    if (this.props.onShow) {
+      this.props.onShow()
+    }
     this.setState({ show: true })
     this.setState({ show: true })
   }
   }
 
 

+ 1 - 1
src/components/molecules/MainDetailsTable/MainDetailsTable.jsx

@@ -394,7 +394,7 @@ class MainDetailsTable extends React.Component<Props, State> {
       <Wrapper>
       <Wrapper>
         <Header>
         <Header>
           <HeaderLabel>Source</HeaderLabel>
           <HeaderLabel>Source</HeaderLabel>
-          <HeaderLabel>Destination</HeaderLabel>
+          <HeaderLabel>Target</HeaderLabel>
         </Header>
         </Header>
         {this.props.instancesDetails.map(instance => (
         {this.props.instancesDetails.map(instance => (
           <InstanceInfo key={instance.name}>
           <InstanceInfo key={instance.name}>

+ 43 - 15
src/components/organisms/MainDetails/MainDetails.jsx

@@ -117,13 +117,16 @@ const PropertyValue = styled.div`
   text-align: right;
   text-align: right;
   overflow: hidden;
   overflow: hidden;
   text-overflow: ellipsis;
   text-overflow: ellipsis;
-  max-width: 50%;
+  max-width: calc(50% + 16px);
+  margin-right: -16px;
 `
 `
 
 
 type Props = {
 type Props = {
   item: ?MainItem,
   item: ?MainItem,
   destinationSchema: FieldType[],
   destinationSchema: FieldType[],
   destinationSchemaLoading: boolean,
   destinationSchemaLoading: boolean,
+  sourceSchema: FieldType[],
+  sourceSchemaLoading: boolean,
   instancesDetails: Instance[],
   instancesDetails: Instance[],
   instancesDetailsLoading: boolean,
   instancesDetailsLoading: boolean,
   endpoints: Endpoint[],
   endpoints: Endpoint[],
@@ -131,8 +134,15 @@ type Props = {
   bottomControls: React.Node,
   bottomControls: React.Node,
   loading: boolean,
   loading: boolean,
 }
 }
+type State = {
+  showPassword: string[]
+}
 @observer
 @observer
-class MainDetails extends React.Component<Props> {
+class MainDetails extends React.Component<Props, State> {
+  state = {
+    showPassword: [],
+  }
+
   getSourceEndpoint(): ?Endpoint {
   getSourceEndpoint(): ?Endpoint {
     let endpoint = this.props.endpoints.find(e => this.props.item && e.id === this.props.item.origin_endpoint_id)
     let endpoint = this.props.endpoints.find(e => this.props.item && e.id === this.props.item.origin_endpoint_id)
     return endpoint
     return endpoint
@@ -204,14 +214,15 @@ class MainDetails extends React.Component<Props> {
     return endpointIsMissing
     return endpointIsMissing
   }
   }
 
 
-  renderPropertiesTable(propertyNames: string[]) {
-    let endpoint = this.getDestinationEndpoint()
+  renderPropertiesTable(propertyNames: string[], type: 'source' | 'destination') {
+    let endpoint = type === 'source' ? this.getSourceEndpoint() : this.getDestinationEndpoint()
 
 
     let getValue = (name: string, value: any) => {
     let getValue = (name: string, value: any) => {
       if (value.join && value.length && value[0].destination && value[0].source) {
       if (value.join && value.length && value[0].destination && value[0].source) {
         return value.map(v => `${v.source}=${v.destination}`).join(', ')
         return value.map(v => `${v.source}=${v.destination}`).join(', ')
       }
       }
-      return fieldHelper.getValueAlias(name, value, this.props.destinationSchema, endpoint && endpoint.type)
+      let schema = type === 'source' ? this.props.sourceSchema : this.props.destinationSchema
+      return fieldHelper.getValueAlias(name, value, schema, endpoint && endpoint.type)
     }
     }
 
 
     let properties = []
     let properties = []
@@ -219,10 +230,11 @@ class MainDetails extends React.Component<Props> {
     let migrationImageMapFieldName = plugin && plugin.migrationImageMapFieldName
     let migrationImageMapFieldName = plugin && plugin.migrationImageMapFieldName
     let dictionaryKey = ''
     let dictionaryKey = ''
     if (endpoint) {
     if (endpoint) {
-      dictionaryKey = `${endpoint.type}-destination`
+      dictionaryKey = `${endpoint.type}-${type}`
     }
     }
+    let environment = this.props.item && (type === 'source' ? this.props.item.source_environment : this.props.item.destination_environment)
     propertyNames.forEach(pn => {
     propertyNames.forEach(pn => {
-      let value = this.props.item ? this.props.item.destination_environment[pn] : ''
+      let value = environment ? environment[pn] : ''
       let label = LabelDictionary.get(pn, dictionaryKey)
       let label = LabelDictionary.get(pn, dictionaryKey)
 
 
       if (value && value.join) {
       if (value && value.join) {
@@ -256,8 +268,12 @@ class MainDetails extends React.Component<Props> {
           <PropertyRow key={prop.label}>
           <PropertyRow key={prop.label}>
             <PropertyName>{prop.label}</PropertyName>
             <PropertyName>{prop.label}</PropertyName>
             <PropertyValue>
             <PropertyValue>
-              {prop.label.toLowerCase().indexOf('password') > -1
-                ? <PasswordValue value={prop.value} /> : <CopyValue value={prop.value} />}
+              {prop.label.toLowerCase().indexOf('password') > -1 && !this.state.showPassword.find(f => f === `${prop.label}-${type}`)
+                ? (
+                  <PasswordValue
+                    value={prop.value}
+                    onShow={() => this.setState({ showPassword: [...this.state.showPassword, `${prop.label}-${type}`] })}
+                  />) : <CopyValue value={prop.value} />}
             </PropertyValue>
             </PropertyValue>
           </PropertyRow>
           </PropertyRow>
         ))}
         ))}
@@ -273,14 +289,15 @@ class MainDetails extends React.Component<Props> {
     const destinationEndpoint = this.getDestinationEndpoint()
     const destinationEndpoint = this.getDestinationEndpoint()
     const lastUpdated = this.renderLastExecutionTime()
     const lastUpdated = this.renderLastExecutionTime()
 
 
-    const destEnv = this.props.item && this.props.item.destination_environment
-    const propertyNames = destEnv ?
-      Object.keys(destEnv).filter(k =>
+    const getPropertyNames = (type: 'source' | 'destination') => {
+      let env = this.props.item && (type === 'source' ? this.props.item.source_environment : this.props.item.destination_environment)
+      return env ? Object.keys(env).filter(k =>
         k !== 'network_map' && (
         k !== 'network_map' && (
           k !== 'storage_mappings' ||
           k !== 'storage_mappings' ||
-          (destEnv[k] != null && typeof destEnv[k] === 'object' && Object.keys(destEnv[k]).length > 0)
+          (env[k] != null && typeof env[k] === 'object' && Object.keys(env[k]).length > 0)
         )
         )
       ) : []
       ) : []
+    }
 
 
     return (
     return (
       <ColumnsLayout>
       <ColumnsLayout>
@@ -297,6 +314,17 @@ class MainDetails extends React.Component<Props> {
               data-test-id="mainDetails-sourceLogo"
               data-test-id="mainDetails-sourceLogo"
             />
             />
           </Row>
           </Row>
+          {getPropertyNames('source').length > 0 ? (
+            <Row>
+              <Field>
+                <Label>Properties{this.props.sourceSchemaLoading ? (
+                  <StatusIcon status="RUNNING" style={{ marginLeft: '8px' }} />
+                ) : <StatusIconStub />
+                }</Label>
+                <Value block>{this.renderPropertiesTable(getPropertyNames('source'), 'source')}</Value>
+              </Field>
+            </Row>
+          ) : null}
           <Row>
           <Row>
             <Field>
             <Field>
               <Label>Id</Label>
               <Label>Id</Label>
@@ -352,14 +380,14 @@ class MainDetails extends React.Component<Props> {
               data-test-id="mainDetails-targetLogo"
               data-test-id="mainDetails-targetLogo"
             />
             />
           </Row>
           </Row>
-          {propertyNames.length > 0 ? (
+          {getPropertyNames('destination').length > 0 ? (
             <Row>
             <Row>
               <Field>
               <Field>
                 <Label>Properties{this.props.destinationSchemaLoading ? (
                 <Label>Properties{this.props.destinationSchemaLoading ? (
                   <StatusIcon status="RUNNING" style={{ marginLeft: '8px' }} />
                   <StatusIcon status="RUNNING" style={{ marginLeft: '8px' }} />
                 ) : <StatusIconStub />
                 ) : <StatusIconStub />
                 }</Label>
                 }</Label>
-                <Value block>{this.renderPropertiesTable(propertyNames)}</Value>
+                <Value block>{this.renderPropertiesTable(getPropertyNames('destination'), 'destination')}</Value>
               </Field>
               </Field>
             </Row>
             </Row>
           ) : null}
           ) : null}

+ 4 - 0
src/components/organisms/MigrationDetailsContent/MigrationDetailsContent.jsx

@@ -59,6 +59,8 @@ type Props = {
   detailsLoading: boolean,
   detailsLoading: boolean,
   instancesDetails: Instance[],
   instancesDetails: Instance[],
   instancesDetailsLoading: boolean,
   instancesDetailsLoading: boolean,
+  sourceSchema: Field[],
+  sourceSchemaLoading: boolean,
   destinationSchema: Field[],
   destinationSchema: Field[],
   destinationSchemaLoading: boolean,
   destinationSchemaLoading: boolean,
   endpoints: Endpoint[],
   endpoints: Endpoint[],
@@ -89,6 +91,8 @@ class MigrationDetailsContent extends React.Component<Props> {
         item={this.props.item}
         item={this.props.item}
         instancesDetails={this.props.instancesDetails}
         instancesDetails={this.props.instancesDetails}
         instancesDetailsLoading={this.props.instancesDetailsLoading}
         instancesDetailsLoading={this.props.instancesDetailsLoading}
+        sourceSchema={this.props.sourceSchema}
+        sourceSchemaLoading={this.props.sourceSchemaLoading}
         destinationSchema={this.props.destinationSchema}
         destinationSchema={this.props.destinationSchema}
         destinationSchemaLoading={this.props.destinationSchemaLoading}
         destinationSchemaLoading={this.props.destinationSchemaLoading}
         endpoints={this.props.endpoints}
         endpoints={this.props.endpoints}

+ 4 - 0
src/components/organisms/ReplicaDetailsContent/ReplicaDetailsContent.jsx

@@ -74,6 +74,8 @@ type TimezoneValue = 'utc' | 'local'
 type Props = {
 type Props = {
   item: ?MainItem,
   item: ?MainItem,
   endpoints: Endpoint[],
   endpoints: Endpoint[],
+  sourceSchema: Field[],
+  sourceSchemaLoading: boolean,
   destinationSchema: Field[],
   destinationSchema: Field[],
   destinationSchemaLoading: boolean,
   destinationSchemaLoading: boolean,
   networks: Network[],
   networks: Network[],
@@ -159,6 +161,8 @@ class ReplicaDetailsContent extends React.Component<Props, State> {
     return (
     return (
       <MainDetails
       <MainDetails
         item={this.props.item}
         item={this.props.item}
+        sourceSchema={this.props.sourceSchema}
+        sourceSchemaLoading={this.props.sourceSchemaLoading}
         destinationSchema={this.props.destinationSchema}
         destinationSchema={this.props.destinationSchema}
         destinationSchemaLoading={this.props.destinationSchemaLoading}
         destinationSchemaLoading={this.props.destinationSchemaLoading}
         instancesDetails={this.props.instancesDetails}
         instancesDetails={this.props.instancesDetails}

+ 35 - 24
src/components/pages/MigrationDetailsPage/MigrationDetailsPage.jsx

@@ -81,33 +81,40 @@ class MigrationDetailsPage extends React.Component<Props, State> {
       if (!details) {
       if (!details) {
         return
         return
       }
       }
-      let endpoint = endpointStore.endpoints.find(e => e.id === details.destination_endpoint_id)
-      if (!endpoint) {
+      let sourceEndpoint = endpointStore.endpoints.find(e => e.id === details.origin_endpoint_id)
+      let destinationEndpoint = endpointStore.endpoints.find(e => e.id === details.destination_endpoint_id)
+      if (!sourceEndpoint || !destinationEndpoint) {
         return
         return
       }
       }
-      // This allows the values to be displayed with their allocated names instead of their IDs
-      await providerStore.loadOptionsSchema({
-        providerName: endpoint.type,
-        optionsType: 'destination',
-        useCache: true,
-        quietError: true,
-      })
-      let getOptionsValuesConfig = {
-        optionsType: 'destination',
-        endpointId: details.destination_endpoint_id,
-        providerName: endpoint.type,
-        useCache: true,
-        quietError: true,
-        allowMultiple: true,
+      const loadOptions = async (optionsType: 'source' | 'destination') => {
+        let providerName = optionsType === 'source' ? sourceEndpoint.type : destinationEndpoint.type
+        // This allows the values to be displayed with their allocated names instead of their IDs
+        await providerStore.loadOptionsSchema({
+          providerName,
+          optionsType,
+          useCache: true,
+          quietError: true,
+        })
+        let getOptionsValuesConfig = {
+          optionsType,
+          endpointId: optionsType === 'source' ? details.origin_endpoint_id : details.destination_endpoint_id,
+          providerName,
+          useCache: true,
+          quietError: true,
+          allowMultiple: true,
+        }
+        // For some providers, the API doesn't return the required fields values
+        // if those required fields are sent in env data,
+        // so to retrieve those values a request without env data must be made
+        await providerStore.getOptionsValues(getOptionsValuesConfig)
+        await providerStore.getOptionsValues({
+          ...getOptionsValuesConfig,
+          envData: optionsType === 'source' ? details.source_environment : details.destination_environment,
+        })
       }
       }
-      // For some providers, the API doesn't return the required fields values
-      // if those required fields are sent in env data,
-      // so to retrieve those values a request without env data must be made
-      await providerStore.getOptionsValues(getOptionsValuesConfig)
-      await providerStore.getOptionsValues({
-        ...getOptionsValuesConfig,
-        envData: details.destination_environment,
-      })
+
+      loadOptions('source')
+      loadOptions('destination')
     }
     }
     loadMigration()
     loadMigration()
 
 
@@ -326,6 +333,10 @@ class MigrationDetailsPage extends React.Component<Props, State> {
             item={migrationStore.migrationDetails}
             item={migrationStore.migrationDetails}
             instancesDetails={instanceStore.instancesDetails}
             instancesDetails={instanceStore.instancesDetails}
             instancesDetailsLoading={instanceStore.loadingInstancesDetails}
             instancesDetailsLoading={instanceStore.loadingInstancesDetails}
+            sourceSchema={providerStore.sourceSchema}
+            sourceSchemaLoading={providerStore.sourceSchemaLoading
+              || providerStore.sourceOptionsPrimaryLoading
+              || providerStore.sourceOptionsSecondaryLoading}
             destinationSchema={providerStore.destinationSchema}
             destinationSchema={providerStore.destinationSchema}
             destinationSchemaLoading={providerStore.destinationSchemaLoading
             destinationSchemaLoading={providerStore.destinationSchemaLoading
               || providerStore.destinationOptionsPrimaryLoading
               || providerStore.destinationOptionsPrimaryLoading

+ 35 - 24
src/components/pages/ReplicaDetailsPage/ReplicaDetailsPage.jsx

@@ -98,33 +98,40 @@ class ReplicaDetailsPage extends React.Component<Props, State> {
       if (!details) {
       if (!details) {
         return
         return
       }
       }
-      let endpoint = endpointStore.endpoints.find(e => e.id === details.destination_endpoint_id)
-      if (!endpoint) {
+      let sourceEndpoint = endpointStore.endpoints.find(e => e.id === details.origin_endpoint_id)
+      let destinationEndpoint = endpointStore.endpoints.find(e => e.id === details.destination_endpoint_id)
+      if (!sourceEndpoint || !destinationEndpoint) {
         return
         return
       }
       }
-      // This allows the values to be displayed with their allocated names instead of their IDs
-      await providerStore.loadOptionsSchema({
-        providerName: endpoint.type,
-        optionsType: 'destination',
-        useCache: true,
-        quietError: true,
-      })
-      let getOptionsValuesConfig = {
-        optionsType: 'destination',
-        endpointId: details.destination_endpoint_id,
-        providerName: endpoint.type,
-        useCache: true,
-        quietError: true,
-        allowMultiple: true,
+      const loadOptions = async (optionsType: 'source' | 'destination') => {
+        let providerName = optionsType === 'source' ? sourceEndpoint.type : destinationEndpoint.type
+        // This allows the values to be displayed with their allocated names instead of their IDs
+        await providerStore.loadOptionsSchema({
+          providerName,
+          optionsType,
+          useCache: true,
+          quietError: true,
+        })
+        let getOptionsValuesConfig = {
+          optionsType,
+          endpointId: optionsType === 'source' ? details.origin_endpoint_id : details.destination_endpoint_id,
+          providerName,
+          useCache: true,
+          quietError: true,
+          allowMultiple: true,
+        }
+        // For some providers, the API doesn't return the required fields values
+        // if those required fields are sent in env data,
+        // so to retrieve those values a request without env data must be made
+        await providerStore.getOptionsValues(getOptionsValuesConfig)
+        await providerStore.getOptionsValues({
+          ...getOptionsValuesConfig,
+          envData: optionsType === 'source' ? details.source_environment : details.destination_environment,
+        })
       }
       }
-      // For some providers, the API doesn't return the required fields values
-      // if those required fields are sent in env data,
-      // so to retrieve those values a request without env data must be made
-      await providerStore.getOptionsValues(getOptionsValuesConfig)
-      await providerStore.getOptionsValues({
-        ...getOptionsValuesConfig,
-        envData: details.destination_environment,
-      })
+
+      loadOptions('source')
+      loadOptions('destination')
     }
     }
     loadReplica()
     loadReplica()
 
 
@@ -495,6 +502,10 @@ class ReplicaDetailsPage extends React.Component<Props, State> {
             scheduleStore={scheduleStore}
             scheduleStore={scheduleStore}
             networks={networkStore.networks}
             networks={networkStore.networks}
             detailsLoading={replicaStore.detailsLoading || endpointStore.loading}
             detailsLoading={replicaStore.detailsLoading || endpointStore.loading}
+            sourceSchema={providerStore.sourceSchema}
+            sourceSchemaLoading={providerStore.sourceSchemaLoading
+              || providerStore.sourceOptionsPrimaryLoading
+              || providerStore.sourceOptionsSecondaryLoading}
             destinationSchema={providerStore.destinationSchema}
             destinationSchema={providerStore.destinationSchema}
             destinationSchemaLoading={providerStore.destinationSchemaLoading
             destinationSchemaLoading={providerStore.destinationSchemaLoading
               || providerStore.destinationOptionsPrimaryLoading
               || providerStore.destinationOptionsPrimaryLoading

+ 3 - 0
src/types/Field.js

@@ -15,6 +15,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 // @flow
 // @flow
 
 
 import { OptionsSchemaPlugin } from '../plugins/endpoint'
 import { OptionsSchemaPlugin } from '../plugins/endpoint'
+import LabelDictionary from '../utils/LabelDictionary'
 
 
 export type Field = {
 export type Field = {
   name: string,
   name: string,
@@ -79,6 +80,8 @@ class FieldHelper {
         let enumObject = field.enum.find(e => e.id ? e.id === v : false)
         let enumObject = field.enum.find(e => e.id ? e.id === v : false)
         if (enumObject && enumObject.name) {
         if (enumObject && enumObject.name) {
           valueName = enumObject.name
           valueName = enumObject.name
+        } else if (field && LabelDictionary.enumFields.find(f => field && f === field.name)) {
+          valueName = LabelDictionary.get(v)
         }
         }
       }
       }
       return valueName
       return valueName