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

Add 'Used in ...' info to endpoint details page

It shows in how many replicas/migrations the endpoint is used and their
names.
This new field and the 'description' field is not ellipsed like the
other fields, instead they are rendered on multiple lines if they don't
fit in one line.
Sergiu Miclea 8 лет назад
Родитель
Сommit
e19ef98413

+ 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() }}