#50323 Ticket 50291 - Add monitor tab functionality to Cockpit UI
Closed 2 years ago by spichugi. Opened 3 years ago by mreynolds.
mreynolds/389-ds-base ticket50291  into  master

@@ -106,7 +106,7 @@ 

  }

  

  .ds-chart-right {

-     margin-left: 90px;

+     margin-left: 65px;

  }

  

  .ds-chart-left {
@@ -233,6 +233,25 @@ 

      line-height: 1;

  }

  

+ .ds-refresh {

+     background-color: #0088ce;

+     background-image: linear-gradient(to bottom,#39a5dc 0,#0088ce 100%);

+     filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff39a5dc', endColorstr='#ff0088ce', GradientType=0);

+     border-color: #00659c;

+     color: #fff;

+     padding: 3px;

+     box-shadow: 0 2px 3px rgba(3,3,3,.1);

+     border-radius: 50%;

+     border: 1px solid transparent;

+     font-size: 13px !important;

+ }

+ 

+ .ds-refresh:hover {

+     color: DarkGray;

+     background-color: white;

+     background-image: none;

+ }

+ 

  .dataTables_wrapper {

      padding: 0px !important;

      margin-bottom: 10px !important;
@@ -241,7 +260,7 @@ 

  td {

      white-space: normal;

      word-wrap: break-word !important;

-     max-width: 400px !important;

+     max-width: 200px !important;

  }

  

  .ds-hr {
@@ -339,6 +358,12 @@ 

      padding-left: 5px;

  }

  

+ .ds-input-auto-good {

+     width: 100%;

+     border-color: green;

+     padding-left: 5px;

+ }

+ 

  .ds-input-right {

      text-align: right;

  }
@@ -385,6 +410,10 @@ 

      max-width: 600px;

  }

  

+ .ds-lag-report {

+     min-width: 800px !important;

+ }

+ 

  .ds-repl-mgr {

      max-width: 600px !important;

  }
@@ -578,10 +607,7 @@ 

  }

  

  .ds-db-table {

-     background-color: white !important;

-     padding: 0px;

-     border: 1px solid #909090;

-     clear: both;

+     border: 1px solid #d1d1d1;

      word-wrap: break-word !important;

      text-align: center;

  }
@@ -599,7 +625,6 @@ 

  

  .ds-table-header th {

      text-align: center !important;

-     background-color: white;

  }

  

  .ds-plugin-table {
@@ -1058,13 +1083,13 @@ 

      vertical-align: top;

      width: 315px;

      height: 80px;

-     resize: none;

      word-wrap: break-word !important;

      line-height: 1;

  }

  

  .ds-agmt-textarea {

      width: 100%;

+     font-family: monospace !important;

  }

  

  .ds-logarea {
@@ -1072,23 +1097,14 @@ 

      padding-top: 5px;

      vertical-align: top;

      width: 100% !important;

-     height: 600px !important;

+     height: 500px;

      max-height: 600px !important;

-     resize: none;

      word-wrap: break-word !important;

      line-height: 1;

      font-family: monospace !important;

      overflow-y: scroll;

  }

  

- /* Removes dotted outline border of the text */

- select {

-     text-shadow: 0 0 0 #000 !important;

-     max-height: 200px !important;

-     line-height: 1;

-     padding: 5px;

- }

- 

  option {

      color: #181818;

  }
@@ -1137,24 +1153,28 @@ 

      float: left;

  }

  

- .ds-footer {

-     background-color: #e5e5e5 !important;

+ .ds-footer{

+     background-color: #f5f5f5 !important;

      margin-left: -25px;

      padding: 10px;

      position: fixed;

      bottom: 0;

      width: 100%;

      height: 50px;

-     border-top: 1px solid #999 !important;

+     border-top: 1px solid #e2e2e2 !important;

  }

  

- .ds-modal-footer {

+ .modal-footer {

      background-color: #f5f5f5 !important;

      padding: 10px;

      bottom: 0;

      width: 100%;

      height: 50px;

-     border-top: 1px solid #999 !important;

+     border-top: .5px solid #e2e2e2 !important;

+ }

+ 

+ .modal-header {

+     border-bottom: .5px solid #e2e2e2 !important;

  }

  

  .ds-nav-bar {
@@ -1226,6 +1246,13 @@ 

      margin-top: 10px;

  }

  

+ .ds-margin-top-sm {

+     margin-top: 9px;

+ }

+ .ds-margin-top-med {

+     margin-top: 15px !important;

+ }

+ 

  .ds-margin-top-lg {

      margin-top: 20px !important;

  }
@@ -1406,6 +1433,10 @@ 

      margin-left: 40px !important;

  }

  

+ .ds-margin-left-piechart {

+     margin-left: 130px !important;

+ }

+ 

  .ds-nested-modal {

      margin-top: 100px;

      margin-left: 100px;
@@ -1466,10 +1497,6 @@ 

      position: relative;

  }

  

- tbody:nth-child(even) {

-     background: #f1f1f1;

- }

- 

  .ds-toolbar {

      bottom: 10px;

  }
@@ -1546,8 +1573,7 @@ 

  }

  

  .ds-table-pagination {

-     background-color: transparent !important;

-     border: 1px solid #909090;

+     border: 1px solid #d1d1d1;

  }

  

  .ds-vlv-label {
@@ -1587,12 +1613,16 @@ 

      margin-bottom: 15px;

  }

  

+ .ds-header {

+     font-size: 16px;

+ }

+ 

  .ds-no-padding () {

      padding: 0 !imporant;

  }

  

  .alert {

-     max-width: 600px;

+     max-width: 750px;

  }

  

  .ds-confirm {
@@ -1622,3 +1652,11 @@ 

      border-color: #bee1f4;

      display: block;

  }

+ 

+ input {

+     padding-left: 5px !important;

+ }

+ 

+ .ds-width-auto {

+     width: 100%;

+ }

@@ -185,9 +185,10 @@ 

                          }), this.setState({configUpdated: 0}));

                  })

                  .fail(err => {

+                     let errMsg = JSON.parse(err);

                      this.addNotification(

                          "error",

-                         `Error loading database configuration - ${err}`

+                         `Error loading database configuration - ${errMsg.desc}`

                      );

                  });

      }
