Просмотр исходного кода

Merge pull request #200 from smiclea/endpoint-usage

Add 'Used in ...' info to endpoint details page
Dorin Paslaru 8 лет назад
Родитель
Сommit
eb8bf6ecb2

+ 44 - 4
src/components/organisms/EndpointDetailsContent/index.jsx

@@ -23,8 +23,12 @@ import PasswordValue from '../../atoms/PasswordValue'
 import Button from '../../atoms/Button'
 import CopyValue from '../../atoms/CopyValue'
 import StatusImage from '../../atoms/StatusImage'
+import CopyButton from '../../atoms/CopyButton'
+import NotificationStore from '../../../stores/NotificationStore'
+import DomUtils from '../../../utils/DomUtils'
 
 import type { Endpoint } from '../../../types/Endpoint'
+import type { MainItem } from '../../../types/MainItem'
 import StyleProps from '../../styleUtils/StyleProps'
 import Palette from '../../styleUtils/Palette'
 import DateUtils from '../../../utils/DateUtils'
@@ -36,14 +40,15 @@ const Wrapper = styled.div`
   padding-left: 126px;
 `
 const Info = styled.div`
-  margin-top: 32px;
   display: flex;
   flex-wrap: wrap;
+  margin-top: 32px;
+  margin-left: -32px;  
 `
 const Field = styled.div`
+  ${StyleProps.exactWidth('calc(50% - 32px)')}
   margin-bottom: 32px;
-  min-width: 50%;
-  max-width: 50%;
+  margin-left: 32px;  
 `
 const Label = styled.div`
   font-size: 10px;
@@ -53,6 +58,17 @@ const Label = styled.div`
   margin-bottom: 3px;
 `
 const Value = styled.div``
+const MultilineValue = styled.div`
+  cursor: pointer;
+
+  &:hover > span {
+    opacity: 1;
+  }
+  > span {
+    background-position-y: 4px;
+    margin-left: 4px;
+  }
+`
 const Buttons = styled.div`
   display: flex;
   justify-content: space-between;