@@ -271,9 +272,10 @@ 

                      ), this.loadAvailableControls());

                  })

                  .fail(err => {

+                     let errMsg = JSON.parse(err);

                      this.addNotification(

                          "error",

-                         `Error loading default chaining configuration - ${err}`

+                         `Error loading default chaining configuration - ${errMsg.desc}`

                      );

                      this.setState({

                          loading: false
@@ -430,9 +432,10 @@ 

                      });

                  })

                  .fail(err => {

+                     let errMsg = JSON.parse(err);

                      this.addNotification(

                          "error",

-                         `Error getting chaining link configuration - ${err}`

+                         `Error getting chaining link configuration - ${errMsg.desc}`

                      );

                  });

      }
@@ -615,9 +618,10 @@ 

                      this.loadSuffixTree(false);

                  })

                  .fail(err => {

+                     let errMsg = JSON.parse(err);

                      this.addNotification(

                          "error",

-                         `Error creating suffix - ${err}`

+                         `Error creating suffix - ${errMsg.desc}`

                      );

                      this.closeSuffixModal();

                  });
@@ -774,9 +778,10 @@ 

                      });

                  })

                  .fail(err => {

+                     let errMsg = JSON.parse(err);

                      this.addNotification(

                          "error",

-                         `Error loading indexes for ${suffix} - ${err}`

+                         `Error loading indexes for ${suffix} - ${errMsg.desc}`

                      );

                  });

      }
@@ -816,7 +821,7 @@ 

              "dsconf", "-j", "ldapi://%2fvar%2frun%2fslapd-" + this.props.serverId + ".socket",

              "backend", "suffix", "get", suffix

          ];

-         log_cmd("loadSuffixConfig", "Load suffix config", cmd);

+         log_cmd("loadSuffix", "Load suffix config", cmd);

          cockpit

                  .spawn(cmd, { superuser: true, err: "message" })

                  .done(content => {
@@ -928,9 +933,10 @@ 

                                                          });

                                                      })

                                                      .fail(err => {

+                                                         let errMsg = JSON.parse(err);

                                                          this.addNotification(

                                                              "error",

-                                                             `Error loading indexes for ${suffix} - ${err}`

+                                                             `Error loading indexes for ${suffix} - ${errMsg.desc}`

                                                          );

                                                          this.setState({

                                                              suffixLoading: false
@@ -999,9 +1005,10 @@ 

                      });

                  })

                  .fail(err => {

+                     let errMsg = JSON.parse(err);

                      this.addNotification(

                          "error",

-                         `Failed to get attributes - ${err}`

+                         `Failed to get attributes - ${errMsg.desc}`

                      );

                  });

      }

@@ -13,7 +13,7 @@ 

  var repl_page_loaded = 0;

  var plugin_page_loaded = 1;

  var schema_page_loaded = 0;

- var monitor_page_loaded = 0;

+ var monitor_page_loaded = 1;

  var config_loaded = 0;

  

  // objects to store original values (used for comparing what changed when saving
@@ -118,18 +118,50 @@ 

  

  function get_date_string (timestamp) {

    // Convert DS timestamp to a friendly string: 20180921142257Z -> 10/21/2018, 2:22:57 PM

-   var year = timestamp.substr(0,4);

-   var month = timestamp.substr(4,2);

-   var day = timestamp.substr(6,2);

-   var hour = timestamp.substr(8,2);

-   var minute = timestamp.substr(10,2);

-   var sec = timestamp.substr(12,2);

-   var date = new Date(parseInt(year), parseInt(month), parseInt(day),

+   let year = timestamp.substr(0,4);

+   let month = timestamp.substr(4,2);

+   let day = timestamp.substr(6,2);

+   let hour = timestamp.substr(8,2);

+   let minute = timestamp.substr(10,2);

+   let sec = timestamp.substr(12,2);

+   let date = new Date(parseInt(year), parseInt(month), parseInt(day),

                        parseInt(hour), parseInt(minute), parseInt(sec));

  

    return date.toLocaleString();

  }

  

+ function get_date_diff(start, end) {

You've added the function here and in tools.jsx. But this one is unused in your code... Was it done for some future code?

+     // Get the start up date

+     let year = start.substr(0,4);

+     let month = start.substr(4,2);

+     let day = start.substr(6,2);

+     let hour = start.substr(8,2);

+     let minute = start.substr(10,2);

+     let sec = start.substr(12,2);

+     let startDate = new Date(parseInt(year), parseInt(month), parseInt(day),

+                              parseInt(hour), parseInt(minute), parseInt(sec));

+ 

+     // Get the servers current date

+     year = end.substr(0,4);

+     month = end.substr(4,2);

+     day = end.substr(6,2);

+     hour = end.substr(8,2);

+     minute = end.substr(10,2);

+     sec = end.substr(12,2);

+     let currDate = new Date(parseInt(year), parseInt(month), parseInt(day),

+                             parseInt(hour), parseInt(minute), parseInt(sec));

+ 

+     // Generate pretty elapsed time string

+     let seconds = Math.floor((startDate - (currDate))/1000);

+     let minutes = Math.floor(seconds/60);

+     let hours = Math.floor(minutes/60);

+     let days = Math.floor(hours/24);

+     hours = hours-(days*24);

+     minutes = minutes-(days*24*60)-(hours*60);

+     seconds = seconds-(days*24*60*60)-(hours*60*60)-(minutes*60);

+ 

+     return("${days} days, ${hours} hours, ${minutes} minutes, and ${seconds} seconds");

+ }

  

  

  function set_no_insts () {
@@ -446,4 +478,8 @@ 

      $(".all-pages").hide();

      $("#database-content").show();

    });

+   $("#monitor-tab").on("click", function() {

+     $(".all-pages").hide();

+     $("#monitor-content").show();

+   });

  });

@@ -2,6 +2,7 @@ 

  import ReactDOM from "react-dom";

  import { Plugins } from "./plugins.jsx";

  import { Database } from "./database.jsx";

+ import { Monitor } from "./monitor.jsx";

  

  var serverIdElem;

  
@@ -15,19 +16,25 @@ 

                  .value.replace("slapd-", "");

      }

      let d = new Date();

-     let n = d.getTime(); // might not be needed MARK

+     let tabKey = d.getTime();

  

      // Plugins Tab

      ReactDOM.render(

-         <Plugins serverId={serverIdElem} key={n} />,

+         <Plugins serverId={serverIdElem} key={tabKey} />,

          document.getElementById("plugins")

      );

  

      // Database tab

      ReactDOM.render(

-         <Database serverId={serverIdElem} key={n} />,

+         <Database serverId={serverIdElem} key={tabKey} />,

          document.getElementById("database")

      );

+ 

+     // Monitor tab

+     ReactDOM.render(

+         <Monitor serverId={serverIdElem} key={tabKey} />,

+         document.getElementById("monitor")

+     );

  }

  

  // We have to create the wrappers because this is no simple way

@@ -23,7 +23,6 @@ 

    <script src="servers.js"></script>

    <script src="security.js"></script>

    <script src="replication.js"></script>

-   <script src="monitor.js"></script>

    <link href="static/bootstrap.min.css" rel="stylesheet">

    <link href="static/jquery.dataTables.min.css" type="text/css" rel="stylesheet">

    <link href="static/jquery.timepicker.min.css" type="text/css" rel="stylesheet">
@@ -117,7 +116,7 @@ 

                  <li><a href="#0" class="ds-nav-choice" id="repl-config-btn" parent-id="replication-tab">Configuration</a></li>

                  <li><a href="#0" class="ds-nav-choice" id="repl-agmts-btn" parent-id="replication-tab">Agreements</a></li>

                  <li><a href="#0" class="ds-nav-choice" id="repl-winsync-btn" parent-id="replication-tab">Winsync Agreements</a></li>

-                 <li><a href="#0" class="ds-nav-choice" id="repl-cleanallruv-btn" parent-id="replication-tab">CleanAllRUV Tasks</a></li>

+                 <li><a href="#0" class="ds-nav-choice" id="repl-tasks-btn" parent-id="replication-tab">Replication Tasks</a></li>

                </ul>

              </li>

  
@@ -142,26 +141,10 @@ 

              </li>

  

              <!-- Monitoring navtab -->

-             <li class="dropdown ds-nav-tab">

-               <a href="#0" class="dropdown-toggle ds-tab-list" data-toggle="dropdown" id="monitor-tab">

+             <li class="ds-nav-tab">

+               <a href="#0" class="ds-tab-list ds-tab-standalone"id="monitor-tab">

                  Monitoring

-                 <b class="caret"></b>

                </a>

-               <ul class="dropdown-menu ds-nav-item">

-                 <li><a tabindex="-1" id="monitor-db-btn" class="ds-nav-choice"  parent-id="monitor-tab" href="#0">Database Performance</a></li>

-                 <li class="dropdown-submenu">

-                   <a tabindex="-1" href="#0">Logging</a>

-                   <ul class="dropdown-menu">

-                     <li><a href="#0" class="ds-nav-choice" id="monitor-log-access-btn"    parent-id="monitor-tab">Access Log</a></li>

-                     <li><a href="#0" class="ds-nav-choice" id="monitor-log-audit-btn"     parent-id="monitor-tab">Audit Log</a></li>

-                     <li><a href="#0" class="ds-nav-choice" id="monitor-log-auditfail-btn" parent-id="monitor-tab">Audit Failure Log</a></li>

-                     <li><a href="#0" class="ds-nav-choice" id="monitor-log-errors-btn"    parent-id="monitor-tab">Errors Log</a></li>

-                   </ul>

-                 </li>

-                 <li><a tabindex="-1" class="ds-nav-choice" parent-id="monitor-tab" id="monitor-repl-btn"   href="#0">Replication</a></li>

-                 <li><a tabindex="-1" class="ds-nav-choice" parent-id="monitor-tab" id="monitor-server-btn" href="#0">Server Statistics</a></li>

-                 <li><a tabindex="-1" class="ds-nav-choice" parent-id="monitor-tab" id="monitor-snmp-btn"   href="#0">SNMP Counters</a></li>

-               </ul>

              </li>

            </ul>

          </div>
@@ -281,7 +264,7 @@ 

                <p><span class="spinner spinner-xs spinner-inline"></span> Reloading schema files...</p>

              </div>

            </div>

-           <div class="modal-footer ds-modal-footer">

+           <div class="modal-footer">

              <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>

              <button type="button" class="btn btn-primary" id ="schema-reload-btn">Reload Schema</button>

            </div>
@@ -320,7 +303,7 @@ 

                <p><span class="spinner spinner-xs spinner-inline"></span> Restoring the server...</p>

              </div>

            </div>

-           <div class="modal-footer ds-modal-footer">

+           <div class="modal-footer">

              <button type="button" class="btn btn-primary" data-dismiss="modal">Close</button>

            </div>

          </div>
@@ -382,7 +365,7 @@ 

                </div>

              </form>

            </div>

-           <div class="modal-footer ds-modal-footer">

+           <div class="modal-footer">

              <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>

              <button type="button" class="btn btn-primary" id="chaining-save">Create Link</button>

            </div>
@@ -455,7 +438,7 @@ 

                </div>

              </form>

            </div>

-           <div class="modal-footer ds-modal-footer">

+           <div class="modal-footer">

              <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>

              <button type="button" class="btn btn-primary" id="create-inst-save">Create Instance</button>

            </div>
@@ -487,7 +470,7 @@ 

                <p><span class="spinner spinner-xs spinner-inline"></span> Backing up the server...</p>

              </div>

            </div>

-           <div class="modal-footer ds-modal-footer">

+           <div class="modal-footer">

              <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>

              <button type="button" class="btn btn-primary" id="ds-backup-btn">Do Backup</button>

            </div>
@@ -535,6 +518,7 @@ 

        </div>

  

        <div id="monitor-content" class="all-pages" hidden>

+           <div id="monitor"></div>

        </div>

  

      </div>

@@ -74,10 +74,11 @@ 

                      );

                  })

                  .fail(err => {

+                     let errMsg = JSON.parse(err);

                      this.props.reload(this.props.suffix);

                      this.props.addNotification(

                          "error",

-                         `Failed to delete encrypted attribute - ${err}`

+                         `Failed to delete encrypted attribute - ${errMsg.desc}`

                      );

                  });

      }