@@ -76,6 +92,7 @@ type Props = {
   item: ?Endpoint,
   connectionInfo: ?$PropertyType<Endpoint, 'connection_info'>,
   loading: boolean,
+  usage: { migrations: MainItem[], replicas: MainItem[] },
   onDeleteClick: () => void,
   onValidateClick: () => void,
   onEditClick: () => void,
@@ -84,6 +101,14 @@ type Props = {
 class EndpointDetailsContent extends React.Component<Props> {
   renderedKeys: { [string]: boolean }
 
+  handleCopy(text: string) {
+    let succesful = DomUtils.copyTextToClipboard(text)
+
+    if (succesful) {
+      NotificationStore.notify('The message has been copied to clipboard.')
+    }
+  }
+
   renderConnectionInfoLoading() {
     if (!this.props.loading) {
       return null
@@ -157,6 +182,15 @@ class EndpointDetailsContent extends React.Component<Props> {
     )
   }
 
+  renderMultilineValue(value: string, dataTestId?: string) {
+    return (
+      <MultilineValue onClick={() => { this.handleCopy(value) }} data-test-id={dataTestId}>
+        {value}
+        <CopyButton />
+      </MultilineValue>
+    )
+  }
+
   renderValue(value: string, dataTestId?: string) {
     return <CopyValue data-test-id={dataTestId} value={value} maxWidth="90%" />
   }
@@ -164,6 +198,8 @@ class EndpointDetailsContent extends React.Component<Props> {
   render() {
     this.renderedKeys = {}
     const { type, name, description, created_at } = this.props.item || {}
+    const usage = this.props.usage.replicas.concat(this.props.usage.migrations)
+
     return (
       <Wrapper>
         <EndpointLogos endpoint={type} />
@@ -178,12 +214,16 @@ class EndpointDetailsContent extends React.Component<Props> {
           </Field>
           <Field>
             <Label>Description</Label>
-            {description ? this.renderValue(description, 'description') : <Value>-</Value>}
+            {description ? this.renderMultilineValue(description, 'description') : <Value>-</Value>}
           </Field>
           <Field>
             <Label>Created</Label>
             {this.renderValue(DateUtils.getLocalTime(created_at).format('DD/MM/YYYY HH:mm'), 'created')}
           </Field>
+          <Field>
+            <Label>Used in replicas/migrations ({usage.length})</Label>
+            {usage.length > 0 ? this.renderMultilineValue(usage.map(i => i.instances.join(', ')).join(', ')) : <Value>-</Value>}
+          </Field>
           {this.renderConnectionInfoLoading()}
           {this.renderConnectionInfo(this.props.connectionInfo)}
         </Info>

+ 16 - 8
src/components/pages/EndpointDetailsPage/index.jsx

@@ -32,6 +32,7 @@ import MigrationStore from '../../../stores/MigrationStore'
 import ReplicaStore from '../../../stores/ReplicaStore'
 import UserStore from '../../../stores/UserStore'
 import type { Endpoint as EndpointType } from '../../../types/Endpoint'
+import type { MainItem } from '../../../types/MainItem'
 
 import endpointImage from './images/endpoint.svg'
 
@@ -46,6 +47,7 @@ type State = {
   showEndpointModal: boolean,
   showEndpointInUseModal: boolean,
   showEndpointInUseLoadingModal: boolean,
+  endpointUsage: {replicas: MainItem[], migrations: MainItem[]}
 }
 @observer
 class EndpointDetailsPage extends React.Component<Props, State> {
@@ -58,6 +60,7 @@ class EndpointDetailsPage extends React.Component<Props, State> {
       showEndpointModal: false,
       showEndpointInUseModal: false,
       showEndpointInUseLoadingModal: false,
+      endpointUsage: { replicas: [], migrations: [] },
     }
   }
 
@@ -75,14 +78,14 @@ class EndpointDetailsPage extends React.Component<Props, State> {
     return EndpointStore.endpoints.find(e => e.id === this.props.match.params.id) || null
   }
 
-  getEndpointUsage() {
+  getEndpointUsage(): {migrations: MainItem[], replicas: MainItem[]} {
     let endpointId = this.props.match.params.id
-    let replicasCount = ReplicaStore.replicas.filter(
-      r => r.origin_endpoint_id === endpointId || r.destination_endpoint_id === endpointId).length
-    let migrationsCount = MigrationStore.migrations.filter(
-      r => r.origin_endpoint_id === endpointId || r.destination_endpoint_id === endpointId).length
+    let replicas = ReplicaStore.replicas.filter(
+      r => r.origin_endpoint_id === endpointId || r.destination_endpoint_id === endpointId)
+    let migrations = MigrationStore.migrations.filter(
+      r => r.origin_endpoint_id === endpointId || r.destination_endpoint_id === endpointId)
 
-    return { migrationsCount, replicasCount }
+    return { migrations, replicas }
   }
 
   handleUserItemClick(item: { value: string }) {
@@ -105,9 +108,9 @@ class EndpointDetailsPage extends React.Component<Props, State> {
     this.setState({ showEndpointInUseLoadingModal: true })
 
     Promise.all([ReplicaStore.getReplicas(), MigrationStore.getMigrations()]).then(() => {
-      let endpointUsage = this.getEndpointUsage()
+      const endpointUsage = this.getEndpointUsage()
 
-      if (endpointUsage.migrationsCount === 0 && endpointUsage.replicasCount === 0) {
+      if (endpointUsage.migrations.length === 0 && endpointUsage.replicas.length === 0) {
         this.setState({ showDeleteEndpointConfirmation: true, showEndpointInUseLoadingModal: false })
       } else {
         this.setState({ showEndpointInUseModal: true, showEndpointInUseLoadingModal: false })
@@ -174,6 +177,10 @@ class EndpointDetailsPage extends React.Component<Props, State> {
         EndpointStore.setConnectionInfo(endpoint.connection_info)
       }
     })
+
+    Promise.all([ReplicaStore.getReplicas(), MigrationStore.getMigrations()]).then(() => {
+      this.setState({ endpointUsage: this.getEndpointUsage() })
+    })
   }
 
   render() {
@@ -194,6 +201,7 @@ class EndpointDetailsPage extends React.Component<Props, State> {
           />}
           contentComponent={<EndpointDetailsContent
             item={endpoint}
+            usage={this.state.endpointUsage}
             loading={EndpointStore.connectionInfoLoading || EndpointStore.loading}
             connectionInfo={EndpointStore.connectionInfo}
             onDeleteClick={() => { this.handleDeleteEndpointClick() }}