@@ -98,10 +99,11 @@ 

                      );

                  })

                  .fail(err => {

+                     let errMsg = JSON.parse(err);

                      this.props.reload(this.props.suffix);

                      this.props.addNotification(

                          "error",

-                         `Failure deleting encrypted attribute - ${err}`

+                         `Failure deleting encrypted attribute - ${errMsg.desc}`

                      );

                  });

      }

@@ -251,10 +251,11 @@ 

                      );

                  })

                  .fail(err => {

+                     let errMsg = JSON.parse(err);

                      this.closeLDIFSpinningModal();

                      this.props.addNotification(

                          "error",

-                         `Failure importing LDIF - ${err}`

+                         `Failure importing LDIF - ${errMsg.desc}`

                      );

                  });

      }
@@ -277,11 +278,12 @@ 

                      );

                  })

                  .fail(err => {

+                     let errMsg = JSON.parse(err);

                      this.props.reload();

                      this.closeLDIFDeleteSpinningModal();

                      this.props.addNotification(

                          "error",

-                         `Failure deleting LDIF file - ${err}`

+                         `Failure deleting LDIF file - ${errMsg.desc}`

                      );

                  });

      }
@@ -312,11 +314,12 @@ 

                      );

                  })

                  .fail(err => {

+                     let errMsg = JSON.parse(err);

                      this.props.reload();

                      this.closeBackupModal();

                      this.props.addNotification(

                          "error",

-                         `Failure backing up server - ${err}`

+                         `Failure backing up server - ${errMsg.desc}`

                      );

                  });

      }
@@ -339,10 +342,11 @@ 

                      );

                  })

                  .fail(err => {

+                     let errMsg = JSON.parse(err);

                      this.closeRestoreSpinningModal();

                      this.props.addNotification(

                          "error",

-                         `Failure restoring up server - ${err}`

+                         `Failure restoring up server - ${errMsg.desc}`

                      );

                  });

      }
@@ -366,11 +370,12 @@ 

                      );

                  })

                  .fail(err => {

+                     let errMsg = JSON.parse(err);

                      this.props.reload();

                      this.closeDelBackupSpinningModal();

                      this.props.addNotification(

                          "error",

-                         `Failure deleting backup - ${err}`

+                         `Failure deleting backup - ${errMsg.desc}`

                      );

                  });

      }
@@ -432,11 +437,12 @@ 

                      });

                  })

                  .fail(err => {

+                     let errMsg = JSON.parse(err);

                      this.props.reload();

                      this.closeExportModal();

                      this.props.addNotification(

                          "error",

-                         `Error exporting database - ${err}`

+                         `Error exporting database - ${errMsg.desc}`

                      );

                      this.setState({

                          showExportModal: false,

@@ -195,10 +195,11 @@ 

                          );

                      })

                      .fail(err => {

+                         let errMsg = JSON.parse(err);

                          this.props.reload();

                          this.props.addNotification(

                              "error",

-                             `Error updating chaining configuration - ${err}`

+                             `Error updating chaining configuration - ${errMsg.desc}`

                          );

                      });

          }
@@ -255,10 +256,11 @@ 

                      );

                  })

                  .fail(err => {

+                     let errMsg = JSON.parse(err);

                      this.props.reload();

                      this.props.addNotification(

                          "error",

-                         `Error updating chaining controls - ${err}`

+                         `Error updating chaining controls - ${errMsg.desc}`

                      );

                  });

      }
@@ -298,10 +300,11 @@ 

                      );

                  })

                  .fail(err => {

+                     let errMsg = JSON.parse(err);

                      this.props.reload();

                      this.props.addNotification(

                          "error",

-                         `Error removing chaining controls - ${err}`

+                         `Error removing chaining controls - ${errMsg.desc}`

                      );

                  });

      }
@@ -370,10 +373,11 @@ 

                      );

                  })

                  .fail(err => {

+                     let errMsg = JSON.parse(err);

                      this.props.reload();

                      this.props.addNotification(

                          "error",

-                         `Error updating chaining components - ${err}`

+                         `Error updating chaining components - ${errMsg.desc}`

                      );

                  });

      }
@@ -400,10 +404,11 @@ 

                      );

                  })

                  .fail(err => {

+                     let errMsg = JSON.parse(err);

                      this.props.reload();

                      this.props.addNotification(

                          "error",

-                         `Error removing chaining components - ${err}`

+                         `Error removing chaining components - ${errMsg.desc}`

                      );

                  });

      }
@@ -832,10 +837,11 @@ 

                          );

                      })

                      .fail(err => {

+                         let errMsg = JSON.parse(err);

                          this.props.reload(this.props.suffix);

                          this.props.addNotification(

                              "error",

-                             `Failed to update link configuration - ${err}`

+                             `Failed to update link configuration - ${errMsg.desc}`

                          );

                      });

          }
@@ -857,10 +863,11 @@ 

                      );

                  })

                  .fail(err => {

+                     let errMsg = JSON.parse(err);

                      this.props.loadSuffixTree(true);

                      this.props.addNotification(

                          "error",

-                         `Failed to delete database link - ${err}`

+                         `Failed to delete database link - ${errMsg.desc}`

                      );

                  });

      }
@@ -1160,7 +1167,7 @@ 

                              </div>

                          </Form>

                      </Modal.Body>

-                     <Modal.Footer className="ds-modal-footerZZZ">

+                     <Modal.Footer>

                          <Button

                              bsStyle="default"

                              className="btn-cancel"
@@ -1221,7 +1228,7 @@ 

                              </div>

                          </Form>

                      </Modal.Body>

-                     <Modal.Footer className="ds-modal-footer">

+                     <Modal.Footer>

                          <Button

                              bsStyle="default"

                              className="btn-cancel"

@@ -190,10 +190,11 @@ 

                          );

                      })

                      .fail(err => {

+                         let errMsg = JSON.parse(err);

                          this.props.reload();

                          this.props.addNotification(

                              "error",

-                             `Error updating configuration - ${err}`

+                             `Error updating configuration - ${errMsg.desc}`

                          );

                      });

          }
@@ -370,7 +371,7 @@ 

                              <p />

                          </div>

                      </CustomCollapse>

-                     <hr />

+                     <p />

                      <div className="ds-save-btn">

                          <button className="btn btn-primary save-button"

                              onClick={this.save_db_config}>Save Configuration</button>

@@ -132,17 +132,19 @@ 

                                              }

                                          })

                                          .fail(err => {

+                                             let errMsg = JSON.parse(err);

                                              this.props.addNotification(

                                                  "error",

-                                                 `Failed to get attributes - ${err}`

+                                                 `Failed to get attributes - ${errMsg.desc}`

                                              );

                                          });

                              });

                  })

                  .fail(err => {

+                     let errMsg = JSON.parse(err);

                      this.props.addNotification(

                          "error",

-                         `Failed to get matching rules - ${err}`

+                         `Failed to get matching rules - ${errMsg.desc}`

                      );

                  });

      }
@@ -242,12 +244,12 @@ 

                      );

                  })

                  .fail(err => {

-                     // this.loadIndexes();

+                     let errMsg = JSON.parse(err);

                      this.props.reload(this.props.suffix);

                      this.closeIndexModal();

                      this.props.addNotification(

                          "error",

-                         `Error creating index - ${err}`

+                         `Error creating index - ${errMsg.desc}`

                      );

                  });

      }
@@ -328,9 +330,10 @@ 

                      });

                  })

                  .fail(err => {

+                     let errMsg = JSON.parse(err);

                      this.props.addNotification(

                          "error",

-                         `Error indexing attribute ${attr} - ${err}`

+                         `Error indexing attribute ${attr} - ${errMsg.desc}`

                      );

                  });

      }
@@ -421,11 +424,12 @@ 

                          }

                      })

                      .fail(err => {

+                         let errMsg = JSON.parse(err);

                          this.props.reload(this.props.suffix);

                          this.closeEditIndexModal();

                          this.props.addNotification(

                              "error",

-                             `Error editing index - ${err}`

+                             `Error editing index - ${errMsg.desc}`

                          );

                      });

          }
@@ -487,10 +491,11 @@ 

                      );

                  })

                  .fail(err => {

+                     let errMsg = JSON.parse(err);

                      this.props.reload(this.props.suffix);

                      this.props.addNotification(

                          "error",

-                         `Error deleting index - ${err}`

+                         `Error deleting index - ${errMsg.desc}`

                      );

                  });

      }

@@ -90,10 +90,11 @@ 

                      );

                  })

                  .fail(err => {

+                     let errMsg = JSON.parse(err);

                      this.props.reload(this.props.suffix);

                      this.props.addNotification(

                          "error",

-                         `Failure deleting referral - ${err}`

+                         `Failure deleting referral - ${errMsg.desc}`

                      );

                  });

      }
@@ -146,11 +147,12 @@ 

                      );

                  })

                  .fail(err => {

+                     let errMsg = JSON.parse(err);

                      this.props.reload(this.props.suffix);

                      this.closeRefModal();

                      this.props.addNotification(

                          "error",

-                         `Failure creating referral - ${err}`

+                         `Failure creating referral - ${errMsg.desc}`

                      );

                  });

      }

@@ -196,9 +196,10 @@ 

                      });

                  })

                  .fail(err => {

+                     let errMsg = JSON.parse(err);

                      this.props.addNotification(

                          "error",

-                         `Error importing LDIF file - ${err}`

+                         `Error importing LDIF file - ${errMsg.desc}`

                      );

                      this.setState({

                          showImportModal: false
@@ -278,10 +279,11 @@ 

                      });

                  })

                  .fail(err => {

+                     let errMsg = JSON.parse(err);

                      this.loadLDIFs();

                      this.props.addNotification(

                          "error",

-                         `Error exporting database - ${err}`

+                         `Error exporting database - ${errMsg.desc}`

                      );

                      this.setState({

                          showExportModal: false,
@@ -330,9 +332,10 @@ 

                      });

                  })

                  .fail(err => {

+                     let errMsg = JSON.parse(err);

                      this.props.addNotification(

                          "error",

-                         `Failed to reindex database - ${err}`

+                         `Failed to reindex database - ${errMsg.desc}`

                      );

                      this.setState({

                          showReindexModal: false,
@@ -405,11 +408,12 @@ 

                      );

                  })

                  .fail(err => {

+                     let errMsg = JSON.parse(err);

                      this.props.loadSuffixTree(false);

                      this.closeSubSuffixModal();

                      this.props.addNotification(

                          "error",

-                         `Error creating sub-suffix - ${err}`

+                         `Error creating sub-suffix - ${errMsg.desc}`

                      );

                  });

      }
@@ -527,11 +531,12 @@ 

                      );

                  })

                  .fail(err => {

+                     let errMsg = JSON.parse(err);

                      this.props.loadSuffixTree(false);

                      this.closeLinkModal();

                      this.props.addNotification(

                          "error",

-                         `Error creating database link - ${err}`

+                         `Error creating database link - ${errMsg.desc}`

                      );

                  });

      }
@@ -594,11 +599,12 @@ 

                      );

                  })

                  .fail(err => {

+                     let errMsg = JSON.parse(err);

                      this.props.loadSuffixTree(true);

                      this.closeLinkModal();

                      this.props.addNotification(

                          "error",

-                         `Error deleting database - ${err}`

+                         `Error deleting database - ${errMsg.desc}`

                      );

                  });

      }
@@ -655,10 +661,11 @@ 

                          );

                      })

                      .fail(err => {

+                         let errMsg = JSON.parse(err);

                          this.props.reload(this.props.suffix);

                          this.props.addNotification(

                              "error",

-                             `Error updating suffix configuration - ${err}`

+                             `Error updating suffix configuration - ${errMsg.desc}`

                          );

                      });

          }

@@ -224,11 +224,12 @@ 

                          );

                      })

                      .fail(err => {

+                         let errMsg = JSON.parse(err);

                          this.closeVLVEditModal();

                          this.props.reload(this.props.suffix);

                          this.props.addNotification(

                              "error",

-                             `Failed to edit VLV search - ${err}`

+                             `Failed to edit VLV search - ${errMsg.desc}`

                          );

                      });

          }
@@ -273,11 +274,12 @@ 

                          );

                      })

                      .fail(err => {

+                         let errMsg = JSON.parse(err);

                          this.closeVLVEditModal();

                          this.props.reload(this.props.suffix);

                          this.props.addNotification(

                              "error",

-                             `Failed to add VLV index entry - ${err}`

+                             `Failed to add VLV index entry - ${errMsg.desc}`

                          );

                      });

          }
@@ -304,11 +306,12 @@ 

                          );

                      })

                      .fail(err => {

+                         let errMsg = JSON.parse(err);

                          this.closeVLVEditModal();

                          this.props.reload(this.props.suffix);

                          this.props.addNotification(

                              "error",

-                             `Failed to add VLV index entry - ${err}`

+                             `Failed to add VLV index entry - ${errMsg.desc}`

                          );

                      });

          }
@@ -391,17 +394,19 @@ 

                                      );

                                  })

                                  .fail(err => {

+                                     let errMsg = JSON.parse(err);

                                      this.props.addNotification(

                                          "error",

-                                         `Failed create VLV index entry - ${err}`

+                                         `Failed create VLV index entry - ${errMsg.desc}`

                                      );

                                  });

                      }

                  })

                  .fail(err => {

+                     let errMsg = JSON.parse(err);

                      this.props.addNotification(

                          "error",

-                         `Failed create VLV search entry - ${err}`

+                         `Failed create VLV search entry - ${errMsg.desc}`

                      );

                  });

          this.closeVLVModal();
@@ -455,10 +460,11 @@ 

                      );

                  })

                  .fail(err => {

+                     let errMsg = JSON.parse(err);

                      this.props.reload(this.props.suffix);

                      this.props.addNotification(

                          "error",

-                         `Failed to deletre VLV index - ${err}`

+                         `Failed to deletre VLV index - ${errMsg.desc}`

                      );

                  });

      }
@@ -492,10 +498,11 @@ 

                      );

                  })

                  .fail(err => {

+                     let errMsg = JSON.parse(err);

                      this.props.reload(this.props.suffix);

                      this.props.addNotification(

                          "error",

-                         `Failed to index VLV index - ${err}`

+                         `Failed to index VLV index - ${errMsg.desc}`

                      );

                  });

      }

@@ -0,0 +1,117 @@ 

+ import React from "react";

+ import PropTypes from "prop-types";

+ import "../../css/ds.css";

+ import {

+     Spinner,

+     noop,

+     Row,

+     Col,

+     ControlLabel,

+     Icon,

+ } from "patternfly-react";

+ 

+ export class AccessLogMonitor extends React.Component {

+     componentDidUpdate () {

+         // Set the textarea to be scrolled down to the bottom

+         let textarea = document.getElementById('accesslog-area');

+         textarea.scrollTop = textarea.scrollHeight;

+     }

+ 

+     render() {

+         let spinner = "";

+         if (this.props.reloading) {

+             spinner =

+                 <div>

+                     <Spinner inline loading size="sm" />

+                     Reloading access log...

+                 </div>;

+         }

+         let contRefreshCheckbox =

+             <input type="checkbox" className="ds-sm-left-margin"

+                 onChange={this.props.handleRefresh}

+             />;

+         if (this.props.refreshing) {

+             contRefreshCheckbox =

+                 <input type="checkbox" className="ds-sm-left-margin"

+                     defaultChecked onChange={this.props.handleRefresh}

+                 />;

+         }

+ 

+         let selectLines =

+             <div>

+                 <label htmlFor="accesslog-lines"> Log Lines To Show</label><select

+                     className="btn btn-default dropdown ds-left-margin"

+                     onChange={this.props.handleChange}

+                     id="accesslog-lines" value={this.props.lines}>

+                     <option>50</option>

+                     <option>100</option>

+                     <option>200</option>

+                     <option>300</option>

+                     <option>400</option>

+                     <option>500</option>

+                     <option>1000</option>

+                     <option>2000</option>

+                     <option>5000</option>

+                     <option>10000</option>

+                     <option>50000</option>

+                 </select>

+             </div>;

+ 

+         return (

+             <div id="monitor-log-access-page" className="container-fluid">

+                 <Row>

+                     <Col sm={3}>

+                         <ControlLabel className="ds-suffix-header">

+                             Access Log

+                             <Icon className="ds-left-margin ds-refresh"

+                                 type="fa" name="refresh" title="Refresh access log"

+                                 onClick={() => this.props.reload(this.props.reload)}

+                             />

+                         </ControlLabel>

+                     </Col>

+                     <Col sm={9} className="ds-float-left">

+                         {spinner}

+                     </Col>

+                 </Row>

+                 <p />

+                 <Row>

+                     <Col sm={6}>

+                         {selectLines}

+                     </Col>

+                     <Col sm={6}>

+                         <div className="ds-float-right">

+                             <label>

+                                 {contRefreshCheckbox} Continuously Refresh

+                             </label>

+                         </div>

+                     </Col>

+                 </Row>

+                 <textarea id="accesslog-area" className="ds-logarea" value={this.props.data} readOnly />

+             </div>

+         );

+     }

+ }

+ 

+ // Props and defaultProps

+ 

+ AccessLogMonitor.propTypes = {

+     data: PropTypes.string,

+     handleChange: PropTypes.func,

+     handleRefresh: PropTypes.func,

+     reload: PropTypes.func,

+     reloading: PropTypes.bool,

+     refreshing: PropTypes.bool,

+     lines: PropTypes.string,

+ };

+ 

+ AccessLogMonitor.defaultProps = {

+     data: "",

+     handleChange: noop,

+     handleRefresh: noop,

+     reload: noop,

+     reloading: false,

+     refreshing: false,

+     line: "50"

+ };

+ 

+ export default AccessLogMonitor;

@@ -0,0 +1,117 @@ 

+ import React from "react";

+ import PropTypes from "prop-types";

+ import "../../css/ds.css";

+ import {

+     Spinner,

+     noop,

+     Row,

+     Col,

+     Icon,

+     ControlLabel

+ } from "patternfly-react";

+ 

+ export class AuditFailLogMonitor extends React.Component {

+     componentDidUpdate () {

+         // Set the textarea to be scrolled down to the bottom

+         let textarea = document.getElementById('auditfaillog-area');

+         textarea.scrollTop = textarea.scrollHeight;

+     }

+ 

+     render() {

+         let spinner = "";

+         if (this.props.reloading) {

+             spinner =

+                 <div>

+                     <Spinner inline loading size="sm" />

+                     Reloading audit failure log...

+                 </div>;

+         }

+         let contRefreshCheckbox =

+             <input type="checkbox" className="ds-sm-left-margin"

+                 onChange={this.props.handleRefresh}

+             />;

+         if (this.props.refreshing) {

+             contRefreshCheckbox =

+                 <input type="checkbox" className="ds-sm-left-margin"

+                     defaultChecked onChange={this.props.handleRefresh}

+                 />;

+         }

+ 

+         let selectLines =

+             <div>

+                 <label htmlFor="auditfaillog-lines"> Log Lines To Show</label><select

+                     className="btn btn-default dropdown ds-left-margin"

+                     onChange={this.props.handleChange}

+                     id="auditfaillog-lines" value={this.props.lines}>

+                     <option>50</option>

+                     <option>100</option>

+                     <option>200</option>

+                     <option>300</option>

+                     <option>400</option>

+                     <option>500</option>

+                     <option>1000</option>

+                     <option>2000</option>

+                     <option>5000</option>

+                     <option>10000</option>

+                     <option>50000</option>

+                 </select>

+             </div>;

+ 

+         return (

+             <div id="monitor-log-auditfail-page" className="container-fluid">

+                 <Row>

+                     <Col sm={3}>

+                         <ControlLabel className="ds-suffix-header">

+                             Audit Failure Log

+                             <Icon className="ds-left-margin ds-refresh"

+                                 type="fa" name="refresh" title="Refresh audit failure log"

+                                 onClick={() => this.props.reload(this.props.reload)}

+                             />

+                         </ControlLabel>

+                     </Col>

+                     <Col sm={9} className="ds-float-left">

+                         {spinner}

+                     </Col>

+                 </Row>

+                 <p />

+                 <Row>

+                     <Col sm={6}>

+                         {selectLines}

+                     </Col>

+                     <Col sm={6}>

+                         <div className="ds-float-right">

+                             <label>

+                                 {contRefreshCheckbox} Continuously Refresh

+                             </label>

+                         </div>

+                     </Col>

+                 </Row>

+                 <textarea id="auditfaillog-area" className="ds-logarea" value={this.props.data} readOnly />

+             </div>

+         );

+     }

+ }

+ 

+ // Props and defaultProps

+ 

+ AuditFailLogMonitor.propTypes = {

+     data: PropTypes.string,

+     handleChange: PropTypes.func,

+     handleRefresh: PropTypes.func,

+     reload: PropTypes.func,

+     reloading: PropTypes.bool,

+     refreshing: PropTypes.bool,

+     lines: PropTypes.string,

+ };

+ 

+ AuditFailLogMonitor.defaultProps = {

+     data: "",

+     handleChange: noop,

+     handleRefresh: noop,

+     reload: noop,

+     reloading: false,

+     refreshing: false,

+     line: "50"

+ };

+ 

+ export default AuditFailLogMonitor;

@@ -0,0 +1,117 @@ 

+ import React from "react";

+ import PropTypes from "prop-types";

+ import "../../css/ds.css";

+ import {

+     Spinner,

+     noop,

+     Row,

+     Col,

+     Icon,

+     ControlLabel

+ } from "patternfly-react";

+ 

+ export class AuditLogMonitor extends React.Component {

+     componentDidUpdate () {

+         // Set the textarea to be scrolled down to the bottom

+         let textarea = document.getElementById('auditlog-area');

+         textarea.scrollTop = textarea.scrollHeight;

+     }

+ 

+     render() {

+         let spinner = "";

+         if (this.props.reloading) {

+             spinner =

+                 <div>

+                     <Spinner inline loading size="sm" />

+                     Reloading audit log...

+                 </div>;

+         }

+         let contRefreshCheckbox =

+             <input type="checkbox" className="ds-sm-left-margin"

+                 onChange={this.props.handleRefresh}

+             />;

+         if (this.props.refreshing) {

+             contRefreshCheckbox =

+                 <input type="checkbox" className="ds-sm-left-margin"

+                     defaultChecked onChange={this.props.handleRefresh}

+                 />;

+         }

+ 

+         let selectLines =

+             <div>

+                 <label htmlFor="auditlog-lines"> Log Lines To Show</label><select

+                     className="btn btn-default dropdown ds-left-margin"

+                     onChange={this.props.handleChange}

+                     id="auditlog-lines" value={this.props.lines}>

+                     <option>50</option>

+                     <option>100</option>

+                     <option>200</option>

+                     <option>300</option>

+                     <option>400</option>

+                     <option>500</option>

+                     <option>1000</option>

+                     <option>2000</option>

+                     <option>5000</option>

+                     <option>10000</option>

+                     <option>50000</option>

+                 </select>

+             </div>;

+ 

+         return (

+             <div id="monitor-log-audit-page" className="container-fluid">

+                 <Row>

+                     <Col sm={3}>

+                         <ControlLabel className="ds-suffix-header">

+                             Audit Log

+                             <Icon className="ds-left-margin ds-refresh"

+                                 type="fa" name="refresh" title="Refresh audit log"

+                                 onClick={() => this.props.reload(this.props.reload)}

+                             />

+                         </ControlLabel>

+                     </Col>

+                     <Col sm={9} className="ds-float-left">

+                         {spinner}

+                     </Col>

+                 </Row>

+                 <p />

+                 <Row>

+                     <Col sm={6}>

+                         {selectLines}

+                     </Col>

+                     <Col sm={6}>

+                         <div className="ds-float-right">

+                             <label>

+                                 {contRefreshCheckbox} Continuously Refresh

+                             </label>

+                         </div>

+                     </Col>

+                 </Row>

+                 <textarea id="auditlog-area" className="ds-logarea" value={this.props.data} readOnly />

+             </div>

+         );

+     }

+ }

+ 

+ // Props and defaultProps

+ 

+ AuditLogMonitor.propTypes = {

+     data: PropTypes.string,

+     handleChange: PropTypes.func,

+     handleRefresh: PropTypes.func,

+     reload: PropTypes.func,

+     reloading: PropTypes.bool,

+     refreshing: PropTypes.bool,

+     lines: PropTypes.string,

+ };

+ 

+ AuditLogMonitor.defaultProps = {

+     data: "",

+     handleChange: noop,

+     handleRefresh: noop,

+     reload: noop,

+     reloading: false,

+     refreshing: false,

+     line: "50"

+ };

+ 

+ export default AuditLogMonitor;

@@ -0,0 +1,177 @@ 

+ import React from "react";

+ import PropTypes from "prop-types";

+ import "../../css/ds.css";

+ import {

+     Row,

+     Col,

+     ControlLabel,

+     Icon,

+ } from "patternfly-react";

+ 

+ export class ChainingMonitor extends React.Component {

+     render() {

+         return (

+             <div id="monitor-server-page" className="container-fluid">

+                 <Row>

+                     <Col sm={12} className="ds-word-wrap">

+                         <ControlLabel className="ds-suffix-header">

+                             <Icon type="fa" name="link" /> {this.props.suffix} (<i>{this.props.bename}</i>)

+                             <Icon className="ds-left-margin ds-refresh"

+                                 type="fa" name="refresh" title="Refresh chaining monitor"

+                                 onClick={() => this.props.reload(this.props.suffix)}

+                             />

+                         </ControlLabel>

+                     </Col>

+                 </Row>

+                 <p />

+                 <hr />

+                 <div>

+                     <Row className="ds-margin-top">

+                         <Col sm={3}>

+                             <ControlLabel>

+                                 Add Operations

+                             </ControlLabel>

+                         </Col>

+                         <Col sm={3}>

+                             <input type="text" value={this.props.data.nsaddcount} size="35" readOnly />

+                         </Col>

+                     </Row>

+                     <Row className="ds-margin-top">

+                         <Col sm={3}>

+                             <ControlLabel>

+                                 Delete Operations

+                             </ControlLabel>

+                         </Col>

+                         <Col sm={3}>

+                             <input type="text" value={this.props.data.nsdeletecount} size="35" readOnly />

+                         </Col>

+                     </Row>

+                     <Row className="ds-margin-top">

+                         <Col sm={3}>

+                             <ControlLabel>

+                                 Modify Operations

+                             </ControlLabel>

+                         </Col>

+                         <Col sm={3}>

+                             <input type="text" value={this.props.data.nsmodifycount} size="35" readOnly />

+                         </Col>

+                     </Row>

+                     <Row className="ds-margin-top">

+                         <Col sm={3}>

+                             <ControlLabel>

+                                 ModRDN Operations

+                             </ControlLabel>

+                         </Col>

+                         <Col sm={3}>

+                             <input type="text" value={this.props.data.nsrenamecount} size="35" readOnly />

+                         </Col>

+                     </Row>

+                     <Row className="ds-margin-top">

+                         <Col sm={3}>

+                             <ControlLabel>

+                                 Base Searches

+                             </ControlLabel>

+                         </Col>

+                         <Col sm={3}>

+                             <input type="text" value={this.props.data.nssearchbasecount} size="35" readOnly />

+                         </Col>

+                     </Row>

+                     <Row className="ds-margin-top">

+                         <Col sm={3}>

+                             <ControlLabel>

+                                 One-Level Searches

+                             </ControlLabel>

+                         </Col>

+                         <Col sm={3}>

+                             <input type="text" value={this.props.data.nssearchonelevelcount} size="35" readOnly />

+                         </Col>

+                     </Row>

+                     <Row className="ds-margin-top">

+                         <Col sm={3}>

+                             <ControlLabel>

+                                 Subtree Searches

+                             </ControlLabel>

+                         </Col>

+                         <Col sm={3}>

+                             <input type="text" value={this.props.data.nssearchsubtreecount} size="35" readOnly />

+                         </Col>

+                     </Row>

+                     <Row className="ds-margin-top">

+                         <Col sm={3}>

+                             <ControlLabel>

+                                 Abandon Operations

+                             </ControlLabel>

+                         </Col>

+                         <Col sm={3}>

+                             <input type="text" value={this.props.data.nsabandoncount} size="35" readOnly />

+                         </Col>

+                     </Row>

+                     <Row className="ds-margin-top">

+                         <Col sm={3}>

+                             <ControlLabel>

+                                 Bind Operations

+                             </ControlLabel>

+                         </Col>

+                         <Col sm={3}>

+                             <input type="text" value={this.props.data.nsbindcount} size="35" readOnly />

+                         </Col>

+                     </Row>

+                     <Row className="ds-margin-top">

+                         <Col sm={3}>

+                             <ControlLabel>

+                                 Unbind Operations

+                             </ControlLabel>

+                         </Col>

+                         <Col sm={3}>

+                             <input type="text" value={this.props.data.nsunbindcount} size="35" readOnly />

+                         </Col>

+                     </Row>

+                     <Row className="ds-margin-top">

+                         <Col sm={3}>

+                             <ControlLabel>

+                                 Compare Operations

+                             </ControlLabel>

+                         </Col>

+                         <Col sm={3}>

+                             <input type="text" value={this.props.data.nscomparecount} size="35" readOnly />

+                         </Col>

+                     </Row>

+                     <Row className="ds-margin-top">

+                         <Col sm={3}>

+                             <ControlLabel>

+                                 Outgoing Connections

+                             </ControlLabel>

+                         </Col>

+                         <Col sm={3}>

+                             <input type="text" value={this.props.data.nsopenopconnectioncount} size="35" readOnly />

+                         </Col>

+                     </Row>

+                     <Row className="ds-margin-top">

+                         <Col sm={3}>

+                             <ControlLabel>

+                                 Outgoing Bind Connections

+                             </ControlLabel>

+                         </Col>

+                         <Col sm={3}>

+                             <input type="text" value={this.props.data.nsopenbindconnectioncount} size="35" readOnly />

+                         </Col>

+                     </Row>

+                 </div>

+             </div>

+         );

+     }

+ }

+