From 752801b8ebfb0242513885e7c53c994e3fad822c Mon Sep 17 00:00:00 2001
From: Mark Reynolds <mreynolds@redhat.com>
Date: Feb 27 2019 21:09:30 +0000
Subject: Ticket 50215 - UI - implement Database Tab in reachJS


Description:  Implement database tab in ReactJS.

https://pagure.io/389-ds-base/issue/50215

Reviewed by: spichugi & firstyear (Thanks!!)

---

diff --git a/src/cockpit/389-console/.eslintrc.json b/src/cockpit/389-console/.eslintrc.json
index ee0a235..11a82c8 100644
--- a/src/cockpit/389-console/.eslintrc.json
+++ b/src/cockpit/389-console/.eslintrc.json
@@ -44,8 +44,7 @@
         "eqeqeq": "off",
         "import/no-webpack-loader-syntax": "off",
         "object-property-newline": "off",
-        "react/jsx-no-bind": "off",
-        "max-len": ["error", { "code": 100 }]
+        "react/jsx-no-bind": "off"
     },
     "globals": {
         "require": false,
diff --git a/src/cockpit/389-console/src/backend.html b/src/cockpit/389-console/src/backend.html
deleted file mode 100644
index c209f96..0000000
--- a/src/cockpit/389-console/src/backend.html
+++ /dev/null
@@ -1,1007 +0,0 @@
-
-
-  <div id="db-global-page" class="all-pages" hidden>
-    <h3 class="ds-config-header">Global Database Settings</h3>
-    <div class="ds-container">
-      <div class="ds-inline">
-        <div>
-          <label for="nsslapd-lookthrough-limit" class="ds-config-label" title=
-            "The maximum number of entries that the Directory Server will check when examining candidate entries in response to a search request (nsslapd-lookthrough-limit).">
-            Database Look Though Limit</label><input class="ds-input" type="text" id="nsslapd-lookthrough-limit" size="15"/>
-        </div>
-        <div>
-          <label for="nsslapd-idlistscanlimit" class="ds-config-label" title=
-            "The number of entry IDs that are searched during a search operation (nsslapd-idlistscanlimit).">
-            ID List Scan Limit</label><input class="ds-input" type="text" id="nsslapd-idlistscanlimit" size="15"/>
-        </div>
-      </div>
-      <div class="ds-divider"></div>
-      <div class="ds-inline">
-        <div>
-          <label for="nsslapd-pagedlookthroughlimit" class="ds-config-label" title=
-            "The maximum number of entries that the Directory Server will check when examining candidate entries for a search which uses the simple paged results control (nsslapd-pagedlookthroughlimit).">
-            Paged Search Look Through Limit</label><input class="ds-input" type="text" id="nsslapd-pagedlookthroughlimit" size="15"/>
-        </div>
-        <div>
-          <label for="nsslapd-pagedidlistscanlimit" class="ds-config-label" title=
-            "The number of entry IDs that are searched, specifically, for a search operation using the simple paged results control (nsslapd-pagedidlistscanlimit).">
-            Paged Search ID List Scan Limit</label><input class="ds-input" type="text" id="nsslapd-pagedidlistscanlimit" size="15"/>
-        </div>
-        <div>
-          <label for="nsslapd-rangelookthroughlimit" class="ds-config-label" title=
-            "The maximum number of entries that the Directory Server will check when examining candidate entries in response to a range search request (nsslapd-rangelookthroughlimit).">
-            Range Search Look Through Limit</label><input class="ds-input" type="text" id="nsslapd-rangelookthroughlimit" size="15"/>
-        </div>
-      </div>
-    </div>
-    <hr>
-    <h4 class="ds-sub-header">Database Cache Settings</h4>
-    <div class="ds-roles">
-      <label title="Set Database/Entry to be set manually"><input
-        class="ds-radio cache-role" type="radio" id="manual-cache" name="cache-role" value="manual-cache" checked="checked"> Manual Cache Tuning</label>
-      <label title="Set Database/Entry to be set automatically"><input
-        class="ds-radio cache-role" type="radio" id="auto-cache" name="cache-role" value="auto-cache"> Automatic Cache Tuning</label>
-    </div>
-    <div id="manual-cache-form" class="ds-margin-left" hidden>
-      <label for="nsslapd-dbcachesize" class="ds-config-label-xlrg" title=
-        "Specifies the database index cache size in bytes (nsslapd-dbcachesize).">
-        Database Cache Size (bytes)</label><input class="ds-input" type="text" id="nsslapd-dbcachesize" size="15"/>
-    </div>
-    <div id="auto-cache-form" class="ds-inline ds-margin-left" hidden>
-      <div>
-        <label for="nsslapd-cache-autosize" class="ds-config-label-xlrg" title=
-          "Enable database and entry cache auto-tuning using a percentage of the systems current resources (nsslapd-cache-autosize).">
-          System Memory Percentage</label><input class="ds-input" type="text" id="nsslapd-cache-autosize" size="3"/> %
-      </div>
-      <div>
-        <label for="nsslapd-cache-autosize-split" class="ds-config-label-xlrg" title=
-          "Sets the percentage of memory that is used for the database cache. The remaining percentage is used for the entry cache (nsslapd-cache-autosize-split).">
-          DB Cache Percentage</label><input class="ds-input" type="text" id="nsslapd-cache-autosize-split" size="3"/> %
-      </div>
-    </div>
-
-    <hr>
-    <h4 class="ds-sub-header">Import Cache Settings</h4>
-    <div class="ds-roles">
-      <label title="Set import cache size manually"><input
-        class="ds-radio import-cache-role" type="radio" id="manual-import-cache" name="import-cache-role" value="manual-import-cache" checked="checked"> Manual Import Cache Tuning</label>
-      <label title="Set Database/Entry to be set automatically"><input
-        class="ds-radio import-cache-role" type="radio" id="auto-import-cache" name="import-cache-role" value="auto-import-cache"> Automatic Import Cache Tuning</label>
-    </div>
-    <div id="manual-import-cache-form" class="ds-margin-left" hidden>
-      <label for="nsslapd-import-cachesize" class="ds-config-label-xlrg" title=
-      "The size of the database cache used in the bulk import process. (nsslapd-import-cachesize).">
-      Import Cache Size (bytes)</label><input class="ds-input" type="text" id="nsslapd-import-cachesize" size="15"/>
-    </div>
-    <div id="auto-import-cache-form" class="ds-margin-left" hidden>
-      <label for="nsslapd-import-cache-autosize" class="ds-config-label-xlrg" title=
-        "Enter '-1' to use 50% of available memory, '0' to disable autotuning, or enter the percentage of available memory to use.  Value range -1 through 100, default is '-1' (nsslapd-import-cache-autosize).">
-        Import Cache Autosize</label><input class="ds-input" type="text" id="nsslapd-import-cache-autosize" size="15"/>
-    </div>
-
-    <button class="accordion ds-accordion" id="db-accordion" type="button">&#9658 Show Advanced Settings</button>
-    <div class="ds-accordion-panel">
-      <div class="ds-container">
-        <div class="ds-inline">
-          <div>
-            <label for="nsslapd-db-logdirectory" class="ds-config-label ds-cache-label" title=
-              "Database Transaction Log Location (nsslapd-db-logdirectory).">
-              Transaction Logs Directory</label><input class="ds-input" type="text" id="nsslapd-db-logdirectory" size="15"/>
-          </div>
-          <div>
-            <label for="nsslapd-db-home-directory" class="ds-config-label ds-cache-label" title=
-              "Location for database memory mapped files.  You must specify a subdirectory of a tempfs type filesystem (nsslapd-db-home-directory).">
-              Database Home Directory</label><input class="ds-input" type="text" id="nsslapd-db-home-directory" size="15"/>
-          </div>
-          <div>
-            <label for="nsslapd-db-locks" class="ds-config-label ds-cache-label" title=
-              "The number of database locks (nsslapd-db-locks).">
-              Database Locks</label><input class="ds-input" type="text" id="nsslapd-db-locks" size="15"/>
-          </div>
-          <div>
-            <label for="nsslapd-db-checkpoint-interval" class="ds-config-label ds-cache-label" title=
-              "Amount of time in seconds after which the Directory Server sends a checkpoint entry to the database transaction log (nsslapd-db-checkpoint-interval).">
-              Database Checkpoint Interval</label><input class="ds-input" type="text" id="nsslapd-db-checkpoint-interval" size="15"/>
-          </div>
-          <div>
-            <label for="nsslapd-db-compactdb-interval" class="ds-config-label ds-cache-label" title=
-              "The interval in seconds when the database is compacted (nsslapd-db-compactdb-interval).">
-              Database Compact Interval</label><input class="ds-input" type="text" id="nsslapd-db-compactdb-interval" size="15"/>
-          </div>
-        </div>
-        <div class="ds-divider"></div>
-        <div class="ds-divider"></div>
-        <div class="ds-inline">
-          <div class="ds-first">
-            <input type="checkbox" class="ds-config-checkbox" id="nsslapd-db-verbose"><label
-              for="nsslapd-db-verbose" class="ds-label" title="Enable database verbose logging (nsslapd-db-verbose)."> Enable Database Verbose Logging</label>
-          </div>
-          <div>
-            <input type="checkbox" class="ds-config-checkbox" id="nsslapd-db-debug"><label
-              for="nsslapd-db-debug" class="ds-label" title="Enables database debug logging (nsslapd-db-debug)."> Enable Database Debug Logging</label>
-          </div>
-          <div>
-            <input type="checkbox" class="ds-config-checkbox" id="nsslapd-db-durable-transactions" checked><label
-              for="nsslapd-db-durable-transactions" class="ds-label" title=
-              "sets whether database transaction log entries are immediately written to the disk. (nsslapd-db-durable-transactions)."> Enable Durable transactions</label>
-          </div>
-        </div>
-      </div>
-      <p></p>
-    </div>
-    <div class="ds-footer">
-      <button class="btn btn-primary save-button">Save</button>
-    </div>
-  </div>
-
-  <div class="all-pages" id="db-chaining-settings-page" hidden>
-    <!-- Database Chaining -->
-    <h3 class="ds-config-header">Database Link Settings</h3>
-    <div class="ds-container">
-      <div class="ds-chaining-split">
-        <form>
-          <label class="ds-config-label" for="chaining-oid-list" title=
-            "A list of LDAP control OIDs to be forwarded through chaining"><b>Forwarded LDAP Controls</b></label>
-          <select id="chaining-oid-list" class="ds-chaining-list" name="nstransmittedcontrols" size="10">
-            <option value="1.5.6.5.5.6.88.4553.344">1.5.6.5.5.6.88.4553.344</option>
-          </select>
-        </form>
-        <div class="clearfix ds-container">
-          <div class="ds-panel-left">
-            <button type="button" data-toggle="modal" data-target="#chaining-oid-form" id="chaining-oid-button" class="ds-button-left">Add</button>
-          </div>
-          <div class="ds-panel-right">
-            <button type="button" id="delete-chaining-oid-button" class="ds-button-right">Delete</button>
-          </div>
-        </div>
-      </div>
-      <div class="ds-chaining-divider"></div>
-      <div class="ds-chaining-split">
-        <form>
-          <label class="ds-config-label" for="chaining-comp-list" title=
-            "A list of components to go through chaining"><b>Components to Chain</b></label>
-          <select id="chaining-comp-list" class="ds-chaining-list" name="nsactivechainingcomponents" size="10">
-            <option value="1.5.6.5.5.6.88.4553.344">cn=roles,cn=components,cn=config</option>
-          </select>
-        </form>
-        <div class="clearfix ds-container">
-          <div class="ds-panel-left">
-            <button type="button" data-toggle="modal" data-target="#chaining-comp-form" id="chaining-comp-button" class="ds-button-left">Add</button>
-          </div>
-          <div class="ds-panel-right">
-            <button type="button" id="delete-chaining-comp-button" class="ds-button-right">Delete</button>
-          </div>
-        </div>
-      </div>
-    </div>
-
-    <h4 class="ds-sub-header"><br>Default Database Link Creation Settings</h4>
-    <hr>
-    <div class="ds-container">
-      <div class="ds-split">
-        <label for="default-chaining-size-limit" class="ds-config-label" title=
-          "The size limit of entries returned over a database link (nsslapd-sizelimit).">
-          Size Limit</label><input class="ds-input" type="text" id="default-chaining-size-limit" size="15"/>
-        <label for="default-chaining-time-limit" class="ds-config-label" title=
-          "The time limit of an operation over a database link (nsslapd-timelimit).">
-          Time Limit</label><input class="ds-input" type="text" id="default-chaining-time-limit" size="15"/>
-        <label for="default-nsbindconnectionslimit" class="ds-config-label" title=
-          "The maximum number of TCP connections the database link establishes with the remote server.  (nsbindconnectionslimit).">
-          Max TCP Connections</label><input class="ds-input" type="text" id="default-nsbindconnectionslimit" size="15"/>
-        <label for="default-nsoperationconnectionslimit" class="ds-config-label" title=
-          "The maximum number of connections allowed over the database link.  (nsoperationconnectionslimit).">
-          Max LDAP Connections</label><input class="ds-input" type="text" id="default-nsoperationconnectionslimit" size="15"/>
-        <label for="default-nsconcurrentbindlimit" class="ds-config-label" title=
-          "The maximum number of concurrent bind operations per TCP connection. (nsconcurrentbindlimit).">
-          Max Binds Per Connection</label><input class="ds-input" type="text" id="default-nsconcurrentbindlimit" size="15"/>
-        <label for="default-nsbindtimeout" class="ds-config-label" title=
-          "The amount of time before the bind attempt times out. (nsbindtimeout).">
-          Bind Timeout</label><input class="ds-input" type="text" id="default-nsbindtimeout" size="15"/>
-      </div>
-      <div class="ds-divider"></div>
-      <div class="ds-split ds-inline">
-        <div>
-          <label for="default-nsbindretrylimit" class="ds-config-label" title=
-            "The number of times the database link tries to bind with the remote server after a connection failure. (nsbindretrylimit).">
-            Bind Retry Limit</label><input class="ds-input" type="text" id="default-nsbindretrylimit" size="15"/>
-        </div>
-        <div>
-          <label for="default-nsconcurrentoperationslimit" class="ds-config-label" title=
-            "The maximum number of operations per connections. (nsconcurrentoperationslimit).">
-            Max Operations Per Connection</label><input class="ds-input" type="text" id="default-nsconcurrentoperationslimit" size="15"/>
-        </div>
-        <div>
-          <label for="default-nsconnectionlife" class="ds-config-label" title=
-            "The life of a database link connection to the remote server.  0 is unlimited  (nsconnectionlife).">
-            Connection Lifetime (in seconds)</label><input class="ds-input" type="text" id="default-nsconnectionlife" size="15"/>
-        </div>
-        <div>
-          <label for="default-nsabandonedsearchcheckinterval" class="ds-config-label" title=
-            "The number of seconds that pass before the server checks for abandoned operations.  (nsabandonedsearchcheckinterval).">
-            Abandoned Op Check Interval</label><input class="ds-input" type="text" id="default-nsabandonedsearchcheckinterval" size="15"/>
-        </div>
-        <div>
-          <label for="default-nshoplimit" class="ds-config-label" title=
-            "The maximum number of times a request can be forwarded from one database link to another.  (nshoplimit).">
-            Database Link Hop Limit</label><input class="ds-input" type="text" id="default-nshoplimit" size="15"/>
-        </div>
-        <div>
-          <p></p>
-          <input type="checkbox" class="ds-config-checkbox" id="default-nschecklocalaci"><label
-            for="default-nschecklocalaci" class="ds-label" title=
-            "Sets whether ACIs are evaluated on the database link as well as the remote data server (nschecklocalaci)."> Check Local ACIs</label>
-        </div>
-        <div>
-          <input type="checkbox" class="ds-config-checkbox" id="default-nsreferralonscopedsearch"><label
-            for="default-nsreferralonscopedsearch" class="ds-label" title=
-            "Sets whether referrals are returned by scoped searches (meaning 'one-level' or 'subtree' scoped searches). (nsreferralonscopedsearch)."> Send Referral On Scoped Search</label>
-        </div>
-      </div>
-    </div>
-    <div class="ds-footer">
-      <button class="btn btn-primary save-button">Save</button>
-    </div>
-  </div>
-
-
-  <!-- Suffix Configuration Page -->
-  <div id="db-page" class="all-pages ds-container" hidden>
-
-    <div>
-      <div id="db-tree" class="jstree-open ds-tree">
-        <ul>
-          <li type="suffix" id="suffix-dc=example,dc=com" data-jstree='{"icon":"glyphicon glyphicon-tree-conifer"}'>dc=example,dc=com
-            <ul>
-              <li type="subsuffix" id="suffix-ou=people-dc=example,dc=com" data-jstree='{"icon":"glyphicon glyphicon-leaf"}'>ou=people,dc=example,dc=com</li>
-            </ul>
-          </li>
-          <li type="suffix" id="suffix-o=ipaca.com" data-jstree='{"icon":"glyphicon glyphicon-tree-conifer"}'>o=ipaca.com
-            <ul>
-              <li type="chained-suffix" id="dblink-o=ipaca.com" data-jstree='{"icon":"glyphicon glyphicon-link"}'>MyChainingDBLink</li>
-            </ul>
-          </li>
-        </ul>
-
-      </div>
-      <div>
-        <button class="btn btn-default" data-toggle="modal" data-target="#add-suffix-form" id="create-ref-btn" type="button"><span class="glyphicon glyphicon-plus"></span>  Create New Suffix</button>
-      </div>
-    </div>
-
-    <!-- Database Link Page -->
-    <div id="chaining-page" class="ds-tree-content all-pages" hidden>
-      <h3 class="ds-config-header" id="chaining-header">Database Chaining Configuration</h3>
-      <div class="ds-container">
-        <div class="ds-inline">
-          <form>
-            <div>
-              <label for="nsfarmserverurl" class="ds-config-label" title=
-                "The URL for the remote server.  Add additional failure servers URLs separated by a space. (nsfarmserverurl)">
-                Remote Server URL(s)</label><input class="ds-input" type="text" id="nsfarmserverurl"/>
-            </div>
-            <div>
-              <label for="nsmultiplexorbinddn" class="ds-config-label" title="Bind DN used to authenticate against the remote server (nsmultiplexorbinddn).">Remote Server Bind DN</label><input
-                class="ds-input" type="text" autocomplete="username" placeholder="Bind DN" id="nsmultiplexorbinddn">
-            </div>
-            <div>
-              <label for="nsmultiplexorcredentials" class="ds-config-label" title="Replication Bind DN (nsDS5ReplicaCredentials).">Bind DN Credentials</label><input
-                class="ds-input" type="password" autocomplete="new-password" placeholder="Enter password" id="nsmultiplexorcredentials">
-            </div>
-            <div>
-              <label for="nsmultiplexorcredentials-confirm" class="ds-config-label" title="Confirm password">Confirm Password</label><input
-                class="ds-input" type="password" autocomplete="new-password" placeholder="Confirm password" id="nsmultiplexorcredentials-confirm">
-            </div>
-            <div>
-              <label for="dblink-conn" class="ds-config-label" title="The connection protocol for the remote server.">Connection Protocol</label><select
-                class="btn btn-default dropdown ds-dblink-dropdown" id="dblink-conn">
-                  <option>LDAP</option>
-                  <option>LDAPS</option>
-                  <option>Start TLS</option>
-                </select>
-            </div>
-            <div>
-              <label for="nsbindmechanism" class="ds-config-label" title="The bind method for contacting the remote server  (nsbindmechanism).">Bind Method</label><select
-                class="btn btn-default dropdown ds-dblink-dropdown" id="nsbindmechanism">
-                  <option>Simple</option>
-                  <option>SASL/DIGEST-MD5</option>
-                  <option>SASL/GSSAPI</option>
-                </select>
-            </div>
-          </form>
-        </div>
-      </div>
-      <p></p>
-
-      <button class="accordion ds-accordion" id="chaining-adv-accordion" type="button">&#9658 Show Advanced Database Link Settings </button>
-      <div class="ds-accordion-panel">
-        <div class="ds-accordian-div">
-          <div class="ds-container">
-            <div class="ds-inline">
-              <div>
-                <label for="chaining-size-limit" class="ds-config-label" title=
-                  "The size limit of entries returned over a database link (nsslapd-sizelimit).">
-                  Size Limit</label><input class="ds-input" type="text" id="chaining-size-limit" size="15"/>
-              </div>
-              <div>
-                <label for="chaining-time-limit" class="ds-config-label" title=
-                  "The time limit of an operation over a database link (nsslapd-timelimit).">
-                  Time Limit</label><input class="ds-input" type="text" id="chaining-time-limit" size="15"/>
-              </div>
-              <div>
-                <label for="nsbindconnectionslimit" class="ds-config-label" title=
-                  "The maximum number of TCP connections the database link establishes with the remote server.  (nsbindconnectionslimit).">
-                  Max TCP Connections</label><input class="ds-input" type="text" id="nsbindconnectionslimit" size="15"/>
-              </div>
-              <div>
-                <label for="nsoperationconnectionslimit" class="ds-config-label" title=
-                  "The maximum number of connections allowed over the database link.  (nsoperationconnectionslimit).">
-                  Max LDAP Connections</label><input class="ds-input" type="text" id="nsoperationconnectionslimit" size="15"/>
-              </div>
-              <div>
-                <label for="nsconcurrentbindlimit" class="ds-config-label" title=
-                  "The maximum number of concurrent bind operations per TCP connection. (nsconcurrentbindlimit).">
-                  Max Binds Per Connection</label><input class="ds-input" type="text" id="nsconcurrentbindlimit" size="15"/>
-              </div>
-              <div>
-                <label for="nsbindtimeout" class="ds-config-label" title=
-                  "The amount of time before the bind attempt times out. (nsbindtimeout).">
-                  Bind Timeout</label><input class="ds-input" type="text" id="nsbindtimeout" size="15"/>
-              </div>
-            </div>
-            <div class="ds-divider"></div>
-            <div class="ds-inline">
-              <div>
-                <label for="nsbindretrylimit" class="ds-config-label" title=
-                  "The number of times the database link tries to bind with the remote server after a connection failure. (nsbindretrylimit).">
-                  Bind Retry Limit</label><input class="ds-input" type="text" id="nsbindretrylimit" size="15"/>
-              </div>
-              <div>
-                <label for="nsconcurrentoperationslimit" class="ds-config-label" title=
-                  "The maximum number of operations per connections. (nsconcurrentoperationslimit).">
-                  Max Operations Per Connection</label><input class="ds-input" type="text" id="nsconcurrentoperationslimit" size="15"/>
-              </div>
-              <div>
-                <label for="nsconnectionlife" class="ds-config-label" title=
-                  "The life of a database link connection to the remote server.  0 is unlimited  (nsconnectionlife).">
-                  Connection Lifetime (in seconds)</label><input class="ds-input" type="text" id="nsconnectionlife" size="15"/>
-              </div>
-              <div>
-                <label for="nsabandonedsearchcheckinterval" class="ds-config-label" title=
-                  "The number of seconds that pass before the server checks for abandoned operations.  (nsabandonedsearchcheckinterval).">
-                  Abandoned Op Check Interval</label><input class="ds-input" type="text" id="nsabandonedsearchcheckinterval" size="15"/>
-              </div>
-              <div>
-                <label for="nshoplimit" class="ds-config-label" title=
-                  "The maximum number of times a request can be forwarded from one database link to another.  (nshoplimit).">
-                  Database Link Hop Limit</label><input class="ds-input" type="text" id="nshoplimit" size="15"/>
-              </div>
-            </div>
-          </div>
-          <div>
-            <p></p>
-            <input type="checkbox" class="ds-config-checkbox" id="nschecklocalaci"><label
-              for="nschecklocalaci" class="ds-label" title=
-              "Sets whether ACIs are evaluated on the database link as well as the remote data server (nschecklocalaci)."> Check Local ACIs</label>
-          </div>
-          <div>
-            <input type="checkbox" class="ds-config-checkbox" id="nsreferralonscopedsearch"><label
-              for="nsreferralonscopedsearch" class="ds-label" title=
-              "Sets whether referrals are returned by scoped searches (meaning 'one-level' or 'subtree' scoped searches). (nsreferralonscopedsearch)."> Send Referral On Scoped Search</label>
-          </div>
-        </div>
-      </div>
-    </div>
-
-    <!-- Suffix Page -->
-    <div class="ds-tree-content all-pages" id="suffix-page">
-      <h3 class="ds-config-header" id="suffix-header">Suffix Configuration</h3>
-      <div class="ds-container">
-        <div class="ds-inline">
-          <div>
-            <label for="nsslapd-cachememsize" class="ds-config-label-lrg" title=
-              "The size for the available memory space for the entry cache (nsslapd-cachememsize).">
-              Entry Cache Size (bytes)</label><input class="ds-input" type="text" id="nsslapd-cachememsize" size="20"/>
-          </div>
-          <div>
-            <label for="nsslapd-cachesize" class="ds-config-label-lrg" title=
-              "The number of entries to keep in the entry cache, use'-1' for unlimited (nsslapd-cachesize).">
-              Entry Cache Max Entries</label><input class="ds-input" type="text" id="nsslapd-cachesize" size="20"/>
-          </div>
-          <div>
-            <label for="nsslapd-cachememsize" class="ds-config-label-lrg" title=
-              "the available memory space for the DN cache. The DN cache is similar to the entry cache for a database, only its table stores only the entry ID and the entry DN (nsslapd-dncachememsize).">
-              DN Cache Size (bytes)</label><input class="ds-input" type="text" id="nsslapd-dncachememsize" size="20"/>
-          </div>
-
-        </div>
-        <div class="ds-divider"></div>
-        <div class="ds-inline">
-          <div>
-            <input type="checkbox" class="ds-config-checkbox" id="nsslapd-readonly-suffix"><label
-              for="nsslapd-readonly-suffix" class="ds-label" title="Put database in Read-Only mode (nsslapd-readonly)."> Database Read-Only Mode</label>
-          </div>
-          <div>
-            <input type="checkbox" class="ds-config-checkbox" id="nsslapd-require-index" checked><label
-              for="nsslapd-require-index" class="ds-label" title="Block unindexed searches on this suffix (nsslapd-require-index)."> Block Unindexed Searches</label>
-          </div>
-        </div>
-      </div>
-
-          <div>
-            <hr>
-            <table id="referral-table" class="display ds-referral-table" cellspacing="0" width="100%">
-              <thead>
-                <tr class="ds-table-header">
-                  <th>Referrals</th>
-                  <th></th>
-                </tr>
-              </thead>
-              <tbody id="referral-tbody">
-                <tr>
-                  <td>ldaps://localhost.localdomain.lab.testing.domain.com:636</td>
-                  <td class='ds-center'><button class="btn btn-default del-ref-btn" type="button"><span class="glyphicon glyphicon-trash"></span> Delete</button></td>
-                </tr>
-                <tr>
-                  <td>ldaps://example.fedora.org:636</td>
-                  <td class='ds-center'><button class="btn btn-default del-ref-btn" type="button"><span class="glyphicon glyphicon-trash"></span> Delete</button></td>
-                </tr>
-              </tbody>
-            </table>
-            <button class="btn btn-default" data-toggle="modal" data-target="#create-ref-form" id="create-ref-btn" type="button">Create Referral</button>
-            <p></p>
-          </div>
-
-
-      <button class="accordion ds-accordion" id="db-system-index-accordion" type="button">&#9658 Show System Indexes </button>
-      <div class="ds-accordion-panel">
-        <h4 class="ds-accordion-header">System Indexes</h4>
-        <div class="ds-indent">
-          <table id="system-index-table" class="display ds-table" cellspacing="0" width="100%">
-            <thead>
-              <tr class="ds-table-header">
-                <th>Attribute Name</th>
-                <th title="Presence indexing">Pres</th>
-                <th title="Equality indexing">Eq</th>
-                <th title="Substring indexing">Sub</th>
-                <th title="Approximate indexing">Approx</th>
-                <th>Matching Rules</th>
-              </tr>
-            </thead>
-            <tbody id="sysindex-tbody">
-              <tr>
-                <td>objectclass</td>
-                <td><input type="checkbox" disabled="disabled" class="" id="objectclass-pres" checked></td>
-                <td><input type="checkbox" disabled="disabled" class="" id="objectclass-eq" checked></td>
-                <td><input type="checkbox" disabled="disabled" class="" id="objectclass-sub" checked></td>
-                <td><input type="checkbox" disabled="disabled" class="" id="objectclass-approx"></td>
-                <td></td>
-              </tr>
-              <tr>
-                <td>cn</td>
-                <td><input type="checkbox" disabled="disabled" class="" id="cn-pres"></td>
-                <td><input type="checkbox" disabled="disabled" class="" id="cn-eq" checked></td>
-                <td><input type="checkbox" disabled="disabled" class="" id="cn-sub"></td>
-                <td><input type="checkbox" disabled="disabled" class="" id="cn-approx"></td>
-                <td></td>
-              </tr>
-            </tbody>
-          </table>
-        </div>
-      </div>
-
-      <div>
-        <button class="accordion ds-accordion" id="db-index-accordion" type="button">&#9658 Show Database Indexes </button>
-        <div class="ds-accordion-panel">
-          <h4 class="ds-accordion-header">Database Indexes</h4>
-          <div class="ds-indent">
-            <table id="index-table" class="display ds-repl-table" cellspacing="0" width="100%">
-              <thead>
-                <tr class="ds-table-header">
-                  <th>Attribute Name</th>
-                  <th title="Presence indexing">Pres</th>
-                  <th title="Equality indexing">Eq</th>
-                  <th title="Substring indexing">Sub</th>
-                  <th title="Approximate indexing">Approx</th>
-                  <th>Matching Rules</th>
-                  <th>Action</th>
-                </tr>
-              </thead>
-              <tbody id="index-tbody">
-                <tr>
-                  <td>uidNumber</td>
-                  <td><input type="checkbox" id="uidnumber-pres" checked></td>
-                  <td><input type="checkbox" id="uidnumber-eq" checked></td>
-                  <td><input type="checkbox" id="uidnumber-sub" checked></td>
-                  <td><input type="checkbox" id="uidnumber-approx"></td>
-                  <td></td>
-                  <td class="">
-                    <div class="dropdown">
-                      <button class="btn btn-default dropdown-toggle" type="button" data-toggle="dropdown">
-                        Choose Action...
-                        <span class="caret"></span>
-                      </button>
-                      <ul class="dropdown-menu" role="menu">
-                        <li><a class="db-index-save-btn">Save Index</a></li>
-                        <li><a class="db-index-save-reindex-btn">Save & Reindex</a></li>
-                        <li><a class="db-index-reindex-btn">Reindex Attribute</a></li>
-                        <li><a class="db-index-delete-btn">Delete Index</a></li>
-                      </ul>
-                    </div>
-                  </td>
-                </tr>
-                <tr>
-                  <td>manager</td>
-                  <td><input type="checkbox" id="manager-pres"></td>
-                  <td><input type="checkbox" id="manager-eq" checked></td>
-                  <td><input type="checkbox" id="manager-sub"></td>
-                  <td><input type="checkbox" id="manager-approx"></td>
-                  <td></td>
-                  <td class="">
-                    <div class="dropdown">
-                      <button class="btn btn-default dropdown-toggle" type="button" data-toggle="dropdown">
-                        Choose Action...
-                        <span class="caret"></span>
-                      </button>
-                      <ul class="dropdown-menu" role="menu">
-                        <li><a class="db-index-save-btn">Save Index</a></li>
-                        <li><a class="db-index-save-reindex-btn">Save & Reindex</a></li>
-                        <li><a class="db-index-reindex-btn">Reindex Attribute</a></li>
-                        <li><a class="db-index-delete-btn">Delete Index</a></li>
-                      </ul>
-                    </div>
-                  </td>
-                </tr>
-              </tbody>
-            </table>
-            <button class="btn btn-primary" type="button" data-toggle="modal" data-target="#add-index-form" id="add-index-button">Add Index</button>
-          </div>
-        </div>
-      </div>
-
-      <div>
-        <button class="accordion ds-accordion" id="suffix-attrencrypt-accordion" type="button">&#9658 Show Encrypted Attributes </button>
-        <div class="ds-accordion-panel">
-          <h4 class="ds-accordion-header">Attribute Encryption</h4>
-          <div class="ds-indent">
-            <table id="attr-encrypt-table" class="display ds-repl-table" cellspacing="0" width="100%">
-              <thead>
-                <tr class="ds-table-header">
-                  <th>Attribute Name</th>
-                  <th>Encryption Algorithm</th>
-                  <th>Action</th>
-                </tr>
-              </thead>
-              <tbody id="attr-encrypt-tbody">
-                <tr>
-                  <td class="" id="attr-encrypt-ssn-">ssn</td>
-                  <td>AES</td>
-                  <td><button class="btn btn-default attr-encrypt-delete-btn" type="button">Remove Attribute</button></td>
-                </tr>
-              </tbody>
-            </table>
-            <button class="btn btn-primary" type="button" data-toggle="modal" data-target="#add-encrypted-attr-form"  id="add-encrypted-attr-button">Add Attribute</button>
-          </div>
-        </div>
-      </div>
-    </div>
-
-    <div class="ds-footer">
-      <button class="btn btn-primary save-button">Save</button>
-    </div>
-  </div>
-
-
-
-  <!-- Modals/Popups/Wizards  -->
-
-  <div class="modal fade" id="chaining-oid-form" data-backdrop="static" tabindex="-1" role="dialog" aria-labelledby="chaining-label" aria-hidden="true">
-    <div class="modal-dialog ds-modal">
-      <div class="modal-content">
-        <div class="modal-header">
-          <button type="button" class="close" data-dismiss="modal" aria-hidden="true" aria-label="Close">
-            <span class="pficon pficon-close"></span>
-          </button>
-          <h4 class="modal-title" id="chaining-label">Forwarded Chaining Controls</h4>
-        </div>
-        <div class="modal-body">
-          <form class="form-horizontal">
-            <label class="ds-config-label" for="avail-chaining-oid-list" title=
-              "A list of LDAP control OIDs to be forwarded through chaining">Available LDAP Controls</label>
-            <div>
-              <select id="avail-chaining-oid-list" class="ds-chaining-form-list" name="availcontrols" size="10" multiple>
-                <option value="1.5.6.5.5.6.88.4553.344">1.5.6.5.5.6.88.4553.344</option>
-                <option value="1.5.6.5.5.6.88.4553.345">1.5.6.5.5.6.88.4553.345</option>
-                <option value="1.5.6.5.5.6.88.4553.346">1.5.6.5.5.6.88.4553.346</option>
-                <option value="1.5.6.5.5.6.88.4553.347">1.5.6.5.5.6.88.4553.347</option>
-                <option value="1.5.6.5.5.6.88.4553.348">1.5.6.5.5.6.88.4553.348</option>
-                <option value="1.5.6.5.5.6.88.4553.349">1.5.6.5.5.6.88.4553.349</option>
-                <option value="1.5.6.5.5.6.88.4553.340">1.5.6.5.5.6.88.4553.340</option>
-                <option value="1.5.6.5.5.6.88.4553.351">1.5.6.5.5.6.88.4553.351</option>
-              </select>
-            </div>
-          </form>
-        </div>
-        <div class="modal-footer" ds-modal-footer>
-          <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
-          <button type="button" class="btn btn-primary" id="chaining-oid-save" data-dismiss="modal">Add Controls</button>
-        </div>
-      </div>
-    </div>
-  </div>
-
-  <div class="modal fade" id="chaining-comp-form" data-backdrop="static" tabindex="-1" role="dialog" aria-labelledby="chaining-comp-label" aria-hidden="true">
-    <div class="modal-dialog ds-modal">
-      <div class="modal-content">
-        <div class="modal-header">
-          <button type="button" class="close" data-dismiss="modal" aria-hidden="true" aria-label="Close">
-            <span class="pficon pficon-close"></span>
-          </button>
-          <h4 class="modal-title" id="chaining-comp-label">Chaining Components</h4>
-        </div>
-        <div class="modal-body">
-          <form class="form-horizontal">
-            <label class="ds-config-label" for="chaining-comp-list" title=
-              "A list of components to work with chaining">Available LDAP Controls</label>
-            <div>
-              <select id="avail-chaining-comp-list" class="ds-chaining-form-list" name="availcomps" size="10" multiple>
-                <option value="cn=roles,cn=compnments,cn=config">cn=roles,cn=components,cn=config</option>
-                <option value="cn=Password Policy,cn=components,cn=config">cn=Password Policy,cn=components,cn=config</option>
-              </select>
-            </div>
-          </form>
-        </div>
-        <div class="modal-footer ds-modal-footer">
-          <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
-          <button type="button" class="btn btn-primary" id="chaining-comp-save" data-dismiss="modal">Add Components</button>
-        </div>
-      </div>
-    </div>
-  </div>
-
-
-  <div class="modal fade" id="add-index-form" data-backdrop="static" tabindex="-1" role="dialog" aria-labelledby="add-index-label" aria-hidden="true">
-    <div class="modal-dialog ds-modal">
-      <div class="modal-content">
-        <div class="modal-header">
-          <button type="button" class="close" data-dismiss="modal" aria-hidden="true" aria-label="Close">
-            <span class="pficon pficon-close"></span>
-          </button>
-          <h4 class="modal-title" id="add-index-label">Add Database Index</h4>
-        </div>
-        <div class="modal-body">
-          <form class="form-horizontal">
-            <div class="ds-inline">
-              <div>
-                <label class="ds-config-label" for="ds-index-form-list" title=
-                  "Select an attribute to index">Select An Attribute</label>
-              </div>
-              <div>
-                <select
-                  id="index-list-select" class="ds-index-form-list" name="availcomps" size="10">
-                  <option value="alias">alias</option>
-                  <option value="cn">cn</option>
-                  <option value="uid">uid</option>
-                  <option value="sn">sn</option>
-                  <option value="givenname">givenname</option>
-                  <option value="description">description</option>
-                  <option value="mail">mail</option>
-                  <option value="memberof">memberof</option>
-                </select>
-              </div>
-              <div>
-                <input type="checkbox" class="ds-config-checkbox" id="add-index-type-eq" checked><label
-                  for="add-index-type-eq" class="ds-label" title="Use equality indexing (nsIndexType)."> Equality Indexing</label>
-              </div>
-              <div>
-                <input type="checkbox" class="ds-config-checkbox" id="add-index-type-pres" checked><label
-                  for="add-index-type-pres" class="ds-label" title="Use presence indexing (nsIndexTypeg)."> Presence Indexing</label>
-              </div>
-              <div>
-                <input type="checkbox" class="ds-config-checkbox" id="add-index-type-sub" checked><label
-                  for="add-index-type-sub" class="ds-label" title="Use substring indexing (nsIndexType)."> Substring Indexing</label>
-              </div>
-              <div>
-                <input type="checkbox" class="ds-config-checkbox" id="add-index-type-approx"><label
-                  for="add-index-type-approx" class="ds-label" title="Use approximate indexing (nsIndexType)."> Approximate Indexing</label>
-              </div>
-              <div>
-                <p></p>
-                <label for="add-index-matchingrules" class="" title=
-                    "Matching rule(s) (nsMatchingRule).">
-                    Matching Rules</label>
-              </div>
-              <div>
-                <input type="text" placeholder="None" id="add-index-matchingrules" size="40"/>
-              </div>
-              <div>
-                <hr>
-                <input type="checkbox" class="ds-config-checkbox" id="reindex-on-add" checked><label
-                  for="reindex-on-add" class="ds-label" title="Index attribute after creating it."> Index Attribute After Saving</label>
-              </div>
-            </div>
-          </form>
-        </div>
-        <div class="modal-footer ds-modal-footer">
-          <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
-          <button type="button" class="btn btn-primary" id="add-index-save" data-dismiss="modal">Add Index</button>
-        </div>
-      </div>
-    </div>
-  </div>
-
-  <!-- Attribute encryption Form -->
-  <div class="modal fade" id="add-encrypted-attr-form" data-backdrop="static" tabindex="-1" role="dialog" aria-labelledby="attr-enc-label" aria-hidden="true">
-    <div class="modal-dialog ds-modal">
-      <div class="modal-content">
-        <div class="modal-header">
-          <button type="button" class="close" data-dismiss="modal" aria-hidden="true" aria-label="Close">
-            <span class="pficon pficon-close"></span>
-          </button>
-          <h4 class="modal-title" id="attr-enc-label">Add Encrypted Attribute</h4>
-        </div>
-        <div class="modal-body">
-          <form class="form-horizontal">
-            <div class="ds-inline">
-              <label class="ds-config-label" for="attr-encrypt-list" title=
-                "Select an attribute to be encrypted">Select An Attribute</label>
-            </div>
-            <div>
-              <select
-                id="attr-encrypt-list" class="ds-index-form-list" name="availattrs" size="10">
-                <option value="alias">alias</option>
-                <option value="cn">cn</option>
-              </select>
-            </div>
-            <div>
-              <label for="nsencryptionalgorithm" class="ds-config-label" title="Agreement name (nsEncryptionAlgorithm).">Encryption Algorithm</label><select
-                class="btn btn-default dropdown ds-agmt-wiz-dropdown ds-form-input" id="nsencryptionalgorithm">
-                  <option>AES</option>
-                  <option>3DES</option>
-                </select>
-            </div>
-          </form>
-        </div>
-        <div class="modal-footer ds-modal-footer">
-          <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
-          <button type="button" class="btn btn-primary" id="add-encrypted-attr-save" data-dismiss="modal">Add Attribute</button>
-        </div>
-      </div>
-    </div>
-  </div>
-
-  <!-- Add Suffix Form -->
-  <div class="modal fade" id="add-suffix-form" data-backdrop="static" tabindex="-1" role="dialog" aria-labelledby="suffix-label" aria-hidden="true">
-    <div class="modal-dialog ds-modal">
-      <div class="modal-content">
-        <div class="modal-header">
-          <button type="button" class="close" data-dismiss="modal" aria-hidden="true" aria-label="Close">
-            <span class="pficon pficon-close"></span>
-          </button>
-          <h4 class="modal-title" id="suffix-label">Create New Suffix</h4>
-        </div>
-        <div class="modal-body">
-          <form class="form-horizontal">
-            <div class="ds-inline">
-              <div>
-                <label for="add-suffix-dn" class="ds-config-label" title=
-                  "Database Suffix DN (nsslapd-suffix)">
-                  Suffix DN</label><input class="ds-input" type="text" id="add-suffix-dn" size="40"/>
-              </div>
-              <div>
-                <label for="add-suffix-backend" class="ds-config-label" title=
-                  "Database backend name (nsslapd-backend)">
-                  Backend Name</label><input class="ds-input" type="text" id="add-suffix-backend" size="40"/>
-              </div>
-              <div>
-                <p></p>
-                <input type="checkbox" class="ds-config-checkbox" id="add-suffix-create-dn" checked><label
-                    for="add-suffix-create-dn" class="ds-label" title="Create the top suffix root entry"> Create Suffix Entry</label>
-              </div>
-            </div>
-          </form>
-        </div>
-        <div class="modal-footer ds-modal-footer">
-          <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
-          <button type="button" class="btn btn-primary" id="add-suffix-save" data-dismiss="modal">Create Suffix</button>
-        </div>
-      </div>
-    </div>
-  </div>
-
-
-  <div class="modal fade" id="add-subsuffix-form" data-backdrop="static" tabindex="-1" role="dialog" aria-labelledby="subsuffix-label" aria-hidden="true">
-    <div class="modal-dialog ds-modal">
-      <div class="modal-content">
-        <div class="modal-header">
-          <button type="button" class="close" data-dismiss="modal" aria-hidden="true" aria-label="Close">
-            <span class="pficon pficon-close"></span>
-          </button>
-          <h4 class="modal-title" id="subsuffix-label">Create New Sub-Suffix</h4>
-        </div>
-        <div class="modal-body">
-          <form class="form-horizontal">
-            <div class="ds-inline">
-              <div>
-                <label class="ds-config-labelZ" id="parent-suffix"></label>
-                <p></p>
-              </div>
-              <div>
-                <label for="add-subsuffix-dn" class="ds-config-label" title=
-                  "Database Suffix DN (nsslapd-suffix)">
-                   Sub-Suffix DN</label><input class="ds-input" type="text" id="add-subsuffix-dn" size="40"/>
-              </div>
-              <div>
-                <label for="add-subsuffix-backend" class="ds-config-label" title=
-                  "Database backend name (nsslapd-backend)">
-                  Backend Name</label><input class="ds-input" type="text" id="add-subsuffix-backend" size="40"/>
-              </div>
-              <div>
-                <p></p>
-                <input type="checkbox" class="ds-config-checkbox" id="add-subsuffix-create-dn" checked><label
-                    for="add-subsuffix-create-dn" class="ds-config-label" title="Create the suffix root entry"> Create Sub-Suffix Root Entry</label>
-              </div>
-            </div>
-          </form>
-        </div>
-        <div class="modal-footer ds-modal-footer">
-          <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
-          <button type="button" class="btn btn-primary" id="add-subsuffix-save" data-dismiss="modal">Create Sub-Suffix</button>
-        </div>
-      </div>
-    </div>
-  </div>
-
-  <div class="modal fade" id="import-ldif-form" data-backdrop="static" tabindex="-1" role="dialog" aria-labelledby="import-label" aria-hidden="true">
-    <div class="modal-dialog">
-      <div class="modal-content">
-        <div class="modal-header">
-          <button type="button" class="close" data-dismiss="modal" aria-hidden="true" aria-label="Close">
-            <span class="pficon pficon-close"></span>
-          </button>
-          <h4 class="modal-title" id="import-label">Initialize Database</h4>
-        </div>
-        <div class="modal-body">
-          <div class="ds-inline">
-            <div>
-              <label for="root-suffix-import" class="ds-config-label-lrg" title=
-                      "Suffix where to import">
-                Root Suffix</label><input class="ds-input" type="text" id="root-suffix-import" size="40" disabled/>
-            </div>
-            <div>
-              <label for="ldif-file-import" class="ds-config-label-lrg" title=
-                      "LDIF filename without an extension. LDIF files are written to the server's LDIF directory (nsslapd-ldifdir)">
-                LDIF Filename</label><input class="ds-input" type="text" id="ldif-file-import" size="40"/>
-            </div>
-            <div>
-              <label for="exclude-suffix-import" class="ds-config-label-lrg" title=
-                      "Exclude Suffix (Optional)">
-                Exclude Suffix (Optional)</label><input class="ds-input" type="text" id="exclude-suffix-import" size="40"/>
-            </div>
-            <div>
-              <label for="include-suffix-import" class="ds-config-label-lrg" title=
-                      "Include Suffix (Optional)">
-                Include Suffix (Optional)</label><input class="ds-input" type="text" id="include-suffix-import" size="40"/>
-            </div>
-          </div>
-          <div id="import-ldif-spinner" class="ds-center" hidden>
-            <p></p>
-            <p><span class="spinner spinner-xs spinner-inline"></span> Running LDIF import task...</p>
-          </div>
-        </div>
-        <div class="modal-footer ds-modal-footer">
-          <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
-          <button type="button" class="btn btn-primary" id="import-ldif-save">Import LDIF File</button>
-        </div>
-      </div>
-    </div>
-  </div>
-
-  <div class="modal fade" id="export-ldif-form" data-backdrop="static" tabindex="-1" role="dialog" aria-labelledby="export-label" aria-hidden="true">
-    <div class="modal-dialog">
-      <div class="modal-content">
-        <div class="modal-header">
-          <button type="button" class="close" data-dismiss="modal" aria-hidden="true" aria-label="Close">
-            <span class="pficon pficon-close"></span>
-          </button>
-          <h4 class="modal-title" id="export-label">Export Database</h4>
-        </div>
-        <div class="modal-body">
-          <div class="ds-inline">
-            <div>
-              <label for="root-suffix-export" class="ds-config-label-lrg" title=
-                      "Suffix where to export">
-                Root Suffix</label><input class="ds-input" type="text" id="root-suffix-export" size="40" disabled/>
-            </div>
-            <div>
-              <label for="ldif-file-export" class="ds-config-label-lrg" title=
-                      "LDIF filename without an extension. LDIF files are written to the server's LDIF directory (nsslapd-ldifdir)">
-                LDIF Filename (Optional)</label><input class="ds-input" type="text" id="ldif-file-export" size="40"/>
-            </div>
-            <div>
-              <label for="exclude-suffix-export" class="ds-config-label-lrg" title=
-                      "Exclude Suffix (Optional)">
-                Exclude Suffix (Optional)</label><input class="ds-input" type="text" id="exclude-suffix-export" size="40"/>
-            </div>
-            <div>
-              <label for="include-suffix-export" class="ds-config-label-lrg" title=
-                      "Include Suffix (Optional)">
-                Include Suffix (Optional)</label><input class="ds-input" type="text" id="include-suffix-export" size="40"/>
-            </div>
-          </div>
-          <div id="export-ldif-spinner" class="ds-center" hidden>
-            <p></p>
-            <p><span class="spinner spinner-xs spinner-inline"></span> Running LDIF export task...</p>
-          </div>
-        </div>
-        <div class="modal-footer ds-modal-footer">
-        <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
-        <button type="button" class="btn btn-primary" id="export-ldif-save">Export Database</button>
-      </div>
-      </div>
-    </div>
-  </div>
-
-  <!-- Create Referral Form, -->
-  <div class="modal fade" id="create-ref-form" data-backdrop="static" tabindex="-1" role="dialog" aria-labelledby="ref-label" aria-hidden="true">
-    <div class="modal-dialog ds-modal">
-      <div class="modal-content">
-        <div class="modal-header">
-          <button type="button" class="close" data-dismiss="modal" aria-hidden="true" aria-label="Close">
-            <span class="pficon pficon-close"></span>
-          </button>
-          <h4 class="modal-title" id="ref-label">Create Referral</h4>
-        </div>
-        <div class="modal-body">
-          <form class="form-horizontal">
-            <div class="ds-inline">
-              <div>
-                <label for="ref-protocol" class="ds-label-sm">Connection Protocol</label><select
-                  class="btn btn-default dropdown ds-ref-dropdown" id="ref-protocol">
-                    <option selected>ldap://</option>
-                    <option>ldaps://</option>
-                  </select>
-              </div>
-              <div>
-                <label for="ref-hostname" class="ds-label-sm">Host Name</label><input class="ds-ref-input" type="text" id="ref-hostname"/>
-              </div>
-              <div>
-                <label for="ref-port" class="ds-label-sm">Port Number</label><input class="ds-ref-input" type="text" id="ref-port"/>
-              </div>
-              <div>
-                <label for="ref-suffix" class="ds-label-sm">Suffix (optional)</label><input class="ds-ref-input" type="text" id="ref-suffix"/>
-              </div>
-              <div>
-                <label for="ref-attrs" class="ds-label-sm">Attributes (optional)</label><input class="ds-ref-input" type="text" id="ref-attrs"/>
-              </div>
-              <div>
-                <label for="ref-scope" class="ds-label-sm">Scope (optional)</label><select
-                  class="btn btn-default dropdown ds-ref-dropdown" id="ref-scope">
-                    <option selected></option>
-                    <option>sub</option>
-                    <option>one</option>
-                    <option>base</option>
-                  </select>
-              </div>
-              <div>
-                <label for="ref-filter" class="ds-label-sm"><b>Filter</b> (optional)</label><input class="ds-ref-input" type="text" id="ref-filter"/>
-              </div>
-              <p></p>
-              <hr class="ds-hr">
-              <p></p>
-              <div class="ds-inline">
-                <button type="button" id="preview-ref-btn" class="btn btn-default ds-ref-button">Preview Referral</button><input
-                class="ds-ref-input" type="text" id="ref-preview-field" readOnly/>
-              </div>
-            </div>
-          </form>
-        </div>
-        <div class="modal-footer ds-modal-footer">
-          <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
-          <button type="button" class="btn btn-primary" id="create-ref-save">Create referral</button>
-        </div>
-      </div>
-    </div>
-  </div>
-
-</div>
-
diff --git a/src/cockpit/389-console/src/backend.js b/src/cockpit/389-console/src/backend.js
deleted file mode 100644
index f396b89..0000000
--- a/src/cockpit/389-console/src/backend.js
+++ /dev/null
@@ -1,956 +0,0 @@
-var prev_tree_node = null;
-var ref_del_html = "<button class=\"btn btn-default del-ref-btn\" type=\"button\"><span class='glyphicon glyphicon-trash'></span> Delete</button>";
-var attr_encrypt_del_html = "<button class=\"btn btn-default attr-encrypt-delete-btn\" type=\"button\">Remove Attribute</button></td>";
-var index_btn_html =
-  '<div class="dropdown"> ' +
-     '<button class="btn btn-default dropdown-toggle" type="button" data-toggle="dropdown">' +
-       'Choose Action...' +
-       '<span class="caret"></span>' +
-     '</button>' +
-     '<ul class="dropdown-menu" role="menu">' +
-       '<li><a class="db-index-save-btn">Save Index</a></li>' +
-       '<li><a class="db-index-save-reindex-btn">Save & Reindex</a></li>' +
-       '<li><a class="db-index-reindex-btn">Reindex Attribute</a></li>' +
-       '<li><a class="db-index-delete-btn">Delete Index</a></li>' +
-     '</ul>' +
-   '</div>';
-
-
-var chaining_attr_map = {
-  'nsbindconnectionslimit': '--conn-bind-limit',
-  'nsoperationconnectionslimit': '--conn-op-limit',
-  'nsabandonedsearchcheckinterval': '--abandon-check-interval',
-  'nsconcurrentbindlimit': '--bind-limit',
-  'nsconcurrentoperationslimit': '--op-limit',
-  'nsproxiedauthorization': '--proxied-auth',
-  'nsconnectionlife': '--conn-lifetime',
-  'nsbindtimeout': '--bind-timeout',
-  'nsreferralonscopedsearch': '--return-ref',
-  'nschecklocalaci': '--check-aci',
-  'nsbindretrylimit': '--bind-attempts',
-  'nsslapd-sizelimit': '--size-limit',
-  'nsslapd-timelimit': '--time-limit',
-  'nshoplimit': '--hop-limit',
-  'nsmaxresponsedelay': '--response-delay',
-  'nsmaxtestresponsedelay': '--test-response-delay',
-  'nsusestarttls':'--use-starttls' ,
-  'nsfarmserverurl': '--server-url',
-  'nsbindmechanism': '--bind-mech',
-  'nsmultiplexorbinddn': '--bind-dn',
-  'nsmultiplexorcredentials': '--bind-pw'
-};
-
-function customMenu (node) {
-  var dblink_items = {
-    "delete_link": {
-      "label": "Delete DB Link",
-      "icon": "glyphicon glyphicon-trash",
-      "action": function (data) {
-        popup_confirm("Are you sure you want to delete this Database Link?", "Confirmation", function (yes) {
-          if (yes) {
-
-           // TODO  Delete db link
-          }
-        });
-      }
-    }
-  };
-
-  var suffix_items = {
-    'import': {
-      "label": "Initialize Suffix",
-       "icon": "glyphicon glyphicon-circle-arrow-right",
-       "action": function (data) {
-         var suffix_id = $(node).attr('id');
-         var parent_suffix = suffix_id.substring(suffix_id.indexOf('-')+1);
-         $("#root-suffix-import").val(parent_suffix);
-         $("#import-ldif-file").val("");
-         $("#import-ldif-form").modal('toggle');
-       }
-     },
-     'export': {
-       "label": "Export Suffix",
-       "icon": "glyphicon glyphicon-circle-arrow-left",
-       "action": function (data) {
-         var suffix_id = $(node).attr('id');
-         var parent_suffix = suffix_id.substring(suffix_id.indexOf('-')+1);
-         $("#root-suffix-export").val(parent_suffix);
-         $("#export-ldif-file").val("");
-         $("#export-ldif-form").modal('toggle');
-       }
-     },
-     'reindex': {
-       "label": "Reindex Suffix",
-       "icon": "glyphicon glyphicon-wrench",
-       "action": function (data) {
-         popup_confirm("This will impact DB performance during the indexing.  Are you sure you want to reindex all attributes?", "Confirmation", function (yes) {
-           if (yes) {
-              // TODO Reindex suffix
-           }
-         });
-       }
-     },
-     "create_db_link": {
-       "label": "Create Database Link",
-       "icon": "glyphicon glyphicon-link",
-       "action": function (data) {
-         var suffix_id = $(node).attr('id');
-         var parent_suffix = suffix_id.substring(suffix_id.indexOf('-')+1);
-         //clear_chaining_form();   //TODO
-         $("#create-db-link-form").modal('toggle');
-       }
-     },
-     "create_sub_suffix": {
-       "label": "Create Sub-Suffix",
-       "icon": "glyphicon glyphicon-triangle-bottom",
-       "action": function (data) {
-         var suffix_id = $(node).attr('id');
-         var parent_suffix = suffix_id.substring(suffix_id.indexOf('-')+1);
-         $("#parent-suffix").html('<b>Parent Suffix:</b>&nbsp;&nbsp;' + parent_suffix);
-         $("#add-subsuffix-dn").val(' ,' + parent_suffix);
-         $("#add-subsuffix-form").modal('toggle');
-       }
-     },
-     'delete_suffix': {
-       "label": "Delete Suffix",
-       "icon": "glyphicon glyphicon-remove",
-       "action": function (data) {
-          popup_confirm("Are you sure you want to delete suffix?", "Confirmation", function (yes) {
-            if (yes) {
-              // TODO
-            }
-          });
-       }
-     }
-   };
-
-   if ( $(node).attr('id').startsWith('suffix') ){
-     return suffix_items;
-   } else {
-     // chaining
-     return dblink_items;
-   }
-};
-
-function get_encoded_ref () {
-  var ref_encoded = $("#ref-protocol").val() + $("#ref-hostname").val();
-  var ref_port = $("#ref-port").val();
-  var ref_suffix = $("#ref-suffix").val();
-  var ref_attrs = $("#ref-attrs").val();
-  var ref_filter = $("#ref-filter").val();
-  var ref_scope = $("#ref-scope").val();
-
-  $("#preview-ref-btn").blur();
-
-  if (ref_port != ""){
-    ref_encoded += ":" + ref_port;
-  }
-
-  if (ref_suffix == "" && (ref_attrs != "" || ref_filter != "" || ref_scope != "")) {
-    popup_msg("Attention!", "Missing suffix - you can not set the attributes, scope, or filter without a suffix.");
-    return;
-  }
-  if (ref_suffix != "" || ref_attrs != "" || ref_filter != "" || ref_scope != "") {
-    ref_encoded += "/" + encodeURIComponent(ref_suffix);
-    if ( ref_attrs != "" ) {
-      ref_encoded += "?" + encodeURIComponent(ref_attrs);
-    } else if ( ref_filter != "" || ref_scope != "" ) {
-      ref_encoded += "?";
-    }
-    if ( ref_scope != "" ) {
-      ref_encoded += "?" + encodeURIComponent(ref_scope);
-    } else if ( ref_filter != "" ) {
-      ref_encoded += "?";
-    }
-    if ( ref_filter != "") {
-      ref_encoded += "?" + encodeURIComponent(ref_filter);
-    }
-  }
-  return ref_encoded;
-}
-
-function load_jstree() {
-  $('#db-tree').jstree({
-    "plugins": [ "contextmenu", "wholerow", "sort" ],
-    "contextmenu": {
-      "items" : customMenu
-    },
-    "core": {
-      "check_callback": true
-    }
-  });
-
-  $('#db-tree').jstree('select_node', 'ul > li:first');
-
-
-  $('#db-tree').on("changed.jstree", function (e, data) {
-    var node_type = data.selected[0];
-    var suffix = data.instance.get_node(data.selected[0]).text.replace(/(\r\n|\n|\r)/gm,"");
-
-    if (node_type.startsWith("dblink")) {
-      var parent_suffix = node_type.substring(node_type.indexOf('-')+1);
-      $(".all-pages").hide();
-      $("#database-content").show();
-      $("#db-page").show();
-      $("#chaining-header").html("Database Chaining Configuration <font size=\"2\">(<b>" + parent_suffix + "</b>)</font>");
-      $("#chaining-page").show();
-    } else {
-      // suffix
-      $(".all-pages").hide();
-      $("#database-content").show();
-      $("#db-page").show();
-      $("#suffix-header").html("Suffix Configuration <font size=\"2\">(<b>" + suffix + "</b>)</font>");
-      $("#suffix-page").show();
-    }
-  });
-};
-
-function clear_ref_form () {
-  $("#ref-scope").prop('selectedIndex',0);
-  $("#ref-protocol").prop('selectedIndex',0);
-  $("#ref-suffix").val("");
-  $("#ref-filter").val("");
-  $("#ref-hostname").val("");
-  $("#ref-port").val("");
-  $("#ref-attrs").val("");
-  $("#ref-preview-field").val("");
-}
-
-function clear_index_form () {
-  $("#index-list-select").prop('selectedIndex',0);
-  $("#add-index-type-eq").prop('checked', false);
-  $("#add-index-type-pres").prop('checked', false);
-  $("#add-index-type-sub").prop('checked', false);
-  $("#add-index-type-approx").prop('checked', false);
-  $("#add-index-matchingrules").val("");
-}
-
-function clear_attr_encrypt_form() {
-  $("#attr-encrypt-list").prop('selectedIndex',0);
-  $("#nsencryptionalgorithm").prop('selectedIndex',0);
-}
-
-$(document).ready( function() {
-  $("#database-content").load("backend.html", function () {
-    load_jstree();
-
-    $(".ds-suffix-panel").toggle("active");
-    $(".ds-suffix-panel").css('display','none');
-
-    $("#create-ref-btn").on("click", function () {
-      clear_ref_form();
-    });
-
-    $("#db-chaining-btn").on("click", function() {
-      $(".all-pages").hide();
-      $("#database-content").show();
-      $("#db-chaining-settings-page").show();
-    });
-    $("#db-global-btn").on("click", function() {
-      $(".all-pages").hide();
-      $("#database-content").show();
-      $("#db-global-page").show();
-    });
-    $("#db-suffix-btn").on("click", function() {
-      $(".all-pages").hide();
-      $("#database-content").show();
-      $("#db-page").show();
-      $("#suffix-page").show();
-    });
-
-    $("#chaining-adv-accordion").on("click", function() {
-      this.classList.toggle("active");
-      var panel = this.nextElementSibling;
-      if (panel.style.display === "block") {
-        var show = "&#9658 Show Advanced Database Link Settings ";
-        $(this).html(show);
-        panel.style.display = "none";
-        $(this).blur();
-      } else {
-        var hide = "&#9660 Hide Advanced Database Link Settings";
-        $(this).html(hide);
-        panel.style.display = "block";
-        $(this).blur();
-      }
-    });
-
-
-    $("#db-system-index-accordion").on("click", function() {
-      this.classList.toggle("active");
-      var panel = this.nextElementSibling;
-      if (panel.style.display === "block") {
-        var show = "&#9658 Show System Indexes ";
-        $(this).html(show);
-        panel.style.display = "none";
-        $(this).blur();
-      } else {
-        var hide = "&#9660 Hide System Indexes ";
-        $(this).html(hide);
-        panel.style.display = "block";
-        $(this).blur();
-      }
-    });
-
-    $("#db-index-accordion").on("click", function() {
-      this.classList.toggle("active");
-      var panel = this.nextElementSibling;
-      if (panel.style.display === "block") {
-        var show = "&#9658 Show Database Indexes ";
-        $(this).html(show);
-        panel.style.display = "none";
-        $(this).blur();
-      } else {
-        var hide = "&#9660 Hide Database Indexes ";
-        $(this).html(hide);
-        panel.style.display = "block";
-        $(this).blur();
-      }
-    });
-
-    $("#suffix-attrencrypt-accordion").on("click", function() {
-      this.classList.toggle("active");
-      var panel = this.nextElementSibling;
-      if (panel.style.display === "block") {
-        var show = "&#9658 Show Encrypted Attributes ";
-        $(this).html(show);
-        panel.style.display = "none";
-        $(this).blur();
-      } else {
-        var hide = "&#9660 Hide Encrypted Attributes ";
-        $(this).html(hide);
-        panel.style.display = "block";
-        $(this).blur();
-      }
-    });
-
-
-    /*
-      We need logic to see if autocaching (import and db) is being used, and disable fields,
-      and set radio buttons, et
-    */
-
-    var ref_table = $('#referral-table').DataTable( {
-      "paging": false,
-      "searching": false,
-      "bInfo" : false,
-      "bAutoWidth": false,
-      "dom": '<"pull-left"f><"pull-right"l>tip',
-      "language": {
-        "emptyTable": "No Referrals"
-      },
-      "columnDefs": [
-        {
-          "targets": 1,
-          "orderable": false,
-        },
-        {
-           "targets": 1,
-           "className": "ds-center"
-        }
-      ]
-    });
-
-
-    $('#system-index-table').DataTable( {
-      "paging": true,
-      "bAutoWidth": false,
-      "dom": '<"pull-left"f><"pull-right"l>tip',
-      "lengthMenu": [ 10, 25, 50, 100],
-      "language": {
-        "search": "Search",
-        "emptyTable": "No System Indexes"
-      },
-      "columns": [
-        { "width": "10%" },
-        { "width": "20px" },
-        { "width": "20px" },
-        { "width": "20px" },
-        { "width": "20px" },
-        { "width": "20%" }
-      ],
-    });
-    var index_table = $('#index-table').DataTable( {
-      "paging": true,
-      "bAutoWidth": false,
-      "dom": '<"pull-left"f><"pull-right"l>tip',
-      "lengthMenu": [ 10, 25, 50, 100],
-      "language": {
-        "search": "Search",
-        "emptyTable": "No Indexes"
-      },
-      "columns": [
-        { "width": "10%" },
-        { "width": "15px" },
-        { "width": "15px" },
-        { "width": "15px" },
-        { "width": "15px" },
-        { "width": "20%" },
-        { "width": "76px" }
-      ],
-      "columnDefs": [ {
-        "targets": 6,
-        "orderable": false
-      } ]
-    });
-
-
-
-
-    var attr_encrypt_table = $('#attr-encrypt-table').DataTable( {
-      "paging": true,
-      "bAutoWidth": false,
-      "searching": true,
-      "dom": '<"pull-left"f><"pull-right"l>tip',
-      "lengthMenu": [ 10, 25, 50, 100],
-      "language": {
-        "search": "Search",
-        "emptyTable": "No Encrypted Attributes"
-      },
-      "columnDefs": [ {
-        "targets": 2,
-        "orderable": false
-      } ]
-    });
-
-    // Accordion opening/closings
-    $(".ds-accordion-panel").css('display','none');
-
-    var suffix_acc = document.getElementsByClassName("suffix-accordion");
-    for (var i = 0; i < suffix_acc.length; i++) {
-      suffix_acc[i].onclick = function() {
-        this.classList.toggle("active");
-        var panel = this.nextElementSibling;
-        if (panel.style.display === "block") {
-            panel.style.display = "none";
-        } else {
-            panel.style.display = "block";
-        }
-      }
-    }
-
-    $("#db-accordion").on("click", function() {
-      this.classList.toggle("active");
-      var panel = this.nextElementSibling;
-      if (panel.style.display === "block") {
-        var show = "&#9658 Show Advanced Settings";
-        $(this).html(show);
-        panel.style.display = "none";
-        $(this).blur();
-      } else {
-        var hide = "&#9660 Hide Advanced Settings ";
-        $(this).html(hide);
-        panel.style.display = "block";
-        $(this).blur();
-      }
-    });
-
-    var db_acc = document.getElementsByClassName("db-accordion");
-    for (var i = 0; i < db_acc.length; i++) {
-      db_acc[i].onclick = function() {
-        this.classList.toggle("active");
-        var panel = this.nextElementSibling;
-        if (panel.style.display === "block") {
-            panel.style.display = "none";
-        } else {
-            panel.style.display = "block";
-        }
-      }
-    }
-
-    var cache_acc = document.getElementsByClassName("cache-accordion");
-    for (var i = 0; i < cache_acc.length; i++) {
-      cache_acc[i].onclick = function() {
-        this.classList.toggle("active");
-        var panel = this.nextElementSibling;
-        if (panel.style.display === "block") {
-            panel.style.display = "none";
-        } else {
-            panel.style.display = "block";
-        }
-      }
-    }
-
-
-    $(".index-type").attr('readonly', true);
-
-    if ( $("#manual-cache").is(":checked") ){
-      $("#auto-cache-form").hide();
-      $("#manual-cache-form").show();
-      $("#nsslapd-dncachememsize").prop('disabled', false);
-      $("#nsslapd-dncachememsize").val('');
-      $("#nsslapd-cachememsize").prop('disabled', false);
-      $("#nsslapd-cachememsize").val('');
-      $("#nsslapd-cachesize").prop('disabled', false);
-      $("#nsslapd-cachesize").val('');
-    } else {
-      $("#manual-cache-form").hide();
-      $("#auto-cache-form").show();
-      $("#nsslapd-dncachememsize").prop('disabled', true);
-      $("#nsslapd-dncachememsize").val('AUTOTUNED');
-      $("#nsslapd-cachememsize").prop('disabled', true);
-      $("#nsslapd-cachememsize").val('AUTOTUNED');
-      $("#nsslapd-cachesize").prop('disabled', true);
-      $("#nsslapd-cachesize").val('AUTOTUNED');
-    }
-
-    if ( $("#manual-import-cache").is(":checked") ){
-      $("#auto-import-cache-form").hide();
-      $("#manual-import-cache-form").show();
-    } else {
-      $("#manual-import-cache-form").hide();
-      $("#auto-import-cache-form").show();
-    }
-
-    $(".cache-role").on("change", function() {
-      var cache_role = $("input[name=cache-role]:checked").val();
-      if (cache_role == "manual-cache") {
-        $("#auto-cache-form").hide();
-        $("#manual-cache-form").show();
-      } else {
-        // auto cache
-        $("#manual-cache-form").hide();
-        $("#auto-cache-form").show();
-      }
-    });
-
-    $(document).on('click', '.del-ref-btn', function(e) {
-      e.preventDefault();
-      var data = ref_table.row( $(this).parents('tr') ).data();
-      var del_ref_name = data[0];
-      var ref_row = $(this); // Store element for callback
-      popup_confirm("Are you sure you want to delete referral:  <b>" + del_ref_name + "</b>", "Confirmation", function (yes) {
-        if (yes) {
-          // TODO Delete mapping from DS
-
-          // Update html table
-          ref_table.row( ref_row.parents('tr') ).remove().draw( false );
-        }
-      });
-    });
-
-    $("#backend-config-save-btn").on("click", function () {
-      var role = $("input[name=cache-role]:checked").val();
-      if (role == "manual-cache") {
-        // TODO - need to get cache values and fields (overwrite AUTOTUNED)
-        $("#nsslapd-dncachememsize").prop('disabled', false);
-        $("#nsslapd-dncachememsize").val('')
-        $("#nsslapd-cachememsize").prop('disabled', false);
-        $("#nsslapd-cachememsize").val('');
-        $("#nsslapd-cachesize").prop('disabled', false);
-        $("#nsslapd-cachesize").val('');
-      } else {
-        // auto cache
-        $("#nsslapd-dncachememsize").prop('disabled', true);
-        $("#nsslapd-dncachememsize").val('AUTOTUNED');
-        $("#nsslapd-cachememsize").prop('disabled', true);
-        $("#nsslapd-cachememsize").val('AUTOTUNED');
-        $("#nsslapd-cachesize").prop('disabled', true);
-        $("#nsslapd-cachesize").val('AUTOTUNED');
-      }
-    });
-
-    $(".import-cache-role").on("change", function() {
-      var role = $("input[name=import-cache-role]:checked").val();
-      if (role == "manual-import-cache") {
-         $("#auto-import-cache-form").hide();
-         $("#manual-import-cache-form").show();
-      } else {
-          // auto cache
-         $("#manual-import-cache-form").hide();
-         $("#auto-import-cache-form").show();
-      }
-    });
-
-    // Based on the db-link connection type change the agmt-auth options
-    $("#dblink-conn").change(function() {
-      var ldap_opts = {"Simple": "Simple",
-                       "SASL/DIGEST-MD5": "SASL/DIGEST-MD5",
-                       "SASL/GSSAPI": "SASL/GSSAPI"};
-      var ldaps_opts = {"Simple": "Simple",
-                        "SSL Client Authentication": "SSL Client Authentication",
-                        "SASL/DIGEST-MD5": "SASL/DIGEST-MD5"};
-      var $auth = $("#nsbindmechanism");
-      $auth.empty();
-      var conn = $('#dblink-conn').val();
-      if (conn == "LDAP"){
-        $.each(ldap_opts, function(key, value) {
-          $auth.append($("<option></option>").attr("value", value).text(key));
-        });
-      } else {
-        // TLS options
-        $.each(ldaps_opts, function(key, value) {
-          $auth.append($("<option></option>").attr("value", value).text(key));
-        });
-      }
-      $("#nsmultiplexorbinddn").prop('disabled', false);
-      $("#nsmultiplexorcredentials").prop('disabled', false);
-      $("#nsmultiplexorcredentials-confirm").prop('disabled', false);
-    });
-
-    // Check for auth changes and disable/enable bind DN & password for db-links
-    $("#nsbindmechanism").change(function() {
-      var authtype = $('#nsbindmechanism').val();
-      if (authtype == "SSL Client Authentication") {
-        $("#nsmultiplexorbinddn").prop('disabled', true);
-        $("#nsmultiplexorcredentials").prop('disabled', true);
-        $("#nsmultiplexorcredentials-confirm").prop('disabled', true);
-      } else {
-        $("#nsmultiplexorbinddn").prop('disabled', false);
-        $("#nsmultiplexorcredentials").prop('disabled', false);
-        $("#nsmultiplexorcredentials-confirm").prop('disabled', false);
-      }
-    });
-
-    //
-    // Modal Forms
-    //
-
-    // Chaining OIDS
-    $("#chaining-oid-button").on("click", function() {
-      $(this).blur();
-    });
-    $("#chaining-oid-save").on("click", function() {
-      // Update oids
-      var chaining_oids = $("#avail-chaining-oid-list").val();
-      for (var i = 0; chaining_oids && i < chaining_oids.length; i++) {
-        $('#chaining-oid-list').append($('<option/>', {
-          value: chaining_oids[i],
-          text : chaining_oids[i]
-        }));
-        $("#avail-chaining-oid-list option[value='" + chaining_oids[i] + "']").remove();
-      }
-      sort_list( $("#chaining-oid-list") );
-      $("#chaining-oid-form").modal('toggle');
-    });
-    $("#delete-chaining-oid-button").on("click", function() {
-      var oids = $("#chaining-oid-list").find('option:selected');
-      if (oids && oids != '' && oids.length > 0) {
-        for (var i = 0; i < oids.length; i++) {
-          if ( $('#avail-chaining-comp-list option[value="' + oids[i].text + '"]').val() === undefined) {
-            $('#avail-chaining-oid-list').append($("<option/>").val(oids[i].text).text(oids[i].text));
-          }
-        }
-      }
-      $("#chaining-oid-list").find('option:selected').remove();
-      sort_list( $('#avail-chaining-oid-list') );
-    });
-
-    // Chaining Comps
-    $("#delete-chaining-comp-button").on("click", function() {
-      var comps = $("#chaining-comp-list").find('option:selected');
-      if (comps && comps != '' && comps.length > 0) {
-        for (var i = 0; i < comps.length; i++) {
-          if ( $('#avail-chaining-comp-list option[value="' + comps[i].text + '"]').val() === undefined) {
-            $('#avail-chaining-comp-list').append($("<option/>").val(comps[i].text).text(comps[i].text));
-          }
-        }
-      }
-      $("#chaining-comp-list").find('option:selected').remove();
-      sort_list($('#avail-chaining-comp-list') );
-    });
-    $("#chaining-comp-save").on("click", function() {
-      // Update comps
-      var chaining_comps = $("#avail-chaining-comp-list").val();
-      for (var i = 0; chaining_comps && i < chaining_comps.length; i++) {
-        $('#chaining-comp-list').append($('<option/>', {
-          value: chaining_comps[i],
-          text : chaining_comps[i]
-        }));
-        $("#avail-chaining-comp-list option[value='" + chaining_comps[i] + "']").remove();
-      }
-      sort_list( $("#chaining-comp-list") );
-      $("#chaining-comp-form").css('display', 'none');
-    });
-
-    // Create DB Link
-    $("#create-chain-close").on("click", function() {
-      $("#create-db-link-form").css('display', 'none');
-    });
-    $("#chaining-cancel").on("click", function() {
-      $("#create-db-link-form").css('display', 'none');
-    });
-    $("#chaining-save").on("click", function() {
-      // Create DB link, if LDAPS is selected replace remotefarmUrl "ldap://" with "ldaps://", and visa versa to remove ldaps://
-      var chaining_name = $("#chaining-name").val();
-      var parent_suffix = $("#db-tree").jstree().get_selected(true)[0];
-      var suffix = $("#db-tree").jstree().get_selected(true)[0].text.replace(/(\r\n|\n|\r)/gm,"");
-
-      // TODO - create db link in DS
-
-      $('#db-tree').jstree().create_node(parent_suffix,
-                                         { "id" : "dblink-" + suffix, "text" : chaining_name, "icon" : "glyphicon glyphicon-link" },
-                                         "last");
-      $("#create-db-link-form").css('display', 'none');
-    });
-
-    // Add Index
-    $("#add-index-button").on("click", function() {
-      clear_index_form();
-    })
-
-    $("#add-index-save").on("click", function() {
-      var attr_name = $("#index-list-select").val();
-      var add_attr_type_eq = '<input type="checkbox" id="' + attr_name + '-eq">';
-      var add_attr_type_pres = '<input type="checkbox" id="' + attr_name + '-pres">';
-      var add_attr_type_sub = '<input type="checkbox" id="' + attr_name + '-sub">';
-      var add_attr_type_approx = '<input type="checkbox" id="' + attr_name + '-approx">';
-      var add_index_matchingrules = $("#add-index-matchingrules").val();
-
-      if ( $("#add-index-type-eq").is(":checked") ){
-        add_attr_type_eq = '<input type="checkbox" id="' + attr_name + '-eq" checked>';
-      }
-      if ( $("#add-index-type-pres").is(":checked") ){
-        add_attr_type_pres = '<input type="checkbox" id="' + attr_name + '-pres" checked>';
-      }
-      if ( $("#add-index-type-sub").is(":checked") ){
-        add_attr_type_sub = '<input type="checkbox" id="' + attr_name + '-sub" checked>';
-      }
-      if ( $("#add-index-type-approx").is(":checked") ){
-        add_attr_type_approx = '<input type="checkbox" id="' + attr_name + '-approx" checked>';
-      }
-
-      // TODO - add index to DS
-
-      // Update table on success
-      index_table.row.add( [
-        attr_name,
-        add_attr_type_eq,
-        add_attr_type_pres,
-        add_attr_type_sub,
-        add_attr_type_approx,
-        add_index_matchingrules,
-        index_btn_html
-      ] ).draw( false );
-
-      $("#add-index-form").css('display', 'none');
-      clear_index_form();
-      // Do the actual save in DS
-      // Update html
-    });
-
-
-    // Add encrypted attribute
-    $("#add-encrypted-attr-button").on("click", function() {
-      clear_attr_encrypt_form();
-    })
-    $("#add-encrypted-attr-save").on("click", function() {
-
-      // Do the actual save in DS
-      // Update html
-
-      var encrypt_attr_name = $("#attr-encrypt-list").val();
-      var attr_encrypt_algo = $("#nsencryptionalgorithm").val();
-      // TODO - add encrypted attr to DS
-
-      // Update table on success
-      attr_encrypt_table.row.add( [
-        encrypt_attr_name,
-        attr_encrypt_algo,
-        attr_encrypt_del_html
-      ] ).draw( false );
-
-      $("#add-encrypted-attr-form").modal('toggle');
-
-    });
-
-    // Create Suffix
-    $("#add-suffix-save").on("click", function() {
-      var suffix = $("#add-suffix-dn").val();
-      var backend = $("#add-suffix-backend").val();
-
-      // TODO - create suffix in DS
-
-      $('#db-tree').jstree().create_node('db-root',
-                                         { "id" : "suffix-" + suffix, "text" : suffix, "icon" : "glyphicon glyphicon-tree-conifer" },
-                                         "last");
-      $("#add-suffix-form").css('display', 'none');
-    });
-
-    // Create Sub Suffix
-    $("#add-subsuffix-close").on("click", function() {
-      $("#add-subsuffix-form").css('display', 'none');
-    });
-    $("#add-subsuffix-cancel").on("click", function() {
-      $("#add-subsuffix-form").css('display', 'none');
-    });
-    $("#add-subsuffix-save").on("click", function() {
-      var suffix = $("#add-subsuffix-dn").val();
-      var backend = $("#add-subsuffix-backend").val();
-      var parent_suffix = $("#db-tree").jstree().get_selected(true)[0];
-
-      // TODO - create suffix in DS
-
-      $('#db-tree').jstree().create_node(parent_suffix,
-                                         { "id" : "subsuffix-" + suffix, "text" : suffix, "icon" : "glyphicon glyphicon-leaf" },
-                                         "last");
-      $("#add-subsuffix-form").css('display', 'none');
-    });
-
-    // Init Suffix (import)
-    $("#import-ldif-save").on("click", function() {
-      var root_suffix_import = $("#root-suffix-import").val();
-      var ldif_file_import = $("#ldif-file-import").val();
-      var exclude_suffix_import = $("#exclude-suffix-import").val();
-      var include_suffix_import = $("#include-suffix-import").val();
-      var cmd = [DSCONF, server_inst, 'backend', 'import', root_suffix_import];
-      // Process and validate parameters
-      if (ldif_file_import == ""){
-        popup_msg("Error", "LDIF file should be specified");
-        return;
-      } else if (ldif_file_import.indexOf(' ') >= 0) {
-        popup_msg("Error", "LDIF file can not contain any spaces");
-        return;
-      } else if (ldif_file_import.indexOf('/') === -1 ) {
-        popup_msg("Error", "LDIF file can not contain a forward slash. " +
-                           "LDIF files are written to the server's LDIF directory (nsslapd-ldifdir)");
-        return;
-      } else {
-        cmd.push(ldif_file_import);
-      }
-      if (include_suffix_import != "") {
-        cmd.push.apply(cmd, ["-s", include_suffix_import]);
-      }
-      if (exclude_suffix_import != "") {
-        cmd.push.apply(cmd, ["-x", exclude_suffix_import]);
-      }
-      $("#import-ldif-spinner").show();
-      cockpit.spawn(cmd, { superuser: true, "err": "message", "environ": [ENV]}).
-      done(function(data) {
-        $("#import-ldif-spinner").hide();
-        popup_success("LDIF has been imported");
-        $("#import-ldif-form").modal('toggle');
-      }).
-      fail(function(data) {
-        $("#import-ldif-spinner").hide();
-        popup_err("Error", "Failed to import LDIF\n" + data.message);
-      })
-    });
-
-    // Export Suffix (import)
-    $("#export-ldif-close").on("click", function() {
-      $("#export-ldif-form").css('display', 'none');
-    });
-    $("#export-ldif-cancel").on("click", function() {
-      $("#export-ldif-form").css('display', 'none');
-    });
-    $("#export-ldif-save").on("click", function() {
-      var root_suffix_export = $("#root-suffix-export").val();
-      var ldif_file_export = $("#ldif-file-export").val();
-      var exclude_suffix_export = $("#exclude-suffix-export").val();
-      var include_suffix_export = $("#include-suffix-export").val();
-      var cmd = [DSCONF, server_inst, 'backend', 'export', root_suffix_export];
-      // Process and validate parameters
-      if (ldif_file_export.indexOf(' ') >= 0) {
-        popup_msg("Error", "LDIF file can not contain any spaces");
-        return;
-      } else if (ldif_file_import.indexOf('/') === -1 ) {
-        popup_msg("Error", "LDIF file can not contain a forward slash. " +
-                           "LDIF files are written to the server's LDIF directory (nsslapd-ldifdir)");
-        return;
-      } else if (ldif_file_export != ""){
-        cmd.push.apply(cmd, ["-l", ldif_file_export]);
-      }
-      if (include_suffix_export != "") {
-        cmd.push.apply(cmd, ["-s", include_suffix_export]);
-      }
-      if (exclude_suffix_export != "") {
-        cmd.push.apply(cmd, ["-x", exclude_suffix_export]);
-      }
-      $("#export-ldif-spinner").show();
-      cockpit.spawn(cmd, { superuser: true, "err": "message", "environ": [ENV]}).
-      done(function(data) {
-        $("#export-ldif-spinner").hide();
-        popup_success("LDIF has been exported");
-        $("#export-ldif-form").modal('toggle');
-      }).
-      fail(function(data) {
-        $("#export-ldif-spinner").hide();
-        popup_err("Error", "Failed to export LDIF\n" + data.message);
-      })
-    });
-
-    $("#create-ref-save").on("click", function() {
-      var ref = get_encoded_ref();
-      // Do the actual save in DS
-      // Update html
-      var tr_row = ref_table.row.add( [
-        ref,
-        ref_del_html
-      ] );
-      $( tr_row ).addClass('ds-nowrap-td');
-      $( tr_row ).find("td:nth-child(1))").addClass('ds-center');
-      tr_row.draw(false);
-      $("#create-ref-form").modal('toggle');
-    });
-
-    $("#preview-ref-btn").on('click', function() {
-      $("#ref-preview-field").val(get_encoded_ref());
-    });
-
-    $(document).on('click', '.delete-referral-btn', function(e) {
-      e.preventDefault();
-      var data = ref_table.row( $(this).parents('tr') ).data();
-      var del_ref_name = data[0];
-      var ref_row = $(this);
-      popup_confirm("Are you sure you want to delete referral: " + del_ref_name, "Confirmation", function (yes) {
-        if (yes) {
-          // TODO Delete ref
-          ref_table.row( ref_row.parents('tr') ).remove().draw( false );
-        }
-      });
-    });
-
-
-    // suffix index actions
-    $(document).on('click', '.db-index-save-btn', function(e) {
-      e.preventDefault();
-      var data = index_table.row( $(this).parents('tr') ).data();
-      var save_index_name = data[0];
-        // Do save!
-    });
-
-    $(document).on('click', '.db-index-reindex-btn', function(e) {
-      e.preventDefault();
-      var data = index_table.row( $(this).parents('tr') ).data();
-      var reindex_name = data[0];
-      popup_confirm("Are you sure you want to reindex attribute: <b>" + reindex_name + "</b>", "Confirmation", function (yes) {
-        if (yes) {
-          // TODO reindex attr
-
-        }
-      });
-    });
-
-    $(document).on('click', '.db-index-delete-btn', function(e) {
-      e.preventDefault();
-      var data = index_table.row( $(this).parents('tr') ).data();
-      var del_index_name = data[0];
-      var index_row = $(this);
-
-      popup_confirm("Are you sure you want to delete index: <b>" + del_index_name + "</b>", "Confirmation", function (yes) {
-        if (yes) {
-          // TODO Delete index
-          index_table.row( index_row.parents('tr') ).remove().draw( false );
-        }
-      });
-    });
-
-    // Attribute encryption
-    $(document).on('click', '.attr-encrypt-delete-btn', function(e) {
-      e.preventDefault();
-      var data = attr_encrypt_table.row( $(this).parents('tr') ).data();
-      var attr_name = data[0];
-      var eattr_row = $(this);
-      popup_confirm("Are you sure you want to delete encrypted attribute: <b>" + attr_name + "</b>", "Confirmation", function (yes) {
-        if (yes) {
-          // TODO Delete ref
-          attr_encrypt_table.row( eattr_row.parents('tr') ).remove().draw( false );
-        }
-      });
-    });
-
-    // Page is loaded, mark it as so...
-    db_page_loaded = 1;
-  });
-});
-
diff --git a/src/cockpit/389-console/src/css/ds.css b/src/cockpit/389-console/src/css/ds.css
index 8e9ba21..6af009c 100644
--- a/src/cockpit/389-console/src/css/ds.css
+++ b/src/cockpit/389-console/src/css/ds.css
@@ -41,6 +41,7 @@
     line-height: 0;
 }
 
+/* Main nav page index.html */
 .ds-content {
     padding: 0;
     padding-top: 115px;
@@ -283,8 +284,9 @@ td {
     min-width: 300px;
     min-height: 400px;
     max-height: 400px;
-    margin: 23px 10px 2px 0px;
+    margin: 25px 10px 2px 0px;
     overflow: auto;
+    padding-top: 5px;
 }
 
 .ds-monitor-tree {
@@ -327,6 +329,20 @@ td {
     padding-left: 5px !important;
 }
 
+.ds-input-bad {
+    border-color: red;
+}
+
+.ds-input-auto-bad {
+    width: 100%;
+    border-color: red;
+    padding-left: 5px;
+}
+
+.ds-input-right {
+    text-align: right;
+}
+
 .ds-pw-input {
     margin-top: 5px;
     padding-right: 5px;
@@ -382,11 +398,6 @@ td {
     padding-left: 5px !important;
 }
 
-.ds-ref-input {
-    width: 300px !important;
-    padding-left: 5px;
-}
-
 .ds-history-input {
     margin-top: !important;
     margin-right: 5px;
@@ -401,6 +412,10 @@ td {
     width: 35px;
 }
 
+.ds-divider-lrg {
+    width: 50px;
+}
+
 .ds-divider-med {
     width: 15px;
 }
@@ -448,10 +463,6 @@ td {
     margin-bottom: 5px;
 }
 
-.ds-radio {
-    margin: 5px !important;
-}
-
 .ds-repl-managers-list {
     width: 420px;
     height: 200px;
@@ -495,11 +506,6 @@ td {
     overflow: auto;
 }
 
-.ds-ref-dropdown {
-    width: 300px !important;
-    text-align: left;
-}
-
 .ds-agmt-wiz-dropdown {
     width: 175px !important;
     text-align: left;
@@ -515,13 +521,8 @@ td {
 }
 
 .ds-dblink-dropdown {
-    padding: 0px !important;
-    padding-right: 5px !important;
-    line-height: 0 !important;
     width: 140px !important;
     text-align: left;
-    outline: 0 !important;
-    margin-top: 5px;
 }
 
 .ds-dblink-dropdown a {
@@ -576,6 +577,15 @@ td {
     text-align: center;
 }
 
+.ds-db-table {
+    background-color: white !important;
+    padding: 0px;
+    border: 1px solid #909090;
+    clear: both;
+    word-wrap: break-word !important;
+    text-align: center;
+}
+
 .ds-table {
     background-color: white !important;
     padding: 0px;
@@ -671,14 +681,6 @@ td {
     vertical-align: middle;
 }
 
-.modal-content {
-    position: absolute;
-    max-height: 750px;
-    max-width: 550px;
-    min-width: 400px;
-    overflow: auto;
-}
-
 .ds-log-panel {
     padding: 0 18px;
     max-height: 0 !important;
@@ -1016,13 +1018,15 @@ td {
 }
 
 .ds-chaining-form-list {
-    width: 355px;
-    height: 400px;
+    width: 100%;
+}
+
+.ds-vlv-sort-list {
+    width: 100%;
 }
 
 .ds-index-form-list {
-    width: 363px;
-    height: 500px;
+    width: 100%;
 }
 
 .ds-oc-form-list {
@@ -1144,10 +1148,6 @@ option {
     border-top: 1px solid #999 !important;
 }
 
-.ds-no-horizontal-scrollbar {
-    overflow-x: hidden;
-}
-
 .ds-modal-footer {
     background-color: #f5f5f5 !important;
     padding: 10px;
@@ -1170,11 +1170,11 @@ option {
 }
 
 .ds-config-header {
-    margin-bottom: 25px;
+    margin-bottom: 20px;
 }
 
 .ds-sub-header {
-    margin-top: 25px;
+    margin-top: 35px !important;
     margin-bottom: 10px;
 }
 
@@ -1219,10 +1219,26 @@ option {
 }
 
 .ds-accordion-panel {
-    padding-left: 25px;
     margin-top: 10px;
 }
 
+.ds-margin-top {
+    margin-top: 10px;
+}
+
+.ds-margin-top-lg {
+    margin-top: 20px !important;
+}
+
+.ds-margin-top-xlg {
+    margin-top: 35px !important;
+}
+
+.ds-modal-spinner {
+    margin-top: 10px;
+    text-align: center;
+}
+
 .ds-accordion-header {
     margin-bottom: 15px;
     margin-top: 0px;
@@ -1278,8 +1294,9 @@ option {
 }
 
 .ds-tree-content {
-    margin: 33px;
-    margin-top: 20px;
+    margin-left: 25px;
+    margin-top: 25px;
+    width: 100%;
 }
 
 .ds-select {
@@ -1361,6 +1378,10 @@ option {
     margin-top: 10px;
 }
 
+.ds-save-btn {
+    margin-top: 20px !important;
+}
+
 .ds-spacing-sm {
     margin-right: 10px;
 }
@@ -1438,12 +1459,11 @@ option {
 .ds-input-auto {
     width: 100%;
     margin-right: 10px;
+    padding-left: 5px;
 }
 
 .content-view-pf-pagination > div > span:last-child {
-    margin-left: 8px;
     position: relative;
-    top: -8px;
 }
 
 tbody:nth-child(even) {
@@ -1459,6 +1479,10 @@ tbody:nth-child(even) {
     margin-left: 5px;
 }
 
+.ds-raise-button {
+    margin-top: -5px !important;
+}
+
 .ds-plugin-spinner {
     margin-top: 20px;
     margin-bottom: 10px;
@@ -1508,3 +1532,93 @@ tbody:nth-child(even) {
 .rbt-input-multi {
     height: auto !important;
 }
+
+.list-group {
+    margin-bottom: 1px !important;
+}
+
+.ds-tab-table {
+    margin-top: 25px !important;
+}
+
+.ds-nav-med {
+    font-size: 12px !important;
+}
+
+.ds-table-pagination {
+    background-color: transparent !important;
+    border: 1px solid #909090;
+}
+
+.ds-vlv-label {
+    width: 50px;
+}
+
+.list-view-pf-view {
+    margin-top: 10px;
+}
+
+.ds-fadein {
+  visibility: visible;
+  opacity: 1;
+  transition: opacity 0.5s linear;
+}
+
+.ds-fadeout {
+  visibility: hidden;
+  opacity: 0;
+  transition: visibility 0s 0s, opacity 1s linear;
+}
+
+.ds-col-append {
+    /* Move this item to the left to offset PF margins */
+    margin-left: -35px;
+    padding-right: 0px;
+    word-wrap: break-word;
+}
+
+.ds-word-wrap {
+    word-wrap: break-word;
+    padding-top: 3px;
+}
+
+.ds-suffix-header {
+    font-size: 16px;
+    margin-bottom: 15px;
+}
+
+.ds-no-padding () {
+    padding: 0 !imporant;
+}
+
+.alert {
+    max-width: 600px;
+}
+
+.ds-confirm {
+    margin-left: 5%;
+    margin-top: 5%;
+}
+
+.treeview .list-group-item {
+    /* remove focus border */
+    outline: none;
+}
+
+.treeitem-row {
+    display: block;
+    outline: none;
+}
+
+.treeview .list-group-item.node-selected > .treeitem-row {
+    background: #0088ce !important;
+    border-color: #0088ce !important;
+    color: #fff !important;
+    display: block;
+}
+
+.treeview-hover .treeitem-row:hover {
+    background-color: #def3ff;
+    border-color: #bee1f4;
+    display: block;
+}
diff --git a/src/cockpit/389-console/src/database.jsx b/src/cockpit/389-console/src/database.jsx
new file mode 100644
index 0000000..ccc2c19
--- /dev/null
+++ b/src/cockpit/389-console/src/database.jsx
@@ -0,0 +1,1223 @@
+import cockpit from "cockpit";
+import React from "react";
+import { NotificationController } from "./lib/notifications.jsx";
+import { log_cmd } from "./lib/tools.jsx";
+import {
+    ChainingConfig,
+    ChainingDatabaseConfig
+} from "./lib/database/chaining.jsx";
+import { GlobalDatabaseConfig } from "./lib/database/databaseConfig.jsx";
+import { Suffix } from "./lib/database/suffix.jsx";
+import { Backups } from "./lib/database/backups.jsx";
+import {
+    Modal,
+    Icon,
+    Form,
+    Button,
+    noop,
+    TreeView,
+    Spinner
+} from "patternfly-react";
+import PropTypes from "prop-types";
+import "./css/ds.css";
+
+const DB_CONFIG = "dbconfig";
+const CHAINING_CONFIG = "chaining-config";
+const BACKUP_CONFIG = "backups";
+const treeViewContainerStyles = {
+    width: '295px',
+};
+
+export class Database extends React.Component {
+    constructor(props) {
+        super(props);
+        this.state = {
+            notifications: [],
+            errObj: {},
+            nodes: [],
+            node_name: "",
+            node_text: "",
+            dbtype: "",
+            showSuffixModal: false,
+            createSuffix: "",
+            createBeName: "",
+            createRootNode: false,
+            // DB config
+            globalDBConfig: {},
+            configUpdated: 0,
+            // Chaining Config
+            chainingConfig: {},
+            chainingUpdated: 0,
+            // Chaining Link
+            chainingLoading: false,
+            // Suffix
+            suffixLoading: false,
+            attributes: [],
+            // Loaded suffix configurations
+            suffix: {},
+            // Other
+            LDIFRows: [],
+            BackupRows: [],
+            suffixList: [],
+            loaded: false,
+        };
+
+        // General
+        this.selectNode = this.selectNode.bind(this);
+        this.removeNotification = this.removeNotification.bind(this);
+        this.addNotification = this.addNotification.bind(this);
+        this.handleChange = this.handleChange.bind(this);
+        this.loadGlobalConfig = this.loadGlobalConfig.bind(this);
+        this.loadLDIFs = this.loadLDIFs.bind(this);
+        this.loadBackups = this.loadBackups.bind(this);
+        this.loadSuffixList = this.loadSuffixList.bind(this);
+
+        // Suffix
+        this.showSuffixModal = this.showSuffixModal.bind(this);
+        this.closeSuffixModal = this.closeSuffixModal.bind(this);
+        this.handleChange = this.handleChange.bind(this);
+        this.createSuffix = this.createSuffix.bind(this);
+        this.loadSuffix = this.loadSuffix.bind(this);
+        this.loadSuffixConfig = this.loadSuffixConfig.bind(this);
+        this.loadIndexes = this.loadIndexes.bind(this);
+        this.loadVLV = this.loadVLV.bind(this);
+        this.loadAttrEncrypt = this.loadAttrEncrypt.bind(this);
+        this.loadReferrals = this.loadReferrals.bind(this);
+        this.getAutoTuning = this.getAutoTuning.bind(this);
+        this.loadAttrs = this.loadAttrs.bind(this);
+
+        // ChainingConfig
+        this.loadChainingLink = this.loadChainingLink.bind(this);
+        this.loadChainingConfig = this.loadChainingConfig.bind(this);
+        this.loadAvailableControls = this.loadAvailableControls.bind(this);
+        this.loadDefaultConfig = this.loadDefaultConfig.bind(this);
+
+        // Other
+        this.loadSuffixTree = this.loadSuffixTree.bind(this);
+    }
+
+    componentWillMount () {
+        this.loadGlobalConfig();
+        this.loadChainingConfig();
+        this.loadLDIFs();
+        this.loadBackups();
+        this.loadSuffixList();
+    }
+
+    componentDidMount() {
+        this.loadSuffixTree(false);
+    }
+
+    componentDidUpdate(prevProps) {
+        if (this.props.serverId !== prevProps.serverId) {
+            this.loadSuffixTree(false);
+        }
+    }
+
+    loadSuffixList () {
+        const cmd = [
+            "dsconf", "-j", "ldapi://%2fvar%2frun%2fslapd-" + this.props.serverId + ".socket",
+            "backend", "suffix", "list", "--suffix"
+        ];
+        log_cmd("loadSuffixList", "Get a list of all the suffixes", cmd);
+        cockpit
+                .spawn(cmd, { superuser: true, err: "message" })
+                .done(content => {
+                    const suffixList = JSON.parse(content);
+                    this.setState(() => (
+                        {suffixList: suffixList.items}
+                    ));
+                });
+    }
+
+    loadGlobalConfig () {
+        const cmd = [
+            "dsconf", "-j", "ldapi://%2fvar%2frun%2fslapd-" + this.props.serverId + ".socket",
+            "backend", "config", "get"
+        ];
+        log_cmd("loadGlobalConfig", "Load the database global configuration", cmd);
+        cockpit
+                .spawn(cmd, { superuser: true, err: "message" })
+                .done(content => {
+                    const config = JSON.parse(content);
+                    const attrs = config.attrs;
+                    let db_cache_auto = false;
+                    let import_cache_auto = false;
+                    let dbhome = "";
+
+                    if ('nsslapd-db-home-directory' in attrs) {
+                        dbhome = attrs['nsslapd-db-home-directory'];
+                    }
+                    if (attrs['nsslapd-cache-autosize'] != "0") {
+                        db_cache_auto = true;
+                    }
+                    if (attrs['nsslapd-import-cache-autosize'] != "0") {
+                        import_cache_auto = true;
+                    }
+
+                    this.setState(() => (
+                        {
+                            globalDBConfig:
+                                {
+                                    loading: false,
+                                    db_cache_auto: db_cache_auto,
+                                    import_cache_auto: import_cache_auto,
+                                    looklimit: attrs['nsslapd-lookthroughlimit'],
+                                    idscanlimit: attrs['nsslapd-idlistscanlimit'],
+                                    pagelooklimit: attrs['nsslapd-pagedlookthroughlimit'],
+                                    pagescanlimit: attrs['nsslapd-pagedidlistscanlimit'],
+                                    rangelooklimit: attrs['nsslapd-rangelookthroughlimit'],
+                                    autosize: attrs['nsslapd-cache-autosize'],
+                                    autosizesplit: attrs['nsslapd-cache-autosize-split'],
+                                    dbcachesize: attrs['nsslapd-dbcachesize'],
+                                    txnlogdir: attrs['nsslapd-db-logdirectory'],
+                                    dbhomedir: dbhome,
+                                    dblocks: attrs['nsslapd-db-locks'],
+                                    chxpoint: attrs['nsslapd-db-checkpoint-interval'],
+                                    compactinterval: attrs['nsslapd-db-compactdb-interval'],
+                                    importcacheauto: attrs['nsslapd-import-cache-autosize'],
+                                    importcachesize: attrs['nsslapd-import-cachesize'],
+                                },
+                            loaded: true,
+                            configUpdated: 1
+                        }), this.setState({configUpdated: 0}));
+                })
+                .fail(err => {
+                    this.props.addNotification(
+                        "error",
+                        `Error loading database configuration - ${err}`
+                    );
+                });
+    }
+
+    loadAvailableControls () {
+        // Get the available control oids from rootdse
+        const cmd = [
+            "dsconf", "-j", "ldapi://%2fvar%2frun%2fslapd-" + this.props.serverId + ".socket",
+            "chaining", "config-get", "--avail-controls"
+        ];
+        log_cmd("loadChainingConfig", "Get available controls", cmd);
+        cockpit
+                .spawn(cmd, { superuser: true, err: "message" })
+                .done(content => {
+                    const config = JSON.parse(content);
+                    const availableOids = config.items.filter((el) => !this.state.chainingConfig.oidList.includes(el));
+                    this.setState((prevState) => (
+                        {
+                            chainingConfig: {
+                                ...this.state.chainingConfig,
+                                availableOids: availableOids,
+                            },
+                            chainingUpdated: 1
+                        }
+                    ), this.setState({chainingUpdated: 0})
+                    );
+                });
+    }
+
+    loadDefaultConfig() {
+        let cmd = [
+            "dsconf", "-j", "ldapi://%2fvar%2frun%2fslapd-" + this.props.serverId + ".socket",
+            "chaining", "config-get-def"
+        ];
+        log_cmd("loadChainingConfig", "Load chaining default configuration", cmd);
+        cockpit
+                .spawn(cmd, { superuser: true, err: "message" })
+                .done(content => {
+                    const config = JSON.parse(content);
+                    const attr = config.attrs;
+                    let checkAci = false;
+                    let proxy = false;
+                    let refOnScope = false;
+                    let useStartTLS = false;
+
+                    if (attr['nschecklocalaci'] == "on") {
+                        checkAci = true;
+                    }
+                    if (attr['nsproxiedauthorization'] == "on") {
+                        proxy = true;
+                    }
+                    if (attr['nsreferralonscopedsearch'] == "on") {
+                        refOnScope = true;
+                    }
+                    if (attr['nsusestarttls'] == "on") {
+                        useStartTLS = true;
+                    }
+                    this.setState(() => (
+                        {
+                            chainingConfig: {
+                                ...this.state.chainingConfig,
+                                defSearchCheck: attr['nsabandonedsearchcheckinterval'],
+                                defBindConnLimit: attr['nsbindconnectionslimit'],
+                                defBindTimeout: attr['nsbindtimeout'],
+                                defBindRetryLimit: attr['nsbindretrylimit'],
+                                defConcurLimit: attr['nsconcurrentbindlimit'],
+                                defConcurOpLimit: attr['nsconcurrentoperationslimit'],
+                                defConnLife: attr['nsconnectionlife'],
+                                defHopLimit: attr['nshoplimit'],
+                                defDelay: attr['nsmaxresponsedelay'],
+                                defTestDelay: attr['nsmaxtestresponsedelay'],
+                                defOpConnLimit: attr['nsoperationconnectionslimit'],
+                                defSizeLimit: attr['nsslapd-sizelimit'],
+                                defTimeLimit: attr['nsslapd-timelimit'],
+                                defProxy: proxy,
+                                defRefOnScoped: refOnScope,
+                                defCheckAci: checkAci,
+                                defUseStartTLS: useStartTLS,
+                            }
+                        }
+                    ), this.loadAvailableControls());
+                })
+                .fail(err => {
+                    this.props.addNotification(
+                        "error",
+                        `Error loading default chaining configuration - ${err}`
+                    );
+                    this.setState({
+                        loading: false
+                    });
+                });
+    }
+
+    loadChainingConfig() {
+        let cmd = [
+            "dsconf", "-j", "ldapi://%2fvar%2frun%2fslapd-" + this.props.serverId + ".socket",
+            "chaining", "config-get"
+        ];
+        log_cmd("loadChainingConfig", "Load chaining OIDs and Controls", cmd);
+        cockpit
+                .spawn(cmd, { superuser: true, err: "message" })
+                .done(content => {
+                    const config = JSON.parse(content);
+                    let availableComps = config.attrs.nspossiblechainingcomponents;
+                    let compList = [];
+                    if ('nsactivechainingcomponents' in config.attrs) {
+                        availableComps = config.attrs.nspossiblechainingcomponents.filter((el) => !config.attrs.nsactivechainingcomponents.includes(el));
+                        compList = config.attrs.nsactivechainingcomponents;
+                    }
+                    this.setState(() => (
+                        {
+                            chainingConfig: {
+                                ...this.state.chainingConfig,
+                                oidList: config.attrs.nstransmittedcontrols,
+                                compList: compList,
+                                availableComps: availableComps
+                            }
+                        }
+                    ), this.loadDefaultConfig());
+                });
+    }
+
+    loadSuffixTree(fullReset) {
+        const cmd = [
+            "dsconf", "-j", "ldapi://%2fvar%2frun%2fslapd-" + this.props.serverId + ".socket",
+            "backend", "get-tree",
+        ];
+        log_cmd("getTree", "Start building the suffix tree", cmd);
+        cockpit
+                .spawn(cmd, { superuser: true, err: "message" })
+                .done(content => {
+                    let treeData = JSON.parse(content);
+                    let basicData = [
+                        {
+                            text: "Global Database Configuration",
+                            selectable: true,
+                            selected: true,
+                            icon: "pficon-settings",
+                            id: "dbconfig",
+
+                        },
+                        {
+                            text: "Chaining Configuration",
+                            icon: "glyphicon glyphicon-link",
+                            selectable: true,
+                            id: "chaining-config",
+                        },
+                        {
+                            text: "Backups & LDIFS",
+                            icon: "glyphicon glyphicon-duplicate",
+                            selectable: true,
+                            id: "backups",
+                        },
+                        {
+                            "text": "Suffixes",
+                            "icon": "pficon-catalog",
+                            "state": {"expanded": true},
+                            selectable: false,
+                            "nodes": []
+                        }
+                    ];
+                    let current_node = this.state.node_name;
+                    if (fullReset) {
+                        current_node = DB_CONFIG;
+                    }
+                    basicData[3].nodes = treeData;
+
+                    this.setState(() => ({
+                        nodes: basicData,
+                        node_name: current_node,
+
+                    }), this.update_tree_nodes);
+                });
+    }
+
+    loadChainingLink(suffix) {
+        this.setState({
+            chainingLoading: true,
+        });
+
+        const cmd = [
+            "dsconf", "-j", "ldapi://%2fvar%2frun%2fslapd-" + this.props.serverId + ".socket",
+            "chaining", "link-get", suffix
+        ];
+        log_cmd("loadChainingLink", "Load chaining link configuration", cmd);
+        cockpit
+                .spawn(cmd, { superuser: true, err: "message" })
+                .done(content => {
+                    const config = JSON.parse(content);
+                    const attrs = config.attrs;
+                    let bindmech = "Simple";
+                    let usestarttls = false;
+                    let refOnScope = false;
+                    let proxiedAuth = false;
+                    let checkLocalAci = false;
+
+                    // Handler checkboxes, need to convert "on" to true
+                    if (config.attrs.nsreferralonscopedsearch[0] == "on") {
+                        refOnScope = true;
+                    }
+                    if (config.attrs.nsproxiedauthorization[0] == "on") {
+                        proxiedAuth = true;
+                    }
+                    if (config.attrs.nschecklocalaci[0] == "on") {
+                        checkLocalAci = true;
+                    }
+                    if (config.attrs.nsusestarttls[0] == "on") {
+                        usestarttls = true;
+                    }
+                    if (config.attrs.nsbindmechanism !== undefined) {
+                        bindmech = config.attrs.nsbindmechanism[0];
+                    }
+
+                    this.setState({
+                        [suffix]: {
+                            nsfarmserverurl: attrs.nsfarmserverurl[0],
+                            nsmultiplexorbinddn: attrs.nsmultiplexorbinddn[0],
+                            nsmultiplexorcredentials: attrs.nsmultiplexorcredentials[0],
+                            nsmultiplexorcredentials_confirm: attrs.nsmultiplexorcredentials[0],
+                            sizelimit: attrs['nsslapd-sizelimit'][0],
+                            timelimit: attrs['nsslapd-timelimit'][0],
+                            bindconnlimit: attrs.nsbindconnectionslimit[0],
+                            opconnlimit: attrs.nsoperationconnectionslimit[0],
+                            concurrbindlimit: attrs.nsconcurrentbindlimit[0],
+                            bindtimeout: attrs.nsbindtimeout[0],
+                            bindretrylimit: attrs.nsbindretrylimit[0],
+                            concurroplimit: attrs.nsconcurrentoperationslimit[0],
+                            connlifetime: attrs.nsconnectionlife[0],
+                            searchcheckinterval: attrs.nsabandonedsearchcheckinterval[0],
+                            hoplimit: attrs.nshoplimit[0],
+                            nsbindmechanism: bindmech,
+                            nsusestarttls: usestarttls,
+                            nsreferralonscopedsearch: refOnScope,
+                            nsproxiedauthorization: proxiedAuth,
+                            nschecklocalaci: checkLocalAci,
+                        },
+                        chainingLoading: false,
+                    });
+                })
+                .fail(err => {
+                    this.addNotification(
+                        "error",
+                        `Error getting chaining link configuration - ${err}`
+                    );
+                });
+    }
+
+    selectNode(selectedNode) {
+        if (selectedNode.id == "dbconfig" ||
+            selectedNode.id == "chaining-config" ||
+            selectedNode.id == "backups") {
+            // Nothing special to do, these configurations have already been loaded
+            this.setState(prevState => {
+                return {
+                    nodes: this.nodeSelector(prevState.nodes, selectedNode),
+                    node_name: selectedNode.id,
+                    node_text: selectedNode.text,
+                    dbtype: selectedNode.type,
+                    bename: "",
+                };
+            });
+        } else {
+            if (selectedNode.id in this.state) {
+                // This suffix is already cached, just use what we have...
+                this.setState(prevState => {
+                    return {
+                        nodes: this.nodeSelector(prevState.nodes, selectedNode),
+                        node_name: selectedNode.id,
+                        node_text: selectedNode.text,
+                        dbtype: selectedNode.type,
+                        bename: selectedNode.be,
+                    };
+                });
+            } else {
+                // Load this suffix whatever it is...
+                if (selectedNode.type == "dblink") {
+                    // Chained suffix
+                    this.loadChainingLink(selectedNode.id);
+                } else {
+                    // Suffix/subsuffix
+                    this.loadSuffix(selectedNode.id);
+                }
+                this.setState(prevState => {
+                    return {
+                        nodes: this.nodeSelector(prevState.nodes, selectedNode),
+                        node_name: selectedNode.id,
+                        node_text: selectedNode.text,
+                        dbtype: selectedNode.type,
+                        bename: selectedNode.be,
+                    };
+                });
+            }
+        }
+    }
+
+    nodeSelector(nodes, targetNode) {
+        return nodes.map(node => {
+            if (node.nodes) {
+                return {
+                    ...node,
+                    nodes: this.nodeSelector(node.nodes, targetNode),
+                    selected: node.id === targetNode.id ? !node.selected : false
+                };
+            } else if (node.id === targetNode.id) {
+                return { ...node, selected: !node.selected };
+            } else if (node.id !== targetNode.id && node.selected) {
+                return { ...node, selected: false };
+            } else {
+                return node;
+            }
+        });
+    }
+
+    addNotification(type, message, timerdelay, persistent) {
+        this.setState(prevState => ({
+            notifications: [
+                ...prevState.notifications,
+                {
+                    key: prevState.notifications.length + 1,
+                    type: type,
+                    persistent: persistent,
+                    timerdelay: timerdelay,
+                    message: message,
+                }
+            ]
+        }));
+    }
+
+    removeNotification(notificationToRemove) {
+        this.setState({
+            notifications: this.state.notifications.filter(
+                notification => notificationToRemove.key !== notification.key
+            )
+        });
+    }
+
+    update_tree_nodes() {
+        // Set title to the text value of each suffix node.  We need to do this
+        // so we can read long suffixes in the UI tree div
+        let elements = document.getElementsByClassName('treeitem-row');
+        for (let el of elements) {
+            el.setAttribute('title', el.innerText);
+        }
+    }
+
+    showSuffixModal () {
+        this.setState({
+            showSuffixModal: true,
+            errObj: {},
+        });
+    }
+
+    handleChange(e) {
+        const value = e.target.type === 'checkbox' ? e.target.checked : e.target.value;
+        let valueErr = false;
+        let errObj = this.state.errObj;
+        if (value == "") {
+            valueErr = true;
+        }
+        errObj[e.target.id] = valueErr;
+        this.setState({
+            [e.target.id]: value,
+            errObj: errObj
+        });
+    }
+
+    closeSuffixModal() {
+        this.setState({
+            showSuffixModal: false
+        });
+    }
+
+    createSuffix() {
+        // validate
+        let errors = false;
+        let missingArgs = {
+            createSuffix: false,
+            createBeName: false
+        };
+
+        if (this.state.createSuffix == "") {
+            this.addNotification(
+                "warning",
+                `Missing the suffix DN`
+            );
+            missingArgs.createSuffix = true;
+            errors = true;
+        }
+        if (this.state.createBeName == "") {
+            this.addNotification(
+                "warning",
+                `Missing the suffix backend name`
+            );
+            missingArgs.createBeName = true;
+            errors = true;
+        }
+        if (errors) {
+            this.setState({
+                errObj: missingArgs
+            });
+            return;
+        }
+
+        // Create a new suffix
+        const cmd = [
+            "dsconf", "-j", "ldapi://%2fvar%2frun%2fslapd-" + this.props.serverId + ".socket",
+            "backend", "create", "--be-name", this.state.createBeName, '--suffix', this.state.createSuffix,
+        ];
+        if (this.state.createSampleEntries == true) {
+            cmd.push('--create-entries');
+        }
+
+        log_cmd("createSuffix", "Create a new backend", cmd);
+        cockpit
+                .spawn(cmd, { superuser: true, err: "message" })
+                .done(content => {
+                    this.closeSuffixModal();
+                    this.addNotification(
+                        "success",
+                        `Successfully create new suffix`
+                    );
+                    // Refresh tree
+                    this.loadSuffixTree(false);
+                })
+                .fail(err => {
+                    this.addNotification(
+                        "error",
+                        `Error creating suffix - ${err}`
+                    );
+                    this.closeSuffixModal();
+                });
+    }
+
+    getAutoTuning(suffix) {
+        const cmd = [
+            "dsconf", "-j", "ldapi://%2fvar%2frun%2fslapd-" + this.props.serverId + ".socket",
+            "backend", "config", "get"
+        ];
+        log_cmd("getAutoTuning", "Check cache auto tuning", cmd);
+        cockpit
+                .spawn(cmd, { superuser: true, err: "message" })
+                .done(content => {
+                    let config = JSON.parse(content);
+                    if ('nsslapd-cache-autosize' in config.attrs &&
+                        config.attrs['nsslapd-cache-autosize'] != "0") {
+                        this.setState({
+                            [suffix]: {
+                                ...this.state[suffix],
+                                autoTuning: true,
+                            },
+                        });
+                    }
+                });
+    }
+
+    loadSuffixConfig(suffix) {
+        const cmd = [
+            "dsconf", "-j", "ldapi://%2fvar%2frun%2fslapd-" + this.props.serverId + ".socket",
+            "backend", "suffix", "get", suffix
+        ];
+        log_cmd("loadSuffixConfig", "Load suffix config", cmd);
+        cockpit
+                .spawn(cmd, { superuser: true, err: "message" })
+                .done(content => {
+                    const config = JSON.parse(content);
+                    let refs = [];
+                    let readonly = false;
+                    let requireindex = false;
+                    if ('nsslapd-referral' in config.attrs) {
+                        refs = config.attrs['nsslapd-referral'];
+                    }
+                    if ('nsslapd-readonly' in config.attrs) {
+                        if (config.attrs['nsslapd-readonly'] == "on") {
+                            readonly = true;
+                        }
+                    }
+                    if ('nsslapd-require-index' in config.attrs) {
+                        if (config.attrs['nsslapd-require-index'] == "on") {
+                            requireindex = true;
+                        }
+                    }
+                    this.setState({
+                        [suffix]: {
+                            ...this.state[suffix],
+                            refRows: refs,
+                            cachememsize: config.attrs['nsslapd-cachememsize'][0],
+                            cachesize: config.attrs['nsslapd-cachesize'][0],
+                            dncachememsize: config.attrs['nsslapd-dncachememsize'][0],
+                            readOnly: readonly,
+                            requireIndex: requireindex,
+                        }
+                    }, this.getAutoTuning(suffix));
+                });
+    }
+
+    loadVLV(suffix) {
+        const cmd = [
+            "dsconf", "-j", "ldapi://%2fvar%2frun%2fslapd-" + this.props.serverId + ".socket",
+            "backend", "vlv-index", "list", suffix
+        ];
+        log_cmd("loadVLV", "Load VLV indexes", cmd);
+        cockpit
+                .spawn(cmd, { superuser: true, err: "message" })
+                .done(content => {
+                    const config = JSON.parse(content);
+                    this.setState({
+                        [suffix]: {
+                            ...this.state[suffix],
+                            vlvItems: config.items,
+                        }
+                    });
+                });
+    }
+
+    loadAttrEncrypt(suffix) {
+        const cmd = [
+            "dsconf", "-j", "ldapi://%2fvar%2frun%2fslapd-" + this.props.serverId + ".socket",
+            "backend", "attr-encrypt", "--list", "--just-names", suffix
+        ];
+        log_cmd("loadAttrEncrypt", "Load encrypted attrs", cmd);
+        cockpit
+                .spawn(cmd, { superuser: true, err: "message" })
+                .done(content => {
+                    const config = JSON.parse(content);
+                    let rows = [];
+                    for (let row of config.items) {
+                        rows.push({"name": row});
+                    }
+                    this.setState({
+                        [suffix]: {
+                            ...this.state[suffix],
+                            encAttrsRows: rows
+                        }
+                    });
+                });
+    }
+
+    loadIndexes(suffix) {
+        // Load the suffix configurations.  Start with indexes which is the
+        // most time consuming (and which controls the spinner), and spawn new
+        // commands for the other areas.
+        const index_cmd = [
+            "dsconf", "-j", "ldapi://%2fvar%2frun%2fslapd-" + this.props.serverId + ".socket",
+            "backend", "index", "list", suffix
+        ];
+        log_cmd("loadIndexes", "Load backend indexes", index_cmd);
+        cockpit
+                .spawn(index_cmd, { superuser: true, err: "message" })
+                .done(content => {
+                    // Now do the Indexes
+                    const config = JSON.parse(content);
+                    let rows = [];
+                    let systemRows = [];
+                    for (let item of config.items) {
+                        let index = item.attrs;
+                        let types = [];
+                        let mrs = [];
+                        if (index.nsindextype.length > 1) {
+                            types = index.nsindextype.join(', ');
+                        } else {
+                            types = index.nsindextype[0];
+                        }
+                        if ('nsmatchingrule' in index) {
+                            if (index.nsmatchingrule.length > 1) {
+                                mrs = index.nsmatchingrule.join(', ');
+                            } else {
+                                mrs = index.nsmatchingrule[0];
+                            }
+                        }
+                        if (index.nssystemindex[0] == 'true') {
+                            systemRows.push({'name': index.cn, 'types': [types], 'matchingrules': [mrs]});
+                        } else {
+                            rows.push({'name': index.cn, 'types': [types], 'matchingrules': [mrs]});
+                        }
+                    }
+                    this.setState({
+                        [suffix]: {
+                            ...this.state[suffix],
+                            indexRows: rows,
+                            systemIndexRows: systemRows
+                        }
+                    });
+                })
+                .fail(err => {
+                    this.props.addNotification(
+                        "error",
+                        `Error loading indexes for ${suffix} - ${err}`
+                    );
+                });
+    }
+
+    loadReferrals(suffix) {
+        let cmd = [
+            "dsconf", "-j", "ldapi://%2fvar%2frun%2fslapd-" + this.props.serverId + ".socket",
+            "backend", "suffix", "get", suffix
+        ];
+        log_cmd("loadReferrals", "get referrals", cmd);
+        cockpit
+                .spawn(cmd, { superuser: true, err: "message" })
+                .done(content => {
+                    const config = JSON.parse(content);
+                    let refs = [];
+                    if ('nsslapd-referral' in config.attrs) {
+                        refs = config.attrs['nsslapd-referral'];
+                    }
+                    this.setState({
+                        [suffix]: {
+                            ...this.state[suffix],
+                            refRows: refs,
+                        }
+                    });
+                });
+    }
+
+    loadSuffix(suffix) {
+        // Load everything, we must nest cockpit promise so we can proper set
+        // the loading is finished
+        this.setState({
+            activeKey: 1,
+            suffixLoading: true
+        }, this.loadAttrs());
+
+        let cmd = [
+            "dsconf", "-j", "ldapi://%2fvar%2frun%2fslapd-" + this.props.serverId + ".socket",
+            "backend", "suffix", "get", suffix
+        ];
+        log_cmd("loadSuffixConfig", "Load suffix config", cmd);
+        cockpit
+                .spawn(cmd, { superuser: true, err: "message" })
+                .done(content => {
+                    const config = JSON.parse(content);
+                    let refs = [];
+                    let readonly = false;
+                    let requireindex = false;
+                    if ('nsslapd-referral' in config.attrs) {
+                        refs = config.attrs['nsslapd-referral'];
+                    }
+                    if ('nsslapd-readonly' in config.attrs) {
+                        if (config.attrs['nsslapd-readonly'] == "on") {
+                            readonly = true;
+                        }
+                    }
+                    if ('nsslapd-require-index' in config.attrs) {
+                        if (config.attrs['nsslapd-require-index'] == "on") {
+                            requireindex = true;
+                        }
+                    }
+                    this.setState({
+                        [suffix]: {
+                            refRows: refs,
+                            cachememsize: config.attrs['nsslapd-cachememsize'][0],
+                            cachesize: config.attrs['nsslapd-cachesize'][0],
+                            dncachememsize: config.attrs['nsslapd-dncachememsize'][0],
+                            readOnly: readonly,
+                            requireIndex: requireindex,
+                        }
+                    }, this.getAutoTuning(suffix));
+
+                    // Now load VLV indexes
+                    let cmd = [
+                        "dsconf", "-j", "ldapi://%2fvar%2frun%2fslapd-" + this.props.serverId + ".socket",
+                        "backend", "vlv-index", "list", suffix
+                    ];
+                    log_cmd("loadVLV", "Load VLV indexes", cmd);
+                    cockpit
+                            .spawn(cmd, { superuser: true, err: "message" })
+                            .done(content => {
+                                const config = JSON.parse(content);
+                                this.setState({
+                                    [suffix]: {
+                                        ...this.state[suffix],
+                                        vlvItems: config.items,
+                                    }
+                                });
+
+                                let cmd = [
+                                    "dsconf", "-j", "ldapi://%2fvar%2frun%2fslapd-" + this.props.serverId + ".socket",
+                                    "backend", "attr-encrypt", "--list", "--just-names", suffix
+                                ];
+                                log_cmd("loadAttrEncrypt", "Load encrypted attrs", cmd);
+                                cockpit
+                                        .spawn(cmd, { superuser: true, err: "message" })
+                                        .done(content => {
+                                            const config = JSON.parse(content);
+                                            let rows = [];
+                                            for (let row of config.items) {
+                                                rows.push({"name": row});
+                                            }
+                                            this.setState({
+                                                [suffix]: {
+                                                    ...this.state[suffix],
+                                                    encAttrsRows: rows
+                                                }
+                                            });
+                                            const index_cmd = [
+                                                "dsconf", "-j", "ldapi://%2fvar%2frun%2fslapd-" + this.props.serverId + ".socket",
+                                                "backend", "index", "list", suffix
+                                            ];
+                                            log_cmd("loadIndexes", "Load backend indexes", index_cmd);
+                                            cockpit
+                                                    .spawn(index_cmd, { superuser: true, err: "message" })
+                                                    .done(content => {
+                                                        // Now do the Indexes
+                                                        const config = JSON.parse(content);
+                                                        let rows = [];
+                                                        let systemRows = [];
+                                                        for (let item of config.items) {
+                                                            let index = item.attrs;
+                                                            let types = [];
+                                                            let mrs = [];
+                                                            if (index.nsindextype.length > 1) {
+                                                                types = index.nsindextype.join(', ');
+                                                            } else {
+                                                                types = index.nsindextype[0];
+                                                            }
+                                                            if ('nsmatchingrule' in index) {
+                                                                if (index.nsmatchingrule.length > 1) {
+                                                                    mrs = index.nsmatchingrule.join(', ');
+                                                                } else {
+                                                                    mrs = index.nsmatchingrule[0];
+                                                                }
+                                                            }
+                                                            if (index.nssystemindex[0] == 'true') {
+                                                                systemRows.push({'name': index.cn, 'types': [types], 'matchingrules': [mrs]});
+                                                            } else {
+                                                                rows.push({'name': index.cn, 'types': [types], 'matchingrules': [mrs]});
+                                                            }
+                                                        }
+                                                        this.setState({
+                                                            [suffix]: {
+                                                                ...this.state[suffix],
+                                                                indexRows: rows,
+                                                                systemIndexRows: systemRows,
+                                                            },
+                                                            suffixLoading: false
+                                                        });
+                                                    })
+                                                    .fail(err => {
+                                                        this.props.addNotification(
+                                                            "error",
+                                                            `Error loading indexes for ${suffix} - ${err}`
+                                                        );
+                                                        this.setState({
+                                                            suffixLoading: false
+                                                        });
+                                                    });
+                                        });
+                            });
+                });
+    }
+
+    loadLDIFs() {
+        const cmd = [
+            "dsctl", "-j", this.props.serverId, "ldifs"
+        ];
+        log_cmd("loadLDIFs", "Load LDIF Files", cmd);
+        cockpit
+                .spawn(cmd, { superuser: true, err: "message" })
+                .done(content => {
+                    const config = JSON.parse(content);
+                    let rows = [];
+                    for (let row of config.items) {
+                        rows.push({'name': row[0], 'date': [row[1]], 'size': [row[2]], 'suffix': [row[3]]});
+                    }
+                    this.setState({
+                        LDIFRows: rows,
+                    });
+                });
+    }
+
+    loadBackups() {
+        const cmd = [
+            "dsctl", "-j", this.props.serverId, "backups"
+        ];
+        log_cmd("loadLDIFs", "Load Backups", cmd);
+        cockpit
+                .spawn(cmd, { superuser: true, err: "message" })
+                .done(content => {
+                    const config = JSON.parse(content);
+                    let rows = [];
+                    for (let row of config.items) {
+                        rows.push({'name': row[0], 'date': [row[1]], 'size': [row[2]]});
+                    }
+                    this.setState({
+                        BackupRows: rows
+                    }, this.loadLDIFs());
+                });
+    }
+
+    loadAttrs() {
+        // Now get the schema that various tabs use
+        const attr_cmd = [
+            "dsconf", "-j", "ldapi://%2fvar%2frun%2fslapd-" + this.props.serverId + ".socket",
+            "schema", "attributetypes", "list"
+        ];
+        log_cmd("Suffixes", "Get attrs", attr_cmd);
+        cockpit
+                .spawn(attr_cmd, { superuser: true, err: "message" })
+                .done(content => {
+                    let attrContent = JSON.parse(content);
+                    let attrs = [];
+                    for (let content of attrContent['items']) {
+                        attrs.push(content.name);
+                    }
+                    this.setState({
+                        attributes: attrs,
+                    });
+                })
+                .fail(err => {
+                    this.props.addNotification(
+                        "error",
+                        `Failed to get attributes - ${err}`
+                    );
+                });
+    }
+
+    render() {
+        const { nodes } = this.state;
+        let db_element = "";
+        if (this.state.loaded) {
+            if (this.state.node_name == DB_CONFIG || this.state.node_name == "") {
+                db_element =
+                    <GlobalDatabaseConfig
+                        serverId={this.props.serverId}
+                        addNotification={this.addNotification}
+                        reload={this.loadGlobalConfig}
+                        data={this.state.globalDBConfig}
+                        key={this.state.configUpdated}
+                    />;
+            } else if (this.state.node_name == CHAINING_CONFIG) {
+                db_element =
+                    <ChainingDatabaseConfig
+                        serverId={this.props.serverId}
+                        addNotification={this.addNotification}
+                        reload={this.loadChainingConfig}
+                        data={this.state.chainingConfig}
+                        key={this.state.chainingUpdated}
+                    />;
+            } else if (this.state.node_name == BACKUP_CONFIG) {
+                db_element =
+                    <Backups
+                        serverId={this.props.serverId}
+                        addNotification={this.addNotification}
+                        backups={this.state.BackupRows}
+                        suffixes={this.state.suffixList}
+                        ldifs={this.state.LDIFRows}
+                        reload={this.loadBackups}
+                    />;
+            } else if (this.state.node_name != "") {
+                // We have a suffix, or database link
+                if (this.state.dbtype == "suffix" || this.state.dbtype == "subsuffix") {
+                    if (this.state.suffixLoading) {
+                        db_element =
+                            <div className="ds-loading-spinner ds-center">
+                                <p />
+                                <h4>Loading suffix configuration for <b>{this.state.node_text} ...</b></h4>
+                                <Spinner loading size="md" />
+                            </div>;
+                    } else {
+                        db_element =
+                            <Suffix
+                                serverId={this.props.serverId}
+                                suffix={this.state.node_text}
+                                bename={this.state.bename}
+                                loadSuffixTree={this.loadSuffixTree}
+                                reload={this.loadSuffix}
+                                reloadRefs={this.loadReferrals}
+                                reloadIndexes={this.loadIndexes}
+                                reloadVLV={this.loadVLV}
+                                reloadAttrEnc={this.loadAttrEncrypt}
+                                addNotification={this.addNotification}
+                                reloadLDIFs={this.loadLDIFs}
+                                LDIFRows={this.state.LDIFRows}
+                                dbtype={this.state.dbtype}
+                                data={this.state[this.state.node_text]}
+                                attrs={this.state.attributes}
+                                key={this.state.node_text}
+                            />;
+                    }
+                } else {
+                    // Chaining
+                    if (this.state.chainingLoading) {
+                        db_element =
+                            <div className="ds-loading-spinner ds-center">
+                                <p />
+                                <h4>Loading chaining configuration for <b>{this.state.node_text} ...</b></h4>
+                                <Spinner loading size="md" />
+                            </div>;
+                    } else {
+                        db_element =
+                            <ChainingConfig
+                                serverId={this.props.serverId}
+                                suffix={this.state.node_text}
+                                bename={this.state.bename}
+                                loadSuffixTree={this.loadSuffixTree}
+                                addNotification={this.addNotification}
+                                data={this.state[this.state.node_text]}
+                                reload={this.loadChainingLink}
+                            />;
+                    }
+                }
+            }
+        }
+
+        return (
+            <div className="container-fluid">
+                <NotificationController
+                    notifications={this.state.notifications}
+                    removeNotificationAction={this.removeNotification}
+                />
+                <div className="ds-container">
+                    <div>
+                        <div className="ds-tree">
+                            <div className="tree-view-container" id="db-tree"
+                                style={treeViewContainerStyles}>
+                                <TreeView
+                                    nodes={nodes}
+                                    highlightOnHover
+                                    highlightOnSelect
+                                    selectNode={this.selectNode}
+                                />
+                            </div>
+                        </div>
+                        <div>
+                            <button className="btn btn-primary save-button"
+                                onClick={this.showSuffixModal}>Create Suffix</button>
+                        </div>
+                    </div>
+                    <div className="ds-tree-content">
+                        {db_element}
+                    </div>
+                </div>
+                <CreateSuffixModal
+                    showModal={this.state.showSuffixModal}
+                    closeHandler={this.closeSuffixModal}
+                    handleChange={this.handleChange}
+                    saveHandler={this.createSuffix}
+                    error={this.state.errObj}
+                />
+            </div>
+        );
+    }
+}
+
+class CreateSuffixModal extends React.Component {
+    render() {
+        const {
+            showModal,
+            closeHandler,
+            handleChange,
+            saveHandler,
+            error
+        } = this.props;
+
+        return (
+            <Modal show={showModal} onHide={closeHandler}>
+                <div className="ds-no-horizontal-scrollbar">
+                    <Modal.Header>
+                        <button
+                            className="close"
+                            onClick={closeHandler}
+                            aria-hidden="true"
+                            aria-label="Close"
+                        >
+                            <Icon type="pf" name="close" />
+                        </button>
+                        <Modal.Title>
+                            Create New Suffix
+                        </Modal.Title>
+                    </Modal.Header>
+                    <Modal.Body>
+                        <Form horizontal autoComplete="off">
+                            <div className="ds-inline">
+                                <div>
+                                    <label htmlFor="createSuffix" className="ds-config-label" title="Database Suffix DN (nsslapd-suffix)">
+                                        Suffix DN</label><input onChange={handleChange} className={error.createSuffix ? "ds-input-bad" : "ds-input"} type="text" id="createSuffix" size="40" />
+                                </div>
+                                <div>
+                                    <label htmlFor="createBeName" className="ds-config-label" title="Database backend name (nsslapd-backend)">
+                                        Backend Name</label><input onChange={handleChange} className={error.createBeName ? "ds-input-bad" : "ds-input"} type="text" id="createBeName" size="40" />
+                                </div>
+                                <div>
+                                    <p />
+                                    <input type="checkbox" className="ds-config-checkbox" id="createSampleEntries" onChange={handleChange} /><label
+                                        htmlFor="createSampleEntries" className="ds-label" title="Create the datbase with sample entries"> Create Sample Entries</label>
+                                </div>
+                            </div>
+                        </Form>
+                    </Modal.Body>
+                    <Modal.Footer>
+                        <Button
+                            bsStyle="default"
+                            className="btn-cancel"
+                            onClick={closeHandler}
+                        >
+                            Cancel
+                        </Button>
+                        <Button
+                            bsStyle="primary"
+                            onClick={saveHandler}
+                        >
+                            Create Suffix
+                        </Button>
+                    </Modal.Footer>
+                </div>
+            </Modal>
+        );
+    }
+}
+
+// Property types and defaults
+
+Database.propTypes = {
+    serverId: PropTypes.string
+};
+
+Database.defaultProps = {
+    serverId: ""
+};
+
+CreateSuffixModal.propTypes = {
+    showModal: PropTypes.bool,
+    closeHandler: PropTypes.func,
+    handleChange: PropTypes.func,
+    saveHandler: PropTypes.func,
+    error: PropTypes.object,
+};
+
+CreateSuffixModal.defaultProps = {
+    showModal: false,
+    closeHandler: noop,
+    handleChange: noop,
+    saveHandler: noop,
+    error: {},
+};
diff --git a/src/cockpit/389-console/src/ds.js b/src/cockpit/389-console/src/ds.js
index c735a86..d309845 100644
--- a/src/cockpit/389-console/src/ds.js
+++ b/src/cockpit/389-console/src/ds.js
@@ -9,7 +9,7 @@ var dn_regex = new RegExp( "^([A-Za-z]+=.*)" );
  */
 var server_page_loaded = 0;
 var security_page_loaded = 0;
-var db_page_loaded = 0;
+var db_page_loaded = 1;
 var repl_page_loaded = 0;
 var plugin_page_loaded = 1;
 var schema_page_loaded = 0;
@@ -433,4 +433,8 @@ $(window.document).ready(function() {
     $(".all-pages").hide();
     $("#plugin-content").show();
   });
+  $("#database-tab").on("click", function() {
+    $(".all-pages").hide();
+    $("#database-content").show();
+  });
 });
diff --git a/src/cockpit/389-console/src/index.es6 b/src/cockpit/389-console/src/index.es6
index bc74f51..7dfd433 100644
--- a/src/cockpit/389-console/src/index.es6
+++ b/src/cockpit/389-console/src/index.es6
@@ -1,6 +1,7 @@
 import React from "react";
 import ReactDOM from "react-dom";
 import { Plugins } from "./plugins.jsx";
+import { Database } from "./database.jsx";
 
 var serverIdElem;
 
@@ -13,10 +14,18 @@ function renderReactDOM(clear) {
                 .getElementById("select-server")
                 .value.replace("slapd-", "");
     }
+
+    // Plugins Tab
     ReactDOM.render(
         <Plugins serverId={serverIdElem} />,
         document.getElementById("plugins")
     );
+
+    // Database tab
+    ReactDOM.render(
+        <Database serverId={serverIdElem} />,
+        document.getElementById("database")
+    );
 }
 
 // We have to create the wrappers because this is no simple way
diff --git a/src/cockpit/389-console/src/index.html b/src/cockpit/389-console/src/index.html
index b23a722..5015717 100644
--- a/src/cockpit/389-console/src/index.html
+++ b/src/cockpit/389-console/src/index.html
@@ -22,7 +22,6 @@
   <script src="schema.js"></script>
   <script src="servers.js"></script>
   <script src="security.js"></script>
-  <script src="backend.js"></script>
   <script src="replication.js"></script>
   <script src="monitor.js"></script>
   <link href="static/bootstrap.min.css" rel="stylesheet">
@@ -101,16 +100,10 @@
             </li>
 
             <!-- Database navtab -->
-            <li class="dropdown ds-nav-tab">
-              <a href="#0" class="dropdown-toggle ds-tab-list" data-toggle="dropdown" id="database-tab">
+            <li class="ds-nav-tab">
+              <a href="#0" class="ds-tab-list ds-tab-standalone" id="database-tab">
                 Database
-                <b class="caret"></b>
               </a>
-              <ul class="dropdown-menu dropup ds-nav-item">
-                <li><a href="#0" class="ds-nav-choice" id="db-chaining-btn" parent-id="database-tab">Chaining Settings</a></li>
-                <li><a href="#0" class="ds-nav-choice" id="db-global-btn" parent-id="database-tab">Global Database Settings</a></li>
-                <li><a href="#0" class="ds-nav-choice" id="db-suffix-btn"   parent-id="database-tab">Database Management</a></li>
-              </ul>
             </li>
 
             <!-- Replication navtab -->
@@ -527,6 +520,7 @@
       </div>
 
       <div id="database-content" class="all-pages" hidden>
+        <div id="database"></div>
       </div>
 
       <div id="replication-content" class="all-pages" hidden>
diff --git a/src/cockpit/389-console/src/lib/database/attrEncryption.jsx b/src/cockpit/389-console/src/lib/database/attrEncryption.jsx
new file mode 100644
index 0000000..6965d72
--- /dev/null
+++ b/src/cockpit/389-console/src/lib/database/attrEncryption.jsx
@@ -0,0 +1,184 @@
+import cockpit from "cockpit";
+import React from "react";
+import { ConfirmPopup } from "../notifications.jsx";
+import { EncryptedAttrTable } from "./databaseTables.jsx";
+import {
+    Row,
+    Col,
+    Button,
+    noop
+} from "patternfly-react";
+import PropTypes from "prop-types";
+import { Typeahead } from "react-bootstrap-typeahead";
+import { log_cmd } from "../tools.jsx";
+import "../../css/ds.css";
+
+export class AttrEncryption extends React.Component {
+    constructor (props) {
+        super(props);
+
+        this.state = {
+            showConfirmAttrDelete: false,
+            typeahead: "",
+            addAttr: "",
+            delAttr: "",
+        };
+
+        // Delete referral and confirmation
+        this.showConfirmAttrDelete = this.showConfirmAttrDelete.bind(this);
+        this.closeConfirmAttrDelete = this.closeConfirmAttrDelete.bind(this);
+        this.handleTypeaheadChange = this.handleTypeaheadChange.bind(this);
+        this.addEncryptedAttr = this.addEncryptedAttr.bind(this);
+        this.delEncryptedAttr = this.delEncryptedAttr.bind(this);
+    }
+
+    showConfirmAttrDelete (item) {
+        this.setState({
+            showConfirmAttrDelete: true,
+            delAttr: item.name
+        });
+    }
+
+    closeConfirmAttrDelete() {
+        this.setState({
+            showConfirmAttrDelete: false
+        });
+    }
+
+    handleTypeaheadChange (value) {
+        this.setState({
+            addAttr: value
+        });
+    }
+
+    addEncryptedAttr () {
+        // reset typeahead input field
+        this.typeahead.getInstance().clear();
+        if (this.state.addAttr == "") {
+            return;
+        }
+
+        // Add the new encrypted attr
+        const cmd = [
+            "dsconf", "-j", "ldapi://%2fvar%2frun%2fslapd-" + this.props.serverId + ".socket",
+            "backend", "attr-encrypt", "--add-attr=" + this.state.addAttr, this.props.suffix
+        ];
+        log_cmd("addEncryptedAttr", "Delete suffix referral", cmd);
+        cockpit
+                .spawn(cmd, { superuser: true, err: "message" })
+                .done(content => {
+                    this.props.reload(this.props.suffix);
+                    this.props.addNotification(
+                        "success",
+                        `Successfully added encrypted attribute`
+                    );
+                })
+                .fail(err => {
+                    this.props.reload(this.props.suffix);
+                    this.props.addNotification(
+                        "error",
+                        `Failed to delete encrypted attribute - ${err}`
+                    );
+                });
+    }
+
+    delEncryptedAttr() {
+        const cmd = [
+            "dsconf", "-j", "ldapi://%2fvar%2frun%2fslapd-" + this.props.serverId + ".socket",
+            "backend", "attr-encrypt", "--del-attr=" + this.state.delAttr, this.props.suffix
+        ];
+        log_cmd("delEncryptedAttr", "Delete encrypted attribute", cmd);
+        cockpit
+                .spawn(cmd, { superuser: true, err: "message" })
+                .done(content => {
+                    this.props.reload(this.props.suffix);
+                    this.props.addNotification(
+                        "success",
+                        `Encrypted attribute successfully deleted`
+                    );
+                })
+                .fail(err => {
+                    this.props.reload(this.props.suffix);
+                    this.props.addNotification(
+                        "error",
+                        `Failure deleting encrypted attribute - ${err}`
+                    );
+                });
+    }
+
+    render() {
+        const delAttr = <b>{this.state.delAttr}</b>;
+
+        // Update the available list of attrs for the Typeahead
+        let fullList = [];
+        let attrs = [];
+        for (let attrProp of this.props.rows) {
+            fullList.push(attrProp.name);
+        }
+        for (let attr of this.props.attrs) {
+            if (fullList.indexOf(attr) == -1) {
+                attrs.push(attr);
+            }
+        }
+
+        return (
+            <div>
+                <EncryptedAttrTable
+                    rows={this.props.rows}
+                    loadModalHandler={this.showConfirmAttrDelete}
+                />
+                <p />
+                <Row>
+                    <Col sm={6}>
+                        <Typeahead
+                            id="attrEncrypt"
+                            onChange={value => {
+                                this.handleTypeaheadChange(value);
+                            }}
+                            maxResults={1000}
+                            options={attrs}
+                            placeholder="Type attribute name to be encrypted"
+                            ref={(typeahead) => { this.typeahead = typeahead }}
+                        />
+                    </Col>
+                    <Col sm={3} bsClass="ds-no-padding">
+                        <Button
+                            bsStyle="primary"
+                            onClick={this.addEncryptedAttr}
+                        >
+                            Add Attribute
+                        </Button>
+                    </Col>
+                </Row>
+                <ConfirmPopup
+                    showModal={this.state.showConfirmAttrDelete}
+                    closeHandler={this.closeConfirmAttrDelete}
+                    actionFunc={this.delEncryptedAttr}
+                    actionParam={this.state.attrName}
+                    msg="Are you sure you want to remove this encrypted attribute?"
+                    msgContent={delAttr}
+                />
+            </div>
+        );
+    }
+}
+
+// Property types and defaults
+
+AttrEncryption.propTypes = {
+    rows: PropTypes.array,
+    suffix: PropTypes.string,
+    serverId: PropTypes.string,
+    addNotification: PropTypes.func,
+    attrs: PropTypes.array,
+    reload: PropTypes.func,
+};
+
+AttrEncryption.defaultProps = {
+    rows: [],
+    suffix: "",
+    serverId: "",
+    addNotification: noop,
+    attrs: [],
+    reload: noop,
+};
diff --git a/src/cockpit/389-console/src/lib/database/backups.jsx b/src/cockpit/389-console/src/lib/database/backups.jsx
new file mode 100644
index 0000000..646fb95
--- /dev/null
+++ b/src/cockpit/389-console/src/lib/database/backups.jsx
@@ -0,0 +1,979 @@
+import cockpit from "cockpit";
+import React from "react";
+import { ConfirmPopup } from "../notifications.jsx";
+import { LDIFManageTable, BackupTable } from "./databaseTables.jsx";
+import {
+    Nav,
+    NavItem,
+    TabContent,
+    TabPane,
+    TabContainer,
+    Col,
+    Button,
+    Spinner,
+    Modal,
+    Icon,
+    ControlLabel,
+    FormControl,
+    Form,
+    Row,
+    noop
+} from "patternfly-react";
+import { log_cmd } from "../tools.jsx";
+import PropTypes from "prop-types";
+import "../../css/ds.css";
+
+export class Backups extends React.Component {
+    constructor (props) {
+        super(props);
+        this.state = {
+            activeKey: 1,
+            showConfirmBackupDelete: false,
+            showConfirmBackup: false,
+            showConfirmRestore: false,
+            showRestoreSpinningModal: false,
+            showDelBackupSpinningModal: false,
+            showBackupModal: false,
+            backupSpinning: false,
+            backupName: "",
+            deleteBackup: "",
+            // LDIF
+            showConfirmLDIFDelete: false,
+            showConfirmLDIFImport: false,
+            showLDIFSpinningModal: false,
+            showLDIFDeleteSpinningModal: false,
+            showExportModal: false,
+            exportSpinner: false,
+            ldifName: "",
+            ldifSuffix: "",
+            errObj: {}
+        };
+
+        this.handleNavSelect = this.handleNavSelect.bind(this);
+        this.handleChange = this.handleChange.bind(this);
+
+        // Backups
+        this.doBackup = this.doBackup.bind(this);
+        this.deleteBackup = this.deleteBackup.bind(this);
+        this.restoreBackup = this.restoreBackup.bind(this);
+        this.showConfirmRestore = this.showConfirmRestore.bind(this);
+        this.closeConfirmRestore = this.closeConfirmRestore.bind(this);
+        this.showConfirmBackup = this.showConfirmBackup.bind(this);
+        this.closeConfirmBackup = this.closeConfirmBackup.bind(this);
+        this.showConfirmBackupDelete = this.showConfirmBackupDelete.bind(this);
+        this.closeConfirmBackupDelete = this.closeConfirmBackupDelete.bind(this);
+        this.showBackupModal = this.showBackupModal.bind(this);
+        this.closeBackupModal = this.closeBackupModal.bind(this);
+        this.showRestoreSpinningModal = this.showRestoreSpinningModal.bind(this);
+        this.closeRestoreSpinningModal = this.closeRestoreSpinningModal.bind(this);
+        this.showDelBackupSpinningModal = this.showDelBackupSpinningModal.bind(this);
+        this.closeDelBackupSpinningModal = this.closeDelBackupSpinningModal.bind(this);
+        // LDIFS
+        this.importLDIF = this.importLDIF.bind(this);
+        this.deleteLDIF = this.deleteLDIF.bind(this);
+        this.showConfirmLDIFImport = this.showConfirmLDIFImport.bind(this);
+        this.closeConfirmLDIFImport = this.closeConfirmLDIFImport.bind(this);
+        this.showConfirmLDIFDelete = this.showConfirmLDIFDelete.bind(this);
+        this.closeConfirmLDIFDelete = this.closeConfirmLDIFDelete.bind(this);
+        this.showLDIFSpinningModal = this.showLDIFSpinningModal.bind(this);
+        this.showLDIFDeleteSpinningModal = this.showLDIFDeleteSpinningModal.bind(this);
+        this.doExport = this.doExport.bind(this);
+        this.showExportModal = this.showExportModal.bind(this);
+        this.closeExportModal = this.closeExportModal.bind(this);
+    }
+
+    showExportModal () {
+        this.setState({
+            showExportModal: true,
+            exportSpinner: false,
+            ldifSuffix: this.props.suffixes[0]
+        });
+    }
+
+    closeExportModal () {
+        this.setState({
+            showExportModal: false
+        });
+    }
+
+    showLDIFSpinningModal () {
+        this.setState({
+            showLDIFSpinningModal: true
+        });
+    }
+
+    closeLDIFSpinningModal () {
+        this.setState({
+            showLDIFSpinningModal: false
+        });
+    }
+
+    showLDIFDeleteSpinningModal () {
+        this.setState({
+            showLDIFDeleteSpinningModal: true
+        });
+    }
+
+    closeLDIFDeleteSpinningModal () {
+        this.setState({
+            showLDIFDeleteSpinningModal: false
+        });
+    }
+
+    showDelBackupSpinningModal () {
+        this.setState({
+            showDelBackupSpinningModal: true
+        });
+    }
+
+    closeDelBackupSpinningModal () {
+        this.setState({
+            showDelBackupSpinningModal: false
+        });
+    }
+
+    showRestoreSpinningModal () {
+        this.setState({
+            showRestoreSpinningModal: true
+        });
+    }
+
+    closeRestoreSpinningModal () {
+        this.setState({
+            showRestoreSpinningModal: false
+        });
+    }
+
+    showBackupModal () {
+        this.setState({
+            showBackupModal: true,
+            backupSpinning: false
+        });
+    }
+
+    closeBackupModal () {
+        this.setState({
+            showBackupModal: false,
+        });
+    }
+
+    showConfirmLDIFImport (item) {
+        this.setState({
+            showConfirmLDIFImport: true,
+            ldifName: item.name,
+            ldifSuffix: item.suffix[0]
+        });
+    }
+
+    closeConfirmLDIFImport () {
+        // call importLDIF
+        this.setState({
+            showConfirmLDIFImport: false,
+        });
+    }
+
+    showConfirmLDIFDelete (item) {
+        // call deleteLDIF
+        this.setState({
+            showConfirmLDIFDelete: true,
+            ldifName: item.name
+        });
+    }
+
+    closeConfirmLDIFDelete () {
+        // call importLDIF
+        this.setState({
+            showConfirmLDIFDelete: false,
+        });
+    }
+
+    showConfirmBackup (item) {
+        // call deleteLDIF
+        this.setState({
+            showConfirmBackup: true,
+            backupName: item.name,
+        });
+    }
+
+    closeConfirmBackup () {
+        // call importLDIF
+        this.setState({
+            showConfirmBackup: false,
+        });
+    }
+
+    showConfirmRestore (item) {
+        this.setState({
+            showConfirmRestore: true,
+            backupName: item.name,
+        });
+    }
+
+    closeConfirmRestore () {
+        // call importLDIF
+        this.setState({
+            showConfirmRestore: false,
+        });
+    }
+
+    showConfirmBackupDelete (item) {
+        // calls deleteBackup
+        this.setState({
+            showConfirmBackupDelete: true,
+            backupName: item.name,
+        });
+    }
+
+    closeConfirmBackupDelete () {
+        // call importLDIF
+        this.setState({
+            showConfirmBackupDelete: false,
+        });
+    }
+
+    importLDIF() {
+        this.showLDIFSpinningModal();
+
+        const cmd = [
+            "dsconf", "-j", "ldapi://%2fvar%2frun%2fslapd-" + this.props.serverId + ".socket",
+            "backend", "import", this.state.ldifSuffix, this.state.ldifName, "--encrypted"
+        ];
+        log_cmd("importLDIF", "Importing LDIF", cmd);
+        cockpit
+                .spawn(cmd, { superuser: true, err: "message" })
+                .done(content => {
+                    this.closeLDIFSpinningModal();
+                    this.props.addNotification(
+                        "success",
+                        `LDIF was successfully imported`
+                    );
+                })
+                .fail(err => {
+                    this.closeLDIFSpinningModal();
+                    this.props.addNotification(
+                        "error",
+                        `Failure importing LDIF - ${err}`
+                    );
+                });
+    }
+
+    deleteLDIF (e) {
+        this.showLDIFDeleteSpinningModal();
+
+        const cmd = [
+            "dsctl", this.props.serverId, "ldifs", "--delete", this.state.ldifName
+        ];
+        log_cmd("deleteLDIF", "Deleting LDIF", cmd);
+        cockpit
+                .spawn(cmd, { superuser: true, err: "message" })
+                .done(content => {
+                    this.props.reload();
+                    this.closeLDIFDeleteSpinningModal();
+                    this.props.addNotification(
+                        "success",
+                        `LDIF file was successfully deleted`
+                    );
+                })
+                .fail(err => {
+                    this.props.reload();
+                    this.closeLDIFDeleteSpinningModal();
+                    this.props.addNotification(
+                        "error",
+                        `Failure deleting LDIF file - ${err}`
+                    );
+                });
+    }
+
+    doBackup () {
+        this.setState({
+            backupSpinning: true
+        });
+
+        const cmd = [
+            "dsconf", "-j", "ldapi://%2fvar%2frun%2fslapd-" + this.props.serverId + ".socket",
+            "backup", "create", this.state.backupName
+        ];
+        log_cmd("doBackup", "Add backup task", cmd);
+        cockpit
+                .spawn(cmd, { superuser: true, err: "message" })
+                .done(content => {
+                    this.props.reload();
+                    this.closeBackupModal();
+                    this.props.addNotification(
+                        "success",
+                        `Server has been backed up`
+                    );
+                })
+                .fail(err => {
+                    this.props.reload();
+                    this.closeBackupModal();
+                    this.props.addNotification(
+                        "error",
+                        `Failure backing up server - ${err}`
+                    );
+                });
+    }
+
+    restoreBackup () {
+        this.showRestoreSpinningModal();
+
+        const cmd = [
+            "dsconf", "-j", "ldapi://%2fvar%2frun%2fslapd-" + this.props.serverId + ".socket",
+            "backup", "restore", this.state.backupName
+        ];
+        log_cmd("restoreBackup", "Restoring server", cmd);
+        cockpit
+                .spawn(cmd, { superuser: true, err: "message" })
+                .done(content => {
+                    this.closeRestoreSpinningModal();
+                    this.props.addNotification(
+                        "success",
+                        `Server has been restored`
+                    );
+                })
+                .fail(err => {
+                    this.closeRestoreSpinningModal();
+                    this.props.addNotification(
+                        "error",
+                        `Failure restoring up server - ${err}`
+                    );
+                });
+    }
+
+    deleteBackup (e) {
+        // Show confirmation
+        this.showDelBackupSpinningModal();
+
+        const cmd = [
+            "dsctl", this.props.serverId, "backups", "--delete", this.state.backupName
+        ];
+        log_cmd("deleteBackup", "Deleting backup", cmd);
+        cockpit
+                .spawn(cmd, { superuser: true, err: "message" })
+                .done(content => {
+                    this.props.reload();
+                    this.closeDelBackupSpinningModal();
+                    this.props.addNotification(
+                        "success",
+                        `Backup was successfully deleted`
+                    );
+                })
+                .fail(err => {
+                    this.props.reload();
+                    this.closeDelBackupSpinningModal();
+                    this.props.addNotification(
+                        "error",
+                        `Failure deleting backup - ${err}`
+                    );
+                });
+    }
+
+    handleNavSelect(key) {
+        this.setState({ activeKey: key });
+    }
+
+    handleChange(e) {
+        const value = e.target.type === 'checkbox' ? e.target.checked : e.target.value;
+        let valueErr = false;
+        let errObj = this.state.errObj;
+        if (value == "") {
+            valueErr = true;
+        }
+        errObj[e.target.id] = valueErr;
+        this.setState({
+            [e.target.id]: value,
+            errObj: errObj
+        });
+    }
+
+    doExport() {
+        let missingArgs = {ldifLocation: false};
+        if (this.state.ldifLocation == "") {
+            this.props.addNotification(
+                "warning",
+                `LDIF name is empty`
+            );
+            missingArgs.ldifLocation = true;
+            this.setState({
+                errObj: missingArgs
+            });
+            return;
+        }
+
+        // Do import
+        let export_cmd = [
+            "dsconf", "-j", "ldapi://%2fvar%2frun%2fslapd-" + this.props.serverId + ".socket",
+            "backend", "export", this.state.ldifSuffix, "--encrypted", "--ldif=" + this.state.ldifName
+        ];
+
+        this.setState({
+            exportSpinner: true,
+        });
+
+        log_cmd("doExport", "Do online export", export_cmd);
+        cockpit
+                .spawn(export_cmd, { superuser: true, err: "message" })
+                .done(content => {
+                    this.props.reload();
+                    this.closeExportModal();
+                    this.props.addNotification(
+                        "success",
+                        `Database export complete`
+                    );
+                    this.setState({
+                        showExportModal: false,
+                    });
+                })
+                .fail(err => {
+                    this.props.reload();
+                    this.closeExportModal();
+                    this.props.addNotification(
+                        "error",
+                        `Error exporting database - ${err}`
+                    );
+                    this.setState({
+                        showExportModal: false,
+                    });
+                });
+    }
+
+    render() {
+        return (
+            <div>
+                <TabContainer id="basic-tabs-pf" onSelect={this.handleNavSelect} activeKey={this.state.activeKey}>
+                    <div>
+                        <Nav bsClass="nav nav-tabs nav-tabs-pf">
+                            <NavItem eventKey={1}>
+                                <div dangerouslySetInnerHTML={{__html: 'Backups'}} />
+                            </NavItem>
+                            <NavItem eventKey={2}>
+                                <div dangerouslySetInnerHTML={{__html: 'LDIFs'}} />
+                            </NavItem>
+                        </Nav>
+                        <TabContent>
+                            <TabPane eventKey={1}>
+                                <div className="ds-margin-top-xlg">
+                                    <BackupTable
+                                        rows={this.props.backups}
+                                        confirmRestore={this.showConfirmRestore}
+                                        confirmDelete={this.showConfirmBackupDelete}
+                                    />
+                                </div>
+                                <p />
+                                <Button
+                                    bsStyle="primary"
+                                    onClick={this.showBackupModal}
+                                >
+                                    Create Backup
+                                </Button>
+                            </TabPane>
+
+                            <TabPane eventKey={2}>
+                                <div className="ds-margin-top-xlg">
+                                    <LDIFManageTable
+                                        rows={this.props.ldifs}
+                                        confirmImport={this.showConfirmLDIFImport}
+                                        confirmDelete={this.showConfirmLDIFDelete}
+                                    />
+                                </div>
+                                <p />
+                                <Button
+                                    bsStyle="primary"
+                                    onClick={this.showExportModal}
+                                >
+                                    Create LDIF Export
+                                </Button>
+                            </TabPane>
+                        </TabContent>
+                    </div>
+                </TabContainer>
+
+                <ExportModal
+                    showModal={this.state.showExportModal}
+                    closeHandler={this.closeExportModal}
+                    handleChange={this.handleChange}
+                    saveHandler={this.doExport}
+                    spinning={this.state.exportSpinner}
+                    error={this.state.errObj}
+                    suffixes={this.props.suffixes}
+                />
+                <BackupModal
+                    showModal={this.state.showBackupModal}
+                    closeHandler={this.closeBackupModal}
+                    handleChange={this.handleChange}
+                    saveHandler={this.doBackup}
+                    spinning={this.state.backupSpinning}
+                    error={this.state.errObj}
+                />
+                <RestoreModal
+                    showModal={this.state.showRestoreSpinningModal}
+                    closeHandler={this.closeRestoreSpinningModal}
+                    msg={this.state.backupName}
+                />
+                <DeleteBackupModal
+                    showModal={this.state.showDelBackupSpinningModal}
+                    closeHandler={this.closeDelBackupSpinningModal}
+                    msg={this.state.backupName}
+                />
+                <ImportingModal
+                    showModal={this.state.showLDIFSpinningModal}
+                    closeHandler={this.closeLDIFSpinningModal}
+                    msg={this.state.ldifName}
+                />
+                <DeletingLDIFModal
+                    showModal={this.state.showLDIFDeleteSpinningModal}
+                    closeHandler={this.closeLDIFDeleteSpinningModal}
+                    msg={this.state.ldifName}
+                />
+                <ConfirmPopup
+                    showModal={this.state.showConfirmLDIFDelete}
+                    closeHandler={this.closeConfirmLDIFDelete}
+                    actionFunc={this.deleteLDIF}
+                    actionParam={this.state.ldifName}
+                    msg="Are you sure you want to delete this LDIF?"
+                    msgContent={this.state.ldifName}
+                />
+                <ConfirmPopup
+                    showModal={this.state.showConfirmLDIFImport}
+                    closeHandler={this.closeConfirmLDIFImport}
+                    actionFunc={this.importLDIF}
+                    actionParam={this.state.ldifName}
+                    msg="Are you sure you want to import this LDIF?"
+                    msgContent={this.state.ldifName}
+                />
+                <ConfirmPopup
+                    showModal={this.state.showConfirmRestore}
+                    closeHandler={this.closeConfirmRestore}
+                    actionFunc={this.restoreBackup}
+                    actionParam={this.state.backupName}
+                    msg="Are you sure you want to restore this backup?"
+                    msgContent={this.state.backupName}
+                />
+                <ConfirmPopup
+                    showModal={this.state.showConfirmBackupDelete}
+                    closeHandler={this.closeConfirmBackupDelete}
+                    actionFunc={this.deleteBackup}
+                    actionParam={this.state.backupName}
+                    msg="Are you sure you want to delete this backup?"
+                    msgContent={this.state.backupName}
+                />
+
+            </div>
+        );
+    }
+}
+
+class ExportModal extends React.Component {
+    render() {
+        const {
+            showModal,
+            closeHandler,
+            handleChange,
+            saveHandler,
+            suffixes,
+            spinning,
+            error
+        } = this.props;
+        let spinner = "";
+        if (spinning) {
+            spinner =
+                <Row>
+                    <div className="ds-modal-spinner">
+                        <Spinner loading inline size="lg" />Exporting database... <font size="1">(You can safely close this window)</font>
+                    </div>
+                </Row>;
+        }
+        let suffixList = suffixes.map((suffix) =>
+            <option key={suffix} value={suffix}>{suffix}</option>
+        );
+        return (
+            <Modal show={showModal} onHide={closeHandler}>
+                <div className="ds-no-horizontal-scrollbar">
+                    <Modal.Header>
+                        <button
+                            className="close"
+                            onClick={closeHandler}
+                            aria-hidden="true"
+                            aria-label="Close"
+                        >
+                            <Icon type="pf" name="close" />
+                        </button>
+                        <Modal.Title>
+                            Export Database To LDIF File
+                        </Modal.Title>
+                    </Modal.Header>
+                    <Modal.Body>
+                        <Form horizontal autoComplete="off">
+                            <Row>
+                                <Col sm={3}>
+                                    <ControlLabel>Select Suffix</ControlLabel>
+                                </Col>
+                                <Col sm={9}>
+                                    <select id="ldifSuffix" onChange={handleChange}>
+                                        {suffixList}
+                                    </select>
+                                </Col>
+                            </Row>
+                            <p />
+                            <Row title="Name of exported LDIF file">
+                                <Col sm={3}>
+                                    <ControlLabel>LDIF File Name</ControlLabel>
+                                </Col>
+                                <Col sm={9}>
+                                    <FormControl
+                                        type="text"
+                                        id="ldifName"
+                                        className={error.ldifName ? "ds-input-bad" : ""}
+                                        onChange={handleChange}
+                                    />
+                                </Col>
+                            </Row>
+                            <p />
+                            {spinner}
+                        </Form>
+                    </Modal.Body>
+                    <Modal.Footer>
+                        <Button
+                            bsStyle="default"
+                            className="btn-cancel"
+                            onClick={closeHandler}
+                        >
+                            Cancel
+                        </Button>
+                        <Button
+                            bsStyle="primary"
+                            onClick={saveHandler}
+                        >
+                            Create LDIF
+                        </Button>
+                    </Modal.Footer>
+                </div>
+            </Modal>
+        );
+    }
+}
+
+export class BackupModal extends React.Component {
+    render() {
+        const {
+            showModal,
+            closeHandler,
+            handleChange,
+            saveHandler,
+            spinning,
+            error
+        } = this.props;
+        let spinner = "";
+        if (spinning) {
+            spinner =
+                <Row>
+                    <div className="ds-modal-spinner">
+                        <Spinner loading inline size="lg" />Backing up databases... <font size="1">(You can safely close this window)</font>
+                    </div>
+                </Row>;
+        }
+
+        return (
+            <Modal show={showModal} onHide={closeHandler}>
+                <div className="ds-no-horizontal-scrollbar">
+                    <Modal.Header>
+                        <button
+                            className="close"
+                            onClick={closeHandler}
+                            aria-hidden="true"
+                            aria-label="Close"
+                        >
+                            <Icon type="pf" name="close" />
+                        </button>
+                        <Modal.Title>
+                            Backup The Server
+                        </Modal.Title>
+                    </Modal.Header>
+                    <Modal.Body>
+                        <Form horizontal autoComplete="off">
+                            <Row title="LDIF file to import">
+                                <Col sm={3}>
+                                    <ControlLabel>Backup Name</ControlLabel>
+                                </Col>
+                                <Col sm={9}>
+                                    <FormControl
+                                        type="text"
+                                        id="backupName"
+                                        className={error.backupName ? "ds-input-bad" : ""}
+                                        onChange={handleChange}
+                                    />
+                                </Col>
+                            </Row>
+                            <p />
+                            {spinner}
+                        </Form>
+                    </Modal.Body>
+                    <Modal.Footer>
+                        <Button
+                            bsStyle="default"
+                            className="btn-cancel"
+                            onClick={closeHandler}
+                        >
+                            Cancel
+                        </Button>
+                        <Button
+                            bsStyle="primary"
+                            onClick={saveHandler}
+                        >
+                            Do Backup
+                        </Button>
+                    </Modal.Footer>
+                </div>
+            </Modal>
+        );
+    }
+}
+
+class RestoreModal extends React.Component {
+    render() {
+        const {
+            showModal,
+            closeHandler,
+            msg
+        } = this.props;
+
+        return (
+            <Modal show={showModal} onHide={closeHandler}>
+                <div className="ds-no-horizontal-scrollbar">
+                    <Modal.Header>
+                        <button
+                            className="close"
+                            onClick={closeHandler}
+                            aria-hidden="true"
+                            aria-label="Close"
+                        >
+                            <Icon type="pf" name="close" />
+                        </button>
+                        <Modal.Title>
+                            Restoring Server From Backup
+                        </Modal.Title>
+                    </Modal.Header>
+                    <Modal.Body>
+                        <Form horizontal autoComplete="off">
+                            <div className="ds-modal-spinner">
+                                <Spinner loading inline size="lg" /> Restoring backup <b>{msg}</b> ...
+                                <p />
+                                <p><font size="1"> (You can safely close this window)</font></p>
+                            </div>
+                        </Form>
+                    </Modal.Body>
+                    <Modal.Footer>
+                        <Button
+                            bsStyle="default"
+                            className="btn-cancel"
+                            onClick={closeHandler}
+                        >
+                            Close
+                        </Button>
+                    </Modal.Footer>
+                </div>
+            </Modal>
+        );
+    }
+}
+
+class DeleteBackupModal extends React.Component {
+    render() {
+        const {
+            showModal,
+            closeHandler,
+            msg
+        } = this.props;
+
+        return (
+            <Modal show={showModal} onHide={closeHandler}>
+                <div className="ds-no-horizontal-scrollbar">
+                    <Modal.Header>
+                        <button
+                            className="close"
+                            onClick={closeHandler}
+                            aria-hidden="true"
+                            aria-label="Close"
+                        >
+                            <Icon type="pf" name="close" />
+                        </button>
+                        <Modal.Title>
+                            Delete Backup
+                        </Modal.Title>
+                    </Modal.Header>
+                    <Modal.Body>
+                        <Form horizontal autoComplete="off">
+                            <div className="ds-modal-spinner">
+                                <Spinner loading inline size="lg" /> Deleting backup <b>{msg}</b> ...
+                                <p />
+                                <p><font size="1"> (You can safely close this window)</font></p>
+                            </div>
+                        </Form>
+                    </Modal.Body>
+                    <Modal.Footer>
+                        <Button
+                            bsStyle="default"
+                            className="btn-cancel"
+                            onClick={closeHandler}
+                        >
+                            Close
+                        </Button>
+                    </Modal.Footer>
+                </div>
+            </Modal>
+        );
+    }
+}
+
+class ImportingModal extends React.Component {
+    render() {
+        const {
+            showModal,
+            closeHandler,
+            msg
+        } = this.props;
+
+        return (
+            <Modal show={showModal} onHide={closeHandler}>
+                <div className="ds-no-horizontal-scrollbar">
+                    <Modal.Header>
+                        <button
+                            className="close"
+                            onClick={closeHandler}
+                            aria-hidden="true"
+                            aria-label="Close"
+                        >
+                            <Icon type="pf" name="close" />
+                        </button>
+                        <Modal.Title>
+                            Import LDIF File
+                        </Modal.Title>
+                    </Modal.Header>
+                    <Modal.Body>
+                        <Form horizontal autoComplete="off">
+                            <div className="ds-modal-spinner">
+                                <Spinner loading inline size="lg" /> Importing LDIF <b>{msg}</b> ...
+                                <p />
+                                <p><font size="1"> (You can safely close this window)</font></p>
+                            </div>
+                        </Form>
+                    </Modal.Body>
+                    <Modal.Footer>
+                        <Button
+                            bsStyle="default"
+                            className="btn-cancel"
+                            onClick={closeHandler}
+                        >
+                            Close
+                        </Button>
+                    </Modal.Footer>
+                </div>
+            </Modal>
+        );
+    }
+}
+
+class DeletingLDIFModal extends React.Component {
+    render() {
+        const {
+            showModal,
+            closeHandler,
+            msg
+        } = this.props;
+
+        return (
+            <Modal show={showModal} onHide={closeHandler}>
+                <div className="ds-no-horizontal-scrollbar">
+                    <Modal.Header>
+                        <button
+                            className="close"
+                            onClick={closeHandler}
+                            aria-hidden="true"
+                            aria-label="Close"
+                        >
+                            <Icon type="pf" name="close" />
+                        </button>
+                        <Modal.Title>
+                            Delete LDIF File
+                        </Modal.Title>
+                    </Modal.Header>
+                    <Modal.Body>
+                        <Form horizontal autoComplete="off">
+                            <div className="ds-modal-spinner">
+                                <Spinner loading inline size="lg" /> Deleting LDIF file <b>{msg}</b> ...
+                                <p />
+                                <p><font size="1"> (You can safely close this window)</font></p>
+                            </div>
+                        </Form>
+                    </Modal.Body>
+                    <Modal.Footer>
+                        <Button
+                            bsStyle="default"
+                            className="btn-cancel"
+                            onClick={closeHandler}
+                        >
+                            Close
+                        </Button>
+                    </Modal.Footer>
+                </div>
+            </Modal>
+        );
+    }
+}
+
+// Properties and defaults
+
+ExportModal.propTypes = {
+    showModal: PropTypes.bool,
+    closeHandler: PropTypes.func,
+    handleChange: PropTypes.func,
+    saveHandler: PropTypes.func,
+    spinning: PropTypes.bool,
+    error: PropTypes.object,
+    suffixes: PropTypes.array
+};
+
+BackupModal.propTypes = {
+    showModal: PropTypes.bool,
+    closeHandler: PropTypes.func,
+    handleChange: PropTypes.func,
+    saveHandler: PropTypes.func,
+    spinning: PropTypes.bool,
+    error: PropTypes.object,
+};
+
+DeletingLDIFModal.propTypes = {
+    showModal: PropTypes.bool,
+    closeHandler: PropTypes.func,
+    msg: PropTypes.string
+};
+
+RestoreModal.propTypes = {
+    showModal: PropTypes.bool,
+    closeHandler: PropTypes.func,
+    msg: PropTypes.string
+};
+
+DeleteBackupModal.propTypes = {
+    showModal: PropTypes.bool,
+    closeHandler: PropTypes.func,
+    msg: PropTypes.string
+};
+
+ImportingModal.propTypes = {
+    showModal: PropTypes.bool,
+    closeHandler: PropTypes.func,
+    msg: PropTypes.string
+};
+
+Backups.propTypes = {
+    backups: PropTypes.array,
+    ldifs: PropTypes.array,
+    reload: PropTypes.func
+};
+
+Backups.defaultProps = {
+    backups: [],
+    ldifs: [],
+    reload: noop
+};
diff --git a/src/cockpit/389-console/src/lib/database/chaining.jsx b/src/cockpit/389-console/src/lib/database/chaining.jsx
new file mode 100644
index 0000000..cf507b3
--- /dev/null
+++ b/src/cockpit/389-console/src/lib/database/chaining.jsx
@@ -0,0 +1,1311 @@
+import cockpit from "cockpit";
+import React from "react";
+import { ConfirmPopup } from "../notifications.jsx";
+import CustomCollapse from "../customCollapse.jsx";
+import { log_cmd } from "../tools.jsx";
+import {
+    Modal,
+    Icon,
+    Button,
+    Form,
+    Row,
+    Col,
+    ControlLabel,
+    Checkbox,
+    FormControl,
+    noop
+} from "patternfly-react";
+import PropTypes from "prop-types";
+import "../../css/ds.css";
+
+//
+// This component is the global chaining & default configuration
+//
+export class ChainingDatabaseConfig extends React.Component {
+    constructor(props) {
+        super(props);
+        this.state = {
+            oids: this.props.data.oids,
+            oidList: this.props.data.oidList,
+            availableOids: this.props.data.availableOids,
+            comps: this.props.data.comps,
+            compList: this.props.data.compList,
+            availableComps: this.props.data.availableComps,
+            selectedOids: this.props.data.selectedOids,
+            selectedComps: this.props.data.selectedComps,
+            removeOids: this.props.data.removeOids,
+            removeComps: this.props.data.removeComps,
+            showConfirmCompDelete: false,
+            showConfirmOidDelete: false,
+            showOidModal: false,
+            showCompsModal: false,
+            // Chaining config settings
+            defSearchCheck: this.props.data.defSearchCheck,
+            defBindConnLimit: this.props.data.defBindConnLimit,
+            defBindTimeout: this.props.data.defBindTimeout,
+            defBindRetryLimit: this.props.data.defBindRetryLimit,
+            defConcurLimit: this.props.data.defConcurLimit,
+            defConcurOpLimit: this.props.data.defConcurOpLimit,
+            defConnLife: this.props.data.defConnLife,
+            defHopLimit: this.props.data.defHopLimit,
+            defDelay: this.props.data.defDelay,
+            defTestDelay: this.props.data.defTestDelay,
+            defOpConnLimit: this.props.data.defOpConnLimit,
+            defSizeLimit: this.props.data.defSizeLimit,
+            defTimeLimit: this.props.data.defTimeLimit,
+            defProxy: this.props.data.defProxy,
+            defRefOnScoped: this.props.data.defRefOnScoped,
+            defCheckAci: this.props.data.defCheckAci,
+            defUseStartTLS: this.props.data.defUseStartTLS,
+            // Original values used for saving config
+            _defSearchCheck: this.props.data.defSearchCheck,
+            _defBindConnLimit: this.props.data.defBindConnLimit,
+            _defBindTimeout: this.props.data.defBindTimeout,
+            _defBindRetryLimit: this.props.data.defBindRetryLimit,
+            _defConcurLimit: this.props.data.defConcurLimit,
+            _defConcurOpLimit: this.props.data.defConcurOpLimit,
+            _defConnLife: this.props.data.defConnLife,
+            _defHopLimit: this.props.data.defHopLimit,
+            _defDelay: this.props.data.defDelay,
+            _defTestDelay: this.props.data.defTestDelay,
+            _defOpConnLimit: this.props.data.defOpConnLimit,
+            _defSizeLimit: this.props.data.defSizeLimit,
+            _defTimeLimit: this.props.data.defTimeLimit,
+            _defProxy: this.props.data.defProxy,
+            _defRefOnScoped: this.props.data.defRefOnScoped,
+            _defCheckAci: this.props.data.defCheckAci,
+            _defUseStartTLS: this.props.data.defUseStartTLS,
+        };
+
+        this.handleChange = this.handleChange.bind(this);
+        this.save_chaining_config = this.save_chaining_config.bind(this);
+        // Chaining Control OIDs
+        this.showOidModal = this.showOidModal.bind(this);
+        this.closeOidModal = this.closeOidModal.bind(this);
+        this.handleOidChange = this.handleOidChange.bind(this);
+        this.saveOids = this.saveOids.bind(this);
+        this.deleteOids = this.deleteOids.bind(this);
+        this.handleSelectOids = this.handleSelectOids.bind(this);
+        // Chaining comps
+        this.showCompsModal = this.showCompsModal.bind(this);
+        this.closeCompsModal = this.closeCompsModal.bind(this);
+        this.handleCompsChange = this.handleCompsChange.bind(this);
+        this.saveComps = this.saveComps.bind(this);
+        this.deleteComps = this.deleteComps.bind(this);
+        this.handleSelectComps = this.handleSelectComps.bind(this);
+        this.showConfirmDelete = this.showConfirmDelete.bind(this);
+        this.closeConfirmOidDelete = this.closeConfirmOidDelete.bind(this);
+        this.closeConfirmCompDelete = this.closeConfirmCompDelete.bind(this);
+    }
+
+    handleChange(e) {
+        // Generic
+        const value = e.target.type === 'checkbox' ? e.target.checked : e.target.value;
+        this.setState({
+            [e.target.id]: value
+        });
+    }
+
+    save_chaining_config () {
+        // Build up the command list
+        let cmd = [
+            'dsconf', '-j', 'ldapi://%2fvar%2frun%2fslapd-' + this.props.serverId + '.socket',
+            'chaining', 'config-set-def'
+        ];
+        let val = "";
+        if (this.state._defUseStartTLS != this.state.defUseStartTLS) {
+            val = "off";
+            if (this.state.defUseStartTLS) {
+                val = "on";
+            }
+            cmd.push("--use-starttls=" + val);
+        }
+        if (this.state._defCheckAci != this.state.defCheckAci) {
+            val = "off";
+            if (this.state.defCheckAci) {
+                val = "on";
+            }
+            cmd.push("--check-aci=" + val);
+        }
+        if (this.state._defRefOnScoped != this.state.defRefOnScoped) {
+            val = "off";
+            if (this.state.defRefOnScoped) {
+                val = "on";
+            }
+            cmd.push("--return-ref=" + val);
+        }
+        if (this.state._defProxy != this.state.defProxy) {
+            val = "off";
+            if (this.state.defProxy) {
+                val = "on";
+            }
+            cmd.push("--proxied-auth=" + val);
+        }
+        if (this.state._defTestDelay != this.state.defTestDelay) {
+            cmd.push("--test-response-delay=" + this.state.defTestDelay);
+        }
+        if (this.state._defOpConnLimit != this.state.defOpConnLimit) {
+            cmd.push("--conn-op-limit=" + this.state.defOpConnLimit);
+        }
+        if (this.state._defSizeLimit != this.state.defSizeLimit) {
+            cmd.push("--size-limit=" + this.state.defSizeLimit);
+        }
+        if (this.state._defTimeLimit != this.state.defTimeLimit) {
+            cmd.push("--time-limit=" + this.state.defTimeLimit);
+        }
+        if (this.state._defSearchCheck != this.state.defSearchCheck) {
+            cmd.push("--abandon-check-interval=" + this.state.defSearchCheck);
+        }
+        if (this.state._defBindTimeout != this.state.defBindTimeout) {
+            cmd.push("--bind-timeout=" + this.state.defBindTimeout);
+        }
+        if (this.state._defBindRetryLimit != this.state.defBindRetryLimit) {
+            cmd.push("--bind-attempts=" + this.state.defBindRetryLimit);
+        }
+        if (this.state._defConcurLimit != this.state.defConcurLimit) {
+            cmd.push("--bind-limit=" + this.state.defConcurLimit);
+        }
+        if (this.state._defConcurOpLimit != this.state.defConcurOpLimit) {
+            cmd.push("--op-limit=" + this.state.defConcurOpLimit);
+        }
+        if (this.state._defConnLife != this.state.defConnLife) {
+            cmd.push("--conn-lifetime=" + this.state.defConnLife);
+        }
+        if (this.state._defHopLimit != this.state.defHopLimit) {
+            cmd.push("--hop-limit=" + this.state.defHopLimit);
+        }
+        if (this.state._defDelay != this.state.defDelay) {
+            cmd.push("--response-delay=" + this.state.defDelay);
+        }
+        if (this.state._defBindConnLimit != this.state.defBindConnLimit) {
+            cmd.push("--conn-bind-limit=" + this.state.defBindConnLimit);
+        }
+
+        // If we have chaining mods, then apply them...
+        if (cmd.length > 5) {
+            log_cmd("save_chaining_config", "Applying default chaining config change", cmd);
+            cockpit
+                    .spawn(cmd, {superuser: true, "err": "message"})
+                    .done(content => {
+                        // Continue with the next mod
+                        this.props.reload();
+                        this.props.addNotification(
+                            "success",
+                            `Successfully updated chaining configuration`
+                        );
+                    })
+                    .fail(err => {
+                        this.props.reload();
+                        this.props.addNotification(
+                            "error",
+                            `Error updating chaining configuration - ${err}`
+                        );
+                    });
+        }
+    }
+
+    //
+    // Chaining OID modal functions
+    //
+    showOidModal () {
+        this.setState({
+            showOidModal: true
+        });
+    }
+
+    closeOidModal() {
+        this.setState({
+            showOidModal: false
+        });
+    }
+
+    handleOidChange(e) {
+        const options = e.target.options;
+        let values = [];
+        for (let option of options) {
+            if (option.selected) {
+                values.push(option.value);
+            }
+        }
+        this.setState({
+            selectedOids: values
+        });
+    }
+
+    saveOids () {
+        // Save chaining control oids
+        let cmd = [
+            "dsconf", "-j", "ldapi://%2fvar%2frun%2fslapd-" + this.props.serverId + ".socket",
+            "chaining", "config-set"
+        ];
+        for (let oid of this.state.selectedOids) {
+            if (!this.state.oidList.includes(oid)) {
+                cmd.push('--add-control=' + oid);
+            }
+        }
+        this.closeOidModal();
+        log_cmd("saveOids", "Save new chaining OID controls", cmd);
+        cockpit
+                .spawn(cmd, { superuser: true, err: "message" })
+                .done(content => {
+                    this.props.reload();
+                    this.props.addNotification(
+                        "success",
+                        `Successfully updated chaining controls`
+                    );
+                })
+                .fail(err => {
+                    this.props.reload();
+                    this.props.addNotification(
+                        "error",
+                        `Error updating chaining controls - ${err}`
+                    );
+                });
+    }
+
+    handleSelectOids (e) {
+        const options = e.target.options;
+        let values = [];
+        for (let option of options) {
+            if (option.selected) {
+                values.push(option.value);
+            }
+        }
+        this.setState({
+            removeOids: values
+        });
+    }
+
+    deleteOids(props) {
+        // Remove chaining controls
+        let cmd = [
+            "dsconf", "-j", "ldapi://%2fvar%2frun%2fslapd-" + this.props.serverId + ".socket",
+            "chaining", "config-set"
+        ];
+        for (let oid of this.state.removeOids) {
+            cmd.push('--del-control=' + oid);
+        }
+        this.state.removeOids = [];
+
+        log_cmd("deleteOids", "Delete chaining controls", cmd);
+        cockpit
+                .spawn(cmd, { superuser: true, err: "message" })
+                .done(content => {
+                    this.props.reload();
+                    this.props.addNotification(
+                        "success",
+                        `Successfully removed chaining controls`
+                    );
+                })
+                .fail(err => {
+                    this.props.reload();
+                    this.props.addNotification(
+                        "error",
+                        `Error removing chaining controls - ${err}`
+                    );
+                });
+    }
+
+    //
+    // Chaining Component modal functions
+    //
+    showCompsModal () {
+        this.setState({
+            showCompsModal: true
+        });
+    }
+
+    closeCompsModal() {
+        this.setState({
+            showCompsModal: false
+        });
+    }
+
+    handleCompsChange(e) {
+        const options = e.target.options;
+        let values = [];
+        for (let option of options) {
+            if (option.selected) {
+                values.push(option.value);
+            }
+        }
+        this.setState({
+            selectedComps: values
+        });
+    }
+
+    handleSelectComps (e) {
+        const options = e.target.options;
+        let values = [];
+        for (let option of options) {
+            if (option.selected) {
+                values.push(option.value);
+            }
+        }
+        this.setState({
+            removeComps: values
+        });
+    }
+
+    saveComps () {
+        // Save chaining control oids
+        let cmd = [
+            "dsconf", "-j", "ldapi://%2fvar%2frun%2fslapd-" + this.props.serverId + ".socket",
+            "chaining", "config-set"
+        ];
+        for (let comp of this.state.selectedComps) {
+            if (!this.state.compList.includes(comp)) {
+                cmd.push('--add-comp=' + comp);
+            }
+        }
+        this.closeCompsModal();
+        log_cmd("saveComps", "Save new chaining components", cmd);
+        cockpit
+                .spawn(cmd, { superuser: true, err: "message" })
+                .done(content => {
+                    this.props.reload();
+                    this.props.addNotification(
+                        "success",
+                        `Successfully updated chaining components`
+                    );
+                })
+                .fail(err => {
+                    this.props.reload();
+                    this.props.addNotification(
+                        "error",
+                        `Error updating chaining components - ${err}`
+                    );
+                });
+    }
+
+    deleteComps(props) {
+        // Remove chaining comps
+        let cmd = [
+            "dsconf", "-j", "ldapi://%2fvar%2frun%2fslapd-" + this.props.serverId + ".socket",
+            "chaining", "config-set"
+        ];
+        for (let comp of this.state.removeComps) {
+            cmd.push('--del-comp=' + comp);
+        }
+        this.state.removeComps = [];
+
+        log_cmd("deleteComps", "Delete chaining components", cmd);
+        cockpit
+                .spawn(cmd, { superuser: true, err: "message" })
+                .done(content => {
+                    this.props.reload();
+                    this.props.addNotification(
+                        "success",
+                        `Successfully removed chaining components`
+                    );
+                })
+                .fail(err => {
+                    this.props.reload();
+                    this.props.addNotification(
+                        "error",
+                        `Error removing chaining components - ${err}`
+                    );
+                });
+    }
+
+    //
+    // Confirm deletion functions
+    //
+    showConfirmDelete(item) {
+        if (item == "oid") {
+            if (this.state.removeOids.length) {
+                this.setState({
+                    showConfirmOidDelete: true
+                });
+            }
+        } else if (item == "comp") {
+            if (this.state.removeComps.length) {
+                this.setState({
+                    showConfirmCompDelete: true
+                });
+            }
+        }
+    }
+
+    closeConfirmOidDelete() {
+        this.setState({
+            showConfirmOidDelete: false
+        });
+    }
+
+    closeConfirmCompDelete() {
+        this.setState({
+            showConfirmCompDelete: false
+        });
+    }
+
+    render() {
+        // Get OIDs and comps
+        this.state.oids = this.state.oidList.map((oid) =>
+            <option key={oid} value={oid}>{oid}</option>
+        );
+        this.state.comps = this.state.compList.map((comp) =>
+            <option key={comp} value={comp}>{comp}</option>
+        );
+
+        return (
+            <div className="container-fluid" id="db-global-page">
+                <h3 className="ds-config-header">Database Chaining Settings</h3>
+                <hr />
+                <div className="ds-container">
+                    <div className="ds-chaining-split">
+                        <form>
+                            <label className="ds-config-label" htmlFor="chaining-oid-list" title="A list of LDAP control OIDs to be forwarded through chaining"><b>Forwarded LDAP Controls</b></label>
+                            <select id="chaining-oid-list" onChange={this.handleSelectOids} className="ds-chaining-list" name="nstransmittedcontrols" size="10" multiple>
+                                {this.state.oids}
+                            </select>
+                        </form>
+                        <div className="clearfix ds-container">
+                            <div className="ds-panel-left">
+                                <button type="button" onClick={this.showOidModal} className="ds-button-left">Add</button>
+                            </div>
+                            <div className="ds-panel-right">
+                                <button type="button" onClick={e => this.showConfirmDelete("oid")} className="ds-button-right">Delete</button>
+                            </div>
+                        </div>
+                    </div>
+                    <div className="ds-chaining-divider" />
+                    <div className="ds-chaining-split">
+                        <form>
+                            <label className="ds-config-label" htmlFor="chaining-comp-list" title="A list of components to go through chaining"><b>Components to Chain</b></label>
+                            <select id="chaining-comp-list" onChange={this.handleSelectComps} className="ds-chaining-list" name="nsactivechainingcomponents" size="10" multiple>
+                                {this.state.comps}}
+                            </select>
+                        </form>
+                        <div className="clearfix ds-container">
+                            <div className="ds-panel-left">
+                                <button type="button" onClick={this.showCompsModal} className="ds-button-left">Add</button>
+                            </div>
+                            <div className="ds-panel-right">
+                                <button type="button" onClick={e => this.showConfirmDelete("comp")} className="ds-button-right">Delete</button>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+
+                <h4 className="ds-sub-header"><br />Default Database Link Creation Settings</h4>
+                <hr />
+                <div className="ds-container">
+                    <div className="ds-split">
+                        <label htmlFor="defSizeLimit" className="ds-config-label" title="The size limit of entries returned over a database link (nsslapd-sizelimit).">
+                            Size Limit</label><input className="ds-input" type="text" id="defSizeLimit" onChange={this.handleChange} value={this.state.defSizeLimit} size="15" />
+                        <label htmlFor="defTimeLimit" className="ds-config-label" title="The time limit of an operation over a database link (nsslapd-timelimit).">
+                            Time Limit</label><input className="ds-input" type="text" id="defTimeLimit" onChange={this.handleChange} value={this.state.defTimeLimit} size="15" />
+                        <label htmlFor="defBindConnLimit" className="ds-config-label" title="The maximum number of TCP connections the database link establishes with the remote server.  (nsbindconnectionslimit).">
+                            Max TCP Connections</label><input className="ds-input" id="defBindConnLimit" type="text" onChange={this.handleChange} value={this.state.defBindConnLimit} size="15" />
+                        <label htmlFor="defOpConnLimit" className="ds-config-label" title="The maximum number of connections allowed over the database link.  (nsoperationconnectionslimit).">
+                            Max LDAP Connections</label><input className="ds-input" id="defOpConnLimit" type="text" onChange={this.handleChange} value={this.state.defOpConnLimit} size="15" />
+                        <label htmlFor="defConcurLimit" className="ds-config-label" title="The maximum number of concurrent bind operations per TCP connection. (nsconcurrentbindlimit).">
+                            Max Binds Per Connection</label><input className="ds-input" id="defConcurLimit" type="text" onChange={this.handleChange} value={this.state.defConcurLimit} size="15" />
+                        <label htmlFor="defBindTimeout" className="ds-config-label" title="The amount of time before the bind attempt times out. (nsbindtimeout).">
+                            Bind Timeout</label><input className="ds-input" id="defBindTimeout" type="text" onChange={this.handleChange} value={this.state.defBindTimeout} size="15" />
+                        <label htmlFor="defBindRetryLimit" className="ds-config-label" title="The number of times the database link tries to bind with the remote server after a connection failure. (nsbindretrylimit).">
+                            Bind Retry Limit</label><input className="ds-input" id="defBindRetryLimit" type="text" onChange={this.handleChange} value={this.state.defBindRetryLimit} size="15" />
+                    </div>
+                    <div className="ds-divider" />
+                    <div className="ds-split ds-inline">
+                        <div>
+                            <label htmlFor="defConcurOpLimit" className="ds-config-label" title="The maximum number of operations per connections. (nsconcurrentoperationslimit).">
+                                Max Operations Per Connection</label><input className="ds-input" id="defConcurOpLimit" type="text" onChange={this.handleChange} value={this.state.defConcurOpLimit} size="15" />
+                        </div>
+                        <div>
+                            <label htmlFor="defConnLife" className="ds-config-label" title="The life of a database link connection to the remote server.  0 is unlimited  (nsconnectionlife).">
+                                Connection Lifetime (in seconds)</label><input className="ds-input" id="defConnLife" type="text" onChange={this.handleChange} value={this.state.defConnLife} size="15" />
+                        </div>
+                        <div>
+                            <label htmlFor="defSearchCheck" className="ds-config-label" title="The number of seconds that pass before the server checks for abandoned operations.  (nsabandonedsearchcheckinterval).">
+                                Abandoned Op Check Interval</label><input className="ds-input" id="defSearchCheck" type="text" onChange={this.handleChange} value={this.state.defSearchCheck} size="15" />
+                        </div>
+                        <div>
+                            <label htmlFor="defHopLimit" className="ds-config-label" title="The maximum number of times a request can be forwarded from one database link to another.  (nshoplimit).">
+                                Database Link Hop Limit</label><input className="ds-input" type="text" onChange={this.handleChange} value={this.state.defHopLimit} id="defHopLimit" size="15" />
+                        </div>
+                        <div>
+                            <p />
+                            <input type="checkbox" onChange={this.handleChange} checked={this.state.defCheckAci} className="ds-config-checkbox" id="defCheckAci" /><label
+                                htmlFor="defCheckAci" className="ds-label" title="Sets whether ACIs are evaluated on the database link as well as the remote data server (nschecklocalaci)."> Check Local ACIs</label>
+                        </div>
+                        <div>
+                            <input type="checkbox" onChange={this.handleChange} checked={this.state.defRefOnScoped} className="ds-config-checkbox" id="defRefOnScoped" /><label
+                                htmlFor="defRefOnScoped" className="ds-label" title="Sets whether referrals are returned by scoped searches (meaning 'one-level' or 'subtree' scoped searches). (nsreferralonscopedsearch)."> Send Referral On Scoped Search</label>
+                        </div>
+                        <div>
+                            <input type="checkbox" onChange={this.handleChange} checked={this.state.defProxy} className="ds-config-checkbox" id="defProxy" /><label
+                                htmlFor="defProxy" className="ds-label" title="Sets whether proxied authentication is allowed (nsproxiedauthorization)."> Allow Proxied Authentication</label>
+                        </div>
+                        <div>
+                            <input type="checkbox" onChange={this.handleChange} checked={this.state.defUseStartTLS} className="ds-config-checkbox" id="defUseStartTLS" /><label
+                                htmlFor="defUseStartTLS" className="ds-label" title="Sets whether to use Start TLS to initiate a secure, encrypted connection over an insecure port.  (nsusestarttls)."> Use StartTLS</label>
+                        </div>
+                    </div>
+                </div>
+                <div className="ds-save-btn">
+                    <button className="btn btn-primary save-button" onClick={this.save_chaining_config}>Save Default Settings</button>
+                </div>
+
+                <ChainControlsModal
+                    showModal={this.state.showOidModal}
+                    closeHandler={this.closeOidModal}
+                    handleChange={this.handleOidChange}
+                    saveHandler={this.saveOids}
+                    oidList={this.state.availableOids}
+                />
+                <ChainCompsModal
+                    showModal={this.state.showCompsModal}
+                    closeHandler={this.closeCompsModal}
+                    handleChange={this.handleCompsChange}
+                    saveHandler={this.saveComps}
+                    compList={this.state.availableComps}
+                />
+                <ConfirmPopup
+                    showModal={this.state.showConfirmOidDelete}
+                    closeHandler={this.closeConfirmOidDelete}
+                    actionFunc={this.deleteOids}
+                    msg="Are you sure you want to delete these OID's?"
+                    msgContent={this.state.removeOids}
+                />
+                <ConfirmPopup
+                    showModal={this.state.showConfirmCompDelete}
+                    closeHandler={this.closeConfirmCompDelete}
+                    actionFunc={this.deleteComps}
+                    msg="Are you sure you want to delete these components?"
+                    msgContent={this.state.removeComps}
+                />
+            </div>
+        );
+    }
+}
+
+//
+// This is the component for the actual database link under a suffix
+//
+export class ChainingConfig extends React.Component {
+    constructor(props) {
+        super(props);
+
+        if (this.props.data !== undefined) {
+            this.state = {
+                errObj: {},
+                showDeleteConfirm: false,
+                linkPwdMatch: true,
+                // Settings
+                nsfarmserverurl: this.props.data.nsfarmserverurl,
+                nsmultiplexorbinddn: this.props.data.nsmultiplexorbinddn,
+                nsmultiplexorcredentials: this.props.data.nsmultiplexorcredentials,
+                nsmultiplexorcredentials_confirm: this.props.data.nsmultiplexorcredentials,
+                sizelimit: this.props.data.sizelimit,
+                timelimit: this.props.data.timelimit,
+                bindconnlimit: this.props.data.bindconnlimit,
+                opconnlimit: this.props.data.opconnlimit,
+                concurrbindlimit: this.props.data.concurrbindlimit,
+                bindtimeout: this.props.data.bindtimeout,
+                bindretrylimit: this.props.data.bindretrylimit,
+                concurroplimit: this.props.data.concurroplimit,
+                connlifetime: this.props.data.connlifetime,
+                searchcheckinterval: this.props.data.searchcheckinterval,
+                hoplimit: this.props.data.hoplimit,
+                nsbindmechanism: this.props.data.nsbindmechanism,
+                nsusestarttls: this.props.data.nsusestarttls,
+                nsreferralonscopedsearch: this.props.data.nsreferralonscopedsearch,
+                nsproxiedauthorization: this.props.data.nsproxiedauthorization,
+                nschecklocalaci: this.props.data.nschecklocalaci,
+                // Original settings
+                _nsfarmserverurl: this.props.data.nsfarmserverurl,
+                _nsmultiplexorbinddn: this.props.data.nsmultiplexorbinddn,
+                _nsmultiplexorcredentials: this.props.data.nsmultiplexorcredentials,
+                _nsmultiplexorcredentials_confirm: this.props.data.nsmultiplexorcredentials,
+                _sizelimit: this.props.data.sizelimit,
+                _timelimit: this.props.data.timelimit,
+                _bindconnlimit: this.props.data.bindconnlimit,
+                _opconnlimit: this.props.data.opconnlimit,
+                _concurrbindlimit: this.props.data.concurrbindlimit,
+                _bindtimeout: this.props.data.bindtimeout,
+                _bindretrylimit: this.props.data.bindretrylimit,
+                _concurroplimit: this.props.data.concurroplimit,
+                _connlifetime: this.props.data.connlifetime,
+                _searchcheckinterval: this.props.data.searchcheckinterval,
+                _hoplimit: this.props.data.hoplimit,
+                _nsbindmechanism: this.props.data.nsbindmechanism,
+                _nsusestarttls: this.props.data.nsusestarttls,
+                _nsreferralonscopedsearch: this.props.data.nsreferralonscopedsearch,
+                _nsproxiedauthorization: this.props.data.nsproxiedauthorization,
+                _nschecklocalaci: this.props.data.nschecklocalaci,
+            };
+        } else {
+            this.state = {
+                errObj: {},
+                showDeleteConfirm: false,
+                linkPwdMatch: true,
+            };
+        }
+        this.handleChange = this.handleChange.bind(this);
+        this.saveLink = this.saveLink.bind(this);
+        this.deleteLink = this.deleteLink.bind(this);
+        this.showDeleteConfirm = this.showDeleteConfirm.bind(this);
+        this.closeDeleteConfirm = this.closeDeleteConfirm.bind(this);
+    }
+
+    showDeleteConfirm () {
+        this.setState({
+            showDeleteConfirm: true
+        });
+    }
+
+    closeDeleteConfirm () {
+        this.setState({
+            showDeleteConfirm: false
+        });
+    }
+
+    checkPasswords() {
+        let pwdMatch = false;
+        if (this.state.nsmultiplexorcredentials == this.state.nsmultiplexorcredentials_confirm) {
+            pwdMatch = true;
+        }
+        this.setState({
+            linkPwdMatch: pwdMatch
+        });
+    }
+
+    handleChange (e) {
+        const value = e.target.type === 'checkbox' ? e.target.checked : e.target.value;
+        let valueErr = false;
+        let errObj = this.state.errObj;
+        if (value == "") {
+            valueErr = true;
+        }
+        errObj[e.target.id] = valueErr;
+        this.setState({
+            [e.target.id]: value,
+            errObj: errObj
+        }, this.checkPasswords);
+    }
+
+    saveLink() {
+        let missingArgs = {};
+        let errors = false;
+
+        if (this.state.nsfarmserverurl == "") {
+            this.props.addNotification(
+                "warning",
+                `Missing Remote Server LDAP URL`
+            );
+            missingArgs.nsfarmserverurl = true;
+            errors = true;
+        }
+        if (this.state.nsmultiplexorbinddn == "") {
+            this.props.addNotification(
+                "warning",
+                `Missing Remote Bind DN`
+            );
+            missingArgs.nsmultiplexorbinddn = true;
+            errors = true;
+        }
+        if (this.state.nsmultiplexorcredentials == "") {
+            this.props.addNotification(
+                "warning",
+                `Missing Remote Bind DN Password`
+            );
+            missingArgs.nsmultiplexorcredentials = true;
+            errors = true;
+        }
+        if (this.state.nsmultiplexorcredentials_confirm == "") {
+            this.props.addNotification(
+                "warning",
+                `Missing Remote Bind DN Password Confirmation`
+            );
+            missingArgs.nsmultiplexorcredentials_confirm = true;
+            errors = true;
+        }
+        if (this.state.nsmultiplexorcredentials != this.state.nsmultiplexorcredentials_confirm) {
+            this.props.addNotification(
+                "warning",
+                `Remote Bind DN Password Do Not Match`
+            );
+            missingArgs.nsmultiplexorcredentials = true;
+            missingArgs.nsmultiplexorcredentials_confirm = true;
+            errors = true;
+        }
+        if (errors) {
+            this.setState({
+                errObj: missingArgs
+            });
+            return;
+        }
+
+        // Buld up the command of all the hcnge we have to do
+        let cmd = [
+            "dsconf", "-j", "ldapi://%2fvar%2frun%2fslapd-" + this.props.serverId + ".socket",
+            "chaining", "link-set", this.props.suffix
+        ];
+
+        if (this.state.nsfarmserverurl != this.state._nsfarmserverurl) {
+            cmd.push('--server-url=' + this.state.nsfarmserverurl);
+        }
+        if (this.state.nsmultiplexorbinddn != this.state._nsmultiplexorbinddn) {
+            cmd.push('--bind-dn=' + this.state.nsmultiplexorbinddn);
+        }
+        if (this.state.nsmultiplexorcredentials != this.state._nsmultiplexorcredentials) {
+            cmd.push('--bind-pw=' + this.state.nsmultiplexorcredentials);
+        }
+        if (this.state.timelimit != this.state._timelimit) {
+            cmd.push('--time-limit=' + this.state.timelimit);
+        }
+        if (this.state.sizelimit != this.state._sizelimit) {
+            cmd.push('--size-limit=' + this.state.sizelimit);
+        }
+        if (this.state.bindconnlimit != this.state._bindconnlimit) {
+            cmd.push('--conn-bind-limit=' + this.state.bindconnlimit);
+        }
+        if (this.state.opconnlimit != this.state._opconnlimit) {
+            cmd.push('--conn-op-limit=' + this.state.opconnlimit);
+        }
+        if (this.state.concurrbindlimit != this.state._concurrbindlimit) {
+            cmd.push('--bind-limit=' + this.state.concurrbindlimit);
+        }
+        if (this.state.bindtimeout != this.state._bindtimeout) {
+            cmd.push('--bind-timeout=' + this.state.bindtimeout);
+        }
+        if (this.state.bindretrylimit != this.state._bindretrylimit) {
+            cmd.push('--bind-attempts=' + this.state.bindretrylimit);
+        }
+        if (this.state.concurroplimit != this.state._concurroplimit) {
+            cmd.push('--op-limit=' + this.state.concurroplimit);
+        }
+        if (this.state.connlifetime != this.state._connlifetime) {
+            cmd.push('--conn-lifetime=' + this.state.connlifetime);
+        }
+        if (this.state.searchcheckinterval != this.state._searchcheckinterval) {
+            cmd.push('--abandon-check-interval=' + this.state.searchcheckinterval);
+        }
+        if (this.state.hoplimit != this.state._hoplimit) {
+            cmd.push('--hop-limit=' + this.state.hoplimit);
+        }
+        if (this.state.nsbindmechanism != this.state._nsbindmechanism) {
+            cmd.push('--bind-mech=' + this.state.nsbindmechanism);
+        }
+
+        if (this.state.nsusestarttls != this.state._nsusestarttls) {
+            if (this.state.nsusestarttls) {
+                cmd.push('--use-starttls=on');
+            } else {
+                cmd.push('--use-starttls=off');
+            }
+        }
+        if (this.state.nsreferralonscopedsearch != this.state._nsreferralonscopedsearch) {
+            if (this.state.nsreferralonscopedsearch) {
+                cmd.push('--return-ref=on');
+            } else {
+                cmd.push('--return-ref=off');
+            }
+        }
+        if (this.state.nsproxiedauthorization != this.state._nsproxiedauthorization) {
+            if (this.state.nsproxiedauthorization) {
+                cmd.push('--proxied-auth=on');
+            } else {
+                cmd.push('--proxied-auth=off');
+            }
+        }
+        if (this.state.nschecklocalaci != this.state._nschecklocalaci) {
+            if (this.state.nschecklocalaci) {
+                cmd.push('--check-aci=on');
+            } else {
+                cmd.push('--check-aci=off');
+            }
+        }
+
+        if (cmd.length > 6) {
+            // Something changed, perform the update
+            log_cmd("saveLink", "Save chaining link config", cmd);
+            cockpit
+                    .spawn(cmd, { superuser: true, err: "message" })
+                    .done(content => {
+                        this.props.reload(this.props.suffix);
+                        this.props.addNotification(
+                            "success",
+                            `Successfully Updated Link Configuration`
+                        );
+                    })
+                    .fail(err => {
+                        this.props.reload(this.props.suffix);
+                        this.props.addNotification(
+                            "error",
+                            `Failed to update link configuration - ${err}`
+                        );
+                    });
+        }
+    }
+
+    deleteLink() {
+        const cmd = [
+            "dsconf", "-j", "ldapi://%2fvar%2frun%2fslapd-" + this.props.serverId + ".socket",
+            "chaining", "link-delete", this.props.suffix
+        ];
+        log_cmd("deleteLink", "Delete database chaining link", cmd);
+        cockpit
+                .spawn(cmd, { superuser: true, err: "message" })
+                .done(content => {
+                    this.props.loadSuffixTree(true);
+                    this.props.addNotification(
+                        "success",
+                        `Successfully Deleted Database Link`
+                    );
+                })
+                .fail(err => {
+                    this.props.loadSuffixTree(true);
+                    this.props.addNotification(
+                        "error",
+                        `Failed to delete database link - ${err}`
+                    );
+                });
+    }
+
+    render () {
+        const error = this.state.errObj;
+        let useStartTLSCheckBox;
+        let checkLocalAci;
+        let referralOnScope;
+        let proxiedAuth;
+
+        // Check local aci's checkbox
+        if (this.state.nschecklocalaci) {
+            checkLocalAci =
+                <Checkbox id="nschecklocalaci" onChange={this.handleChange} key={this.state.nschecklocalaci} defaultChecked
+                    title="Sets whether ACIs are evaluated on the database link as well as the remote data server (nschecklocalaci).">
+                    Check Local ACIs
+                </Checkbox>;
+        } else {
+            checkLocalAci =
+                <Checkbox id="nschecklocalaci" onChange={this.handleChange} key={this.state.nschecklocalaci}
+                    title="Sets whether ACIs are evaluated on the database link as well as the remote data server (nschecklocalaci).">
+                    Check Local ACIs
+                </Checkbox>;
+        }
+        // Referral on scoped search checkbox
+        if (this.state.nsreferralonscopedsearch) {
+            referralOnScope =
+                <Checkbox id="nsreferralonscopedsearch" onChange={this.handleChange} defaultChecked
+                    title="Sets whether referrals are returned by scoped searches (meaning 'one-level' or 'subtree' scoped searches). (nsreferralonscopedsearch).">
+                    Send Referral On Scoped Search
+                </Checkbox>;
+        } else {
+            referralOnScope =
+                <Checkbox id="nsreferralonscopedsearch" onChange={this.handleChange}
+                    title="Sets whether referrals are returned by scoped searches (meaning 'one-level' or 'subtree' scoped searches). (nsreferralonscopedsearch).">
+                    Send Referral On Scoped Search
+                </Checkbox>;
+        }
+        // Allow proxied auth checkbox
+        if (this.state.nsproxiedauthorization) {
+            proxiedAuth =
+                <Checkbox id="nsproxiedauthorization" onChange={this.handleChange} defaultChecked
+                    title="Allow proxied authentication to the remote server. (nsproxiedauthorization).">
+                    Allow Proxied Authentication
+                </Checkbox>;
+        } else {
+            proxiedAuth =
+                <Checkbox id="nsproxiedauthorization" onChange={this.handleChange} defaultChecked
+                    title="Allow proxied authentication to the remote server. (nsproxiedauthorization).">
+                    Allow Proxied Authentication
+                </Checkbox>;
+        }
+        // use startTLS checkbox
+        if (this.state.nsusestarttls) {
+            useStartTLSCheckBox =
+                <Checkbox id="nsusestarttls" onChange={this.handleChange} title="Use StartTLS for connection to remote server. (nsusestarttls)"
+                    defaultChecked
+                >
+                    Use StartTLS for remote connection
+                </Checkbox>;
+        } else {
+            useStartTLSCheckBox =
+                <Checkbox id="nsusestarttls" onChange={this.handleChange} title="Use StartTLS for connection to remote server. (nsusestarttls)">
+                    Use StartTLS for remote connection
+                </Checkbox>;
+        }
+
+        return (
+            <div className="container-fluid">
+                <Row>
+                    <Col sm={8} className="ds-word-wrap">
+                        <ControlLabel className="ds-suffix-header"><Icon type="fa" name="link" /> {this.props.suffix} (<i>{this.props.bename}</i>)</ControlLabel>
+                    </Col>
+                    <Col sm={2}>
+                        <Button
+                            bsStyle="primary"
+                            onClick={this.showDeleteConfirm}
+                        >
+                            Delete Link
+                        </Button>
+                    </Col>
+                </Row>
+                <h4>Database Link Configuration</h4>
+                <hr />
+                <Form horizontal autoComplete="off">
+                    <Row title="The LDAP URL for the remote server.  Add additional failure server URLs by separating them with a space. (nsfarmserverurl)">
+                        <Col sm={3}>
+                            <ControlLabel>Remote Server LDAP URL(s)</ControlLabel>
+                        </Col>
+                        <Col sm={7}>
+                            <FormControl
+                                type="text"
+                                id="nsfarmserverurl"
+                                className="ds-input-auto"
+                                onChange={this.handleChange}
+                                defaultValue={this.state.nsfarmserverurl}
+                            />
+                        </Col>
+                    </Row>
+                    <p />
+                    <Row title="The distinguished name (DN) of the entry to authenticate to the remote server. (nsmultiplexorbinddn)">
+                        <Col sm={3}>
+                            <ControlLabel>Remote Server Bind DN</ControlLabel>
+                        </Col>
+                        <Col sm={7}>
+                            <FormControl
+                                type="text"
+                                id="nsmultiplexorbinddn"
+                                className="ds-input-auto"
+                                onChange={this.handleChange}
+                                defaultValue={this.state.nsmultiplexorbinddn}
+                            />
+                        </Col>
+                    </Row>
+                    <p />
+                    <Row title="The password for the authenticating entry. (nsmultiplexorcredentials)">
+                        <Col sm={3}>
+                            <ControlLabel>Bind DN Password</ControlLabel>
+                        </Col>
+                        <Col sm={7}>
+                            <FormControl
+                                type="password"
+                                id="nsmultiplexorcredentials"
+                                className={(error.nsmultiplexorcredentials || !this.state.linkPwdMatch) ? "ds-input-auto-bad" : "ds-input-auto"}
+                                onChange={this.handleChange}
+                                defaultValue={this.state.nsmultiplexorcredentials}
+                            />
+                        </Col>
+                    </Row>
+                    <p />
+                    <Row title="Confirm the password for the authenticating entry. (nsmultiplexorcredentials)">
+                        <Col sm={3}>
+                            <ControlLabel>Confirm Password</ControlLabel>
+                        </Col>
+                        <Col sm={7}>
+                            <FormControl
+                                type="password"
+                                id="nsmultiplexorcredentials_confirm"
+                                className={(error.nsmultiplexorcredentials_confirm || !this.state.linkPwdMatch) ? "ds-input-auto-bad" : "ds-input-auto"}
+                                onChange={this.handleChange}
+                                defaultValue={this.state.nsmultiplexorcredentials_confirm}
+                            />
+                        </Col>
+                    </Row>
+                    <p />
+                    <Row title="THe authentication mechanism.  Simple (user name and password), SASL/DIGEST-MD5, or SASL>GSSAPI. (nsbindmechanism)">
+                        <Col sm={3}>
+                            <ControlLabel>Bind Mechanism</ControlLabel>
+                        </Col>
+                        <Col sm={7}>
+                            <select value={this.state.nsbindmechanism}
+                                className="btn btn-default dropdown ds-dblink-dropdown"
+                                onChange={this.handleChange}
+                                id="nsbindmechanism"
+                            >
+                                <option>Simple</option>
+                                <option>SASL/DIGEST-MD5</option>
+                                <option>SASL/GSSAPI</option>
+                            </select>
+                        </Col>
+                    </Row>
+                    <p />
+                    <Row>
+                        <Col sm={9}>
+                            {useStartTLSCheckBox}
+                        </Col>
+                    </Row>
+                </Form>
+                <p />
+
+                <CustomCollapse>
+                    <div className="ds-accordion-panel">
+                        <div className="ds-accordian-div">
+                            <div className="ds-container">
+                                <div className="ds-inline">
+                                    <div>
+                                        <label htmlFor="sizelimit" className="ds-config-label" title="The size limit of entries returned over a database link (nsslapd-sizelimit).">
+                                            Size Limit</label><input onChange={this.handleChange} defaultValue={this.state.sizelimit} className="ds-input" type="text" id="sizelimit" size="15" />
+                                    </div>
+                                    <div>
+                                        <label htmlFor="timelimit" className="ds-config-label" title="The time limit of an operation over a database link (nsslapd-timelimit).">
+                                            Time Limit</label><input onChange={this.handleChange} defaultValue={this.state.timelimit} className="ds-input" type="text" id="timelimit" size="15" />
+                                    </div>
+                                    <div>
+                                        <label htmlFor="bindconnlimit" className="ds-config-label" title="The maximum number of TCP connections the database link establishes with the remote server.  (nsbindconnectionslimit).">
+                                            Max TCP Connections</label><input onChange={this.handleChange} defaultValue={this.state.bindconnlimit} className="ds-input" type="text" id="bindconnlimit" size="15" />
+                                    </div>
+                                    <div>
+                                        <label htmlFor="opconnlimit" className="ds-config-label" title="The maximum number of connections allowed over the database link.  (nsoperationconnectionslimit).">
+                                            Max LDAP Connections</label><input onChange={this.handleChange} defaultValue={this.state.opconnlimit} className="ds-input" type="text" id="opconnlimit" size="15" />
+                                    </div>
+                                    <div>
+                                        <label htmlFor="concurrbindlimit" className="ds-config-label" title="The maximum number of concurrent bind operations per TCP connection. (nsconcurrentbindlimit).">
+                                            Max Binds Per Connection</label><input onChange={this.handleChange} defaultValue={this.state.concurrbindlimit} className="ds-input" type="text" id="concurrbindlimit" size="15" />
+                                    </div>
+                                    <div>
+                                        <label htmlFor="bindtimeout" className="ds-config-label" title="The amount of time before the bind attempt times out. (nsbindtimeout).">
+                                            Bind Timeout</label><input onChange={this.handleChange} defaultValue={this.state.bindtimeout} className="ds-input" type="text" id="bindtimeout" size="15" />
+                                    </div>
+                                </div>
+                                <div className="ds-divider" />
+                                <div className="ds-inline">
+                                    <div>
+                                        <label htmlFor="bindretrylimit" className="ds-config-label" title="The number of times the database link tries to bind with the remote server after a connection failure. (nsbindretrylimit).">
+                                            Bind Retry Limit</label><input onChange={this.handleChange} defaultValue={this.state.bindretrylimit} className="ds-input" type="text" id="bindretrylimit" size="15" />
+                                    </div>
+                                    <div>
+                                        <label htmlFor="concurroplimit" className="ds-config-label" title="The maximum number of operations per connections. (nsconcurrentoperationslimit).">
+                                            Max Operations Per Connection</label><input onChange={this.handleChange} defaultValue={this.state.concurroplimit} className="ds-input" type="text" id="concurroplimit" size="15" />
+                                    </div>
+                                    <div>
+                                        <label htmlFor="connlifetime" className="ds-config-label" title="The life of a database link connection to the remote server.  0 is unlimited  (nsconnectionlife).">
+                                            Connection Lifetime (in seconds)</label><input onChange={this.handleChange} defaultValue={this.state.connlifetime} className="ds-input" type="text" id="connlifetime" size="15" />
+                                    </div>
+                                    <div>
+                                        <label htmlFor="searchcheckinterval" className="ds-config-label" title="The number of seconds that pass before the server checks for abandoned operations.  (nsabandonedsearchcheckinterval).">
+                                            Abandoned Op Check Interval</label><input onChange={this.handleChange} defaultValue={this.state.searchcheckinterval} className="ds-input" type="text" id="searchcheckinterval" size="15" />
+                                    </div>
+                                    <div>
+                                        <label htmlFor="hoplimit" className="ds-config-label" title="The maximum number of times a request can be forwarded from one database link to another.  (nshoplimit).">
+                                            Database Link Hop Limit</label><input onChange={this.handleChange} defaultValue={this.state.hoplimit} className="ds-input" type="text" id="hoplimit" size="15" />
+                                    </div>
+                                </div>
+                            </div>
+                            <p />
+                            <div>
+                                {proxiedAuth}
+                            </div>
+                            <div>
+                                {checkLocalAci}
+                            </div>
+                            <div>
+                                {referralOnScope}
+                            </div>
+                        </div>
+                    </div>
+                    <hr />
+                </CustomCollapse>
+                <div className="ds-save-btn">
+                    <button onClick={this.saveLink} className="btn btn-primary">Save Configuration</button>
+                </div>
+                <ConfirmPopup
+                    showModal={this.state.showDeleteConfirm}
+                    closeHandler={this.closeDeleteConfirm}
+                    actionFunc={this.deleteLink}
+                    actionParam={this.props.suffix}
+                    msg="Are you really sure you want to delete this database link?"
+                    msgContent={this.props.suffix}
+                />
+            </div>
+        );
+    }
+}
+
+//
+// Chaining modals
+//
+
+export class ChainControlsModal extends React.Component {
+    render() {
+        const {
+            showModal,
+            closeHandler,
+            handleChange,
+            saveHandler,
+            oidList
+        } = this.props;
+
+        const oids = oidList.map((oid) =>
+            <option key={oid} value={oid}>{oid}</option>
+        );
+
+        return (
+            <Modal show={showModal} onHide={closeHandler}>
+                <div className="ds-no-horizontal-scrollbar">
+                    <Modal.Header>
+                        <button
+                            className="close"
+                            onClick={closeHandler}
+                            aria-hidden="true"
+                            aria-label="Close"
+                        >
+                            <Icon type="pf" name="close" />
+                        </button>
+                        <Modal.Title>
+                            Chaining LDAP Controls
+                        </Modal.Title>
+                    </Modal.Header>
+                    <Modal.Body>
+                        <Form horizontal autoComplete="off">
+                            <label className="ds-config-label" htmlFor="avail-chaining-oid-list" title="A list of LDAP control OIDs to be forwarded through chaining">Available LDAP Controls</label>
+                            <div>
+                                <select id="avail-chaining-oid-list" onChange={handleChange} className="ds-chaining-form-list" size="10" multiple>
+                                    {oids}
+                                </select>
+                            </div>
+                        </Form>
+                    </Modal.Body>
+                    <Modal.Footer className="ds-modal-footerZZZ">
+                        <Button
+                            bsStyle="default"
+                            className="btn-cancel"
+                            onClick={closeHandler}
+                        >
+                            Cancel
+                        </Button>
+                        <Button
+                            bsStyle="primary"
+                            onClick={saveHandler}
+                        >
+                            Add & Save New Controls
+                        </Button>
+                    </Modal.Footer>
+                </div>
+            </Modal>
+        );
+    }
+}
+
+export class ChainCompsModal extends React.Component {
+    render() {
+        const {
+            showModal,
+            closeHandler,
+            handleChange,
+            saveHandler,
+            compList
+        } = this.props;
+
+        const comps = compList.map((comp) =>
+            <option key={comp} value={comp}>{comp}</option>
+        );
+
+        return (
+            <Modal show={showModal} onHide={closeHandler}>
+                <div className="ds-no-horizontal-scrollbar">
+                    <Modal.Header>
+                        <button
+                            className="close"
+                            onClick={closeHandler}
+                            aria-hidden="true"
+                            aria-label="Close"
+                        >
+                            <Icon type="pf" name="close" />
+                        </button>
+                        <Modal.Title>
+                            Chaining Components
+                        </Modal.Title>
+                    </Modal.Header>
+                    <Modal.Body>
+                        <Form horizontal autoComplete="off">
+                            <label className="ds-config-label" htmlFor="avail-chaining-comp-list" title="A list of LDAP control OIDs to be forwarded through chaining">Available Components</label>
+                            <div>
+                                <select id="avail-chaining-comp-list" onChange={handleChange} className="ds-chaining-form-list" size="10" multiple>
+                                    {comps}
+                                </select>
+                            </div>
+                        </Form>
+                    </Modal.Body>
+                    <Modal.Footer className="ds-modal-footer">
+                        <Button
+                            bsStyle="default"
+                            className="btn-cancel"
+                            onClick={closeHandler}
+                        >
+                            Cancel
+                        </Button>
+                        <Button
+                            bsStyle="primary"
+                            onClick={saveHandler}
+                        >
+                            Add & Save New Components
+                        </Button>
+                    </Modal.Footer>
+                </div>
+            </Modal>
+        );
+    }
+}
+
+// Property types and defaults
+
+ChainCompsModal.propTypes = {
+    showModal: PropTypes.bool,
+    closeHandler: PropTypes.func,
+    handleChange: PropTypes.func,
+    saveHandler: PropTypes.func,
+    compList: PropTypes.array,
+};
+
+ChainCompsModal.defaultProps = {
+    showModal: false,
+    closeHandler: noop,
+    handleChange: noop,
+    saveHandler: noop,
+    compList: [],
+};
+
+ChainControlsModal.propTypes = {
+    showModal: PropTypes.bool,
+    closeHandler: PropTypes.func,
+    handleChange: PropTypes.func,
+    saveHandler: PropTypes.func,
+    oidList: PropTypes.array,
+};
+
+ChainControlsModal.defaultProps = {
+    showModal: false,
+    closeHandler: noop,
+    handleChange: noop,
+    saveHandler: noop,
+    oidList: [],
+};
+
+ChainingDatabaseConfig.propTypes = {
+    serverId: PropTypes.string,
+    addNotification: PropTypes.func,
+    reload: PropTypes.func,
+    data: PropTypes.object,
+};
+
+ChainingDatabaseConfig.defaultProps = {
+    serverId: "",
+    addNotification: noop,
+    reload: noop,
+    data: {},
+};
+
+ChainingConfig.propTypes = {
+    serverId: PropTypes.string,
+    suffix: PropTypes.string,
+    bename: PropTypes.string,
+    loadSuffixTree: PropTypes.func,
+    addNotification: PropTypes.func,
+    data: PropTypes.object,
+    reload: PropTypes.func,
+};
+
+ChainingConfig.defaultProps = {
+    serverId: "",
+    suffix: "",
+    bename: "",
+    loadSuffixTree: noop,
+    addNotification: noop,
+    data: {},
+    reload: noop,
+};
diff --git a/src/cockpit/389-console/src/lib/database/databaseConfig.jsx b/src/cockpit/389-console/src/lib/database/databaseConfig.jsx
new file mode 100644
index 0000000..a34316d
--- /dev/null
+++ b/src/cockpit/389-console/src/lib/database/databaseConfig.jsx
@@ -0,0 +1,398 @@
+import cockpit from "cockpit";
+import React from "react";
+import CustomCollapse from "../customCollapse.jsx";
+import { log_cmd } from "../tools.jsx";
+import {
+    Spinner,
+    noop
+} from "patternfly-react";
+import PropTypes from "prop-types";
+import "../../css/ds.css";
+
+export class GlobalDatabaseConfig extends React.Component {
+    constructor(props) {
+        super(props);
+        this.state = {
+            db_cache_auto: this.props.data.db_cache_auto,
+            import_cache_auto: this.props.data.import_cache_auto,
+            looklimit: this.props.data.looklimit,
+            idscanlimit: this.props.data.idscanlimit,
+            pagelooklimit: this.props.data.pagelooklimit,
+            pagescanlimit: this.props.data.pagescanlimit,
+            rangelooklimit: this.props.data.rangelooklimit,
+            autosize: this.props.data.autosize,
+            autosizesplit: this.props.data.autosizesplit,
+            dbcachesize: this.props.data.dbcachesize,
+            txnlogdir: this.props.data.txnlogdir,
+            dbhomedir: this.props.data.dbhomedir,
+            dblocks: this.props.data.dblocks,
+            chxpoint: this.props.data.chxpoint,
+            compactinterval: this.props.data.compactinterval,
+            importcachesize: this.props.data.importcachesize,
+            importcacheauto: this.props.data.importcacheauto,
+            // These variables store the original value (used for saving config)
+            _looklimit: this.props.data.looklimit,
+            _idscanlimit: this.props.data.idscanlimit,
+            _pagelooklimit: this.props.data.pagelooklimit,
+            _pagescanlimit: this.props.data.pagescanlimit,
+            _rangelooklimit: this.props.data.rangelooklimit,
+            _autosize: this.props.data.autosize,
+            _autosizesplit: this.props.data.autosizesplit,
+            _dbcachesize: this.props.data.dbcachesize,
+            _txnlogdir: this.props.data.txnlogdir,
+            _dbhomedir: this.props.data.dbhomedir,
+            _dblocks: this.props.data.dblocks,
+            _chxpoint: this.props.data.chxpoint,
+            _compactinterval: this.props.data.compactinterval,
+            _importcachesize: this.props.data.importcachesize,
+            _importcacheauto: this.props.data.importcacheauto,
+            _db_cache_auto: this.props.data.db_cache_auto,
+            _import_cache_auto: this.props.data.import_cache_auto,
+        };
+        this.handleChange = this.handleChange.bind(this);
+        this.select_auto_cache = this.select_auto_cache.bind(this);
+        this.select_auto_import_cache = this.select_auto_import_cache.bind(this);
+        this.save_db_config = this.save_db_config.bind(this);
+    }
+
+    select_auto_cache (e) {
+        this.setState({
+            db_cache_auto: !this.state.db_cache_auto
+        }, this.handleChange(e));
+    }
+
+    select_auto_import_cache (e) {
+        this.setState({
+            import_cache_auto: !this.state.import_cache_auto
+        }, this.handleChange(e));
+    }
+
+    handleChange(e) {
+        // Generic
+        const value = e.target.type === 'checkbox' ? e.target.checked : e.target.value;
+        this.setState({
+            [e.target.id]: value
+        });
+    }
+
+    save_db_config() {
+        // Build up the command list
+        let cmd = [
+            'dsconf', '-j', 'ldapi://%2fvar%2frun%2fslapd-' + this.props.serverId + '.socket',
+            'backend', 'config', 'set'
+        ];
+        let requireRestart = false;
+
+        if (this.state._looklimit != this.state.looklimit) {
+            cmd.push("--lookthroughlimit=" + this.state.looklimit);
+        }
+        if (this.state._idscanlimit != this.state.idscanlimit) {
+            cmd.push("--idlistscanlimit=" + this.state.idscanlimit);
+        }
+        if (this.state._pagelooklimit != this.state.pagelooklimit) {
+            cmd.push("--pagedlookthroughlimit=" + this.state.pagelooklimit);
+        }
+        if (this.state._pagescanlimit != this.state.pagescanlimit) {
+            cmd.push("--pagedidlistscanlimit=" + this.state.pagescanlimit);
+        }
+        if (this.state._rangelooklimit != this.state.rangelooklimit) {
+            cmd.push("--rangelookthroughlimit=" + this.state.rangelooklimit);
+        }
+        if (this.state.db_cache_auto) {
+            // Auto cache is selected
+            if (this.state._db_cache_auto != this.state.db_cache_auto) {
+                // We just enabled auto cache,
+                if (this.state.autosize == "0") {
+                    cmd.push("--cache-autosize=10");
+                } else {
+                    cmd.push("--cache-autosize=" + this.state.autosize);
+                }
+                requireRestart = true;
+            } else if (this.state._autosize != this.state.autosize) {
+                // Update auto cache settings if it changed
+                cmd.push("--cache-autosize=" + this.state.autosize);
+                requireRestart = true;
+            }
+        } else {
+            // No auto cache, check if we need to reset the value
+            if (this.state._db_cache_auto != this.state.db_cache_auto) {
+                // We just disabled auto cache
+                cmd.push("--cache-autosize=0");
+                requireRestart = true;
+            }
+        }
+        if (this.state._autosizesplit != this.state.autosizesplit) {
+            cmd.push("--cache-autosize-split=" + this.state.autosizesplit);
+            requireRestart = true;
+        }
+        if (this.state._dbcachesize != this.state.dbcachesize) {
+            cmd.push("--dbcachesize=" + this.state.dbcachesize);
+            requireRestart = true;
+        }
+        if (this.state._txnlogdir != this.state.txnlogdir) {
+            cmd.push("--logdirectory=" + this.state.txnlogdir);
+            requireRestart = true;
+        }
+        if (this.state._dbhomedir != this.state.dbhomedir) {
+            cmd.push("--db-home-directory=" + this.state.dbhomedir);
+            requireRestart = true;
+        }
+        if (this.state._dblocks != this.state.dblocks) {
+            cmd.push("--locks=" + this.state.dblocks);
+            requireRestart = true;
+        }
+        if (this.state._chxpoint != this.state.chxpoint) {
+            cmd.push("--checkpoint-interval=" + this.state.chxpoint);
+            requireRestart = true;
+        }
+        if (this.state._compactinterval != this.state.compactinterval) {
+            cmd.push("--compactdb-interval=" + this.state.compactinterval);
+            requireRestart = true;
+        }
+        if (this.state.import_cache_auto) {
+            // Auto cache is selected
+            if (this.state._import_cache_auto != this.state.import_cache_auto) {
+                // We just enabled auto cache,
+                if (this.state.importcachesize == "0") {
+                    cmd.push("--import-cache-autosize=-1");
+                } else {
+                    cmd.push("--import-cache-autosize=" + this.state.importcachesize);
+                }
+            } else if (this.state._importcachesize != this.state.importcachesize) {
+                // Update auto cache settings if it changed
+                cmd.push("--import-cache-autosize=" + this.state.importcachesize);
+            }
+        } else {
+            // Auto cache is not selected, check if we need to reset the value
+            if (this.state._import_cache_auto != this.state.import_cache_auto) {
+                // We just disabled auto cache
+                cmd.push("--import-cache-autosize=0");
+            }
+        }
+        if (this.state._importcachesize != this.state.importcachesize) {
+            cmd.push("--import-cachesize=" + this.state.importcachesize);
+        }
+        if (cmd.length > 6) {
+            log_cmd("save_db_config", "Applying config change", cmd);
+            let msg = "Successfully updated database configuration";
+            if (requireRestart) {
+                msg = ("Successfully updated database configuration.  These " +
+                    "changes require the server to be restarted to take effect");
+            }
+            cockpit
+                    .spawn(cmd, {superuser: true, "err": "message"})
+                    .done(content => {
+                        // Continue with the next mod
+                        this.props.reload();
+                        this.props.addNotification(
+                            "success",
+                            msg
+                        );
+                    })
+                    .fail(err => {
+                        this.props.reload();
+                        this.props.addNotification(
+                            "error",
+                            `Error updating configuration - ${err}`
+                        );
+                    });
+        }
+    }
+
+    render() {
+        let db_cache_form;
+        let import_cache_form;
+        let db_auto_checked = false;
+        let import_auto_checked = false;
+
+        if (this.state.db_cache_auto) {
+            db_cache_form = <div id="auto-cache-form" className="ds-margin-left">
+                <div>
+                    <label htmlFor="autosize" className="ds-config-label-xlrg"
+                        title="Enable database and entry cache auto-tuning using a percentage of the systems current resources (nsslapd-cache-autosize).">
+                        System Memory Percentage</label><input className="ds-input" type="text"
+                        id="autosizee" size="10" onChange={this.handleChange}
+                        value={this.state.autosize} />
+                </div>
+                <div>
+                    <label htmlFor="autosizesplit" className="ds-config-label-xlrg"
+                        title="Sets the percentage of memory that is used for the database cache. The remaining percentage is used for the entry cache (nsslapd-cache-autosize-split).">
+                        DB Cache Percentage</label><input className="ds-input" type="text"
+                        id="autosizesplit" size="10" onChange={this.handleChange}
+                        value={this.state.autosizesplit} />
+                </div>
+            </div>;
+            db_auto_checked = true;
+        } else {
+            db_cache_form = <div id="manual-cache-form" className="ds-margin-left">
+                <label htmlFor="dbcachesize" className="ds-config-label-xlrg"
+                    title="Specifies the database index cache size in bytes (nsslapd-dbcachesize).">
+                    Database Cache Size (bytes)</label><input className="ds-input" type="text"
+                    id="dbcachesize" size="10" onChange={this.handleChange} value={this.state.dbcachesize} />
+            </div>;
+            db_auto_checked = false;
+        }
+
+        if (this.state.import_cache_auto) {
+            import_cache_form = <div id="auto-import-cache-form" className="ds-margin-left">
+                <label htmlFor="importcacheauto" className="ds-config-label-xlrg"
+                    title="Enter '-1' to use 50% of available memory, '0' to disable autotuning, or enter the percentage of available memory to use.  Value range -1 through 100, default is '-1' (nsslapd-import-cache-autosize).">
+                    Import Cache Autosize</label><input className="ds-input" type="text"
+                    id="importcacheauto" size="10"
+                    onChange={this.handleChange} value={this.state.importcacheauto} />
+            </div>;
+            import_auto_checked = true;
+        } else {
+            import_cache_form = <div id="manual-import-cache-form" className="ds-margin-left">
+                <label htmlFor="importcachesize" className="ds-config-label-xlrg"
+                    title="The size of the database cache used in the bulk import process. (nsslapd-import-cachesize).">
+                    Import Cache Size (bytes)</label><input className="ds-input" type="text" id="importcachesize"
+                    size="10" onChange={this.handleChange} value={this.state.importcachesize} />
+            </div>;
+            import_auto_checked = false;
+        }
+
+        let spinner = "";
+        if (this.state.loading) {
+            spinner =
+                <div className="ds-loading-spinner ds-center">
+                    <p />
+                    <h4>Loading global database configuration ...</h4>
+                    <Spinner loading size="md" />
+                </div>;
+        }
+
+        return (
+            <div className="container-fluid" id="db-global-page">
+                {spinner}
+                <div className={this.state.loading ? 'ds-fadeout' : 'ds-fadein'}>
+                    <h3 className="ds-config-header">Global Database Configuration</h3>
+                    <hr />
+                    <div className="ds-container">
+                        <div className="ds-inline">
+                            <div>
+                                <label htmlFor="nsslapd-lookthrough-limit" className="ds-config-label"
+                                    title="The maximum number of entries that the Directory Server will check when examining candidate entries in response to a search request (nsslapd-lookthrough-limit).">
+                                    Database Look Though Limit</label><input id="looklimit" value={this.state.looklimit}
+                                    onChange={this.handleChange} className="ds-input" type="text" size="15" />
+                            </div>
+                            <div>
+                                <label htmlFor="nsslapd-idlistscanlimit" className="ds-config-label"
+                                    title="The number of entry IDs that are searched during a search operation (nsslapd-idlistscanlimit).">
+                                    ID List Scan Limit</label><input id="idscanlimit" value={this.state.idscanlimit}
+                                    onChange={this.handleChange} className="ds-input" type="text"size="15" />
+                            </div>
+                        </div>
+                        <div className="ds-divider" />
+                        <div className="ds-inline">
+                            <div>
+                                <label htmlFor="nsslapd-pagedlookthroughlimit" className="ds-config-label"
+                                    title="The maximum number of entries that the Directory Server will check when examining candidate entries for a search which uses the simple paged results control (nsslapd-pagedlookthroughlimit).">
+                                    Paged Search Look Through Limit</label><input id="pagelooklimit" value={this.state.pagelooklimit}
+                                    onChange={this.handleChange} className="ds-input" type="text" size="15" />
+                            </div>
+                            <div>
+                                <label htmlFor="nsslapd-pagedidlistscanlimit" className="ds-config-label"
+                                    title="The number of entry IDs that are searched, specifically, for a search operation using the simple paged results control (nsslapd-pagedidlistscanlimit).">
+                                    Paged Search ID List Scan Limit</label><input id="pagescanlimit"
+                                    value={this.state.pagescanlimit} onChange={this.handleChange}
+                                    className="ds-input" type="text" size="15" />
+                            </div>
+                            <div>
+                                <label htmlFor="nsslapd-rangelookthroughlimit" className="ds-config-label"
+                                    title="The maximum number of entries that the Directory Server will check when examining candidate entries in response to a range search request (nsslapd-rangelookthroughlimit).">
+                                    Range Search Look Through Limit</label><input id="rangelooklimit"
+                                    value={this.state.rangelooklimit} onChange={this.handleChange}
+                                    className="ds-input" type="text" size="15" />
+                            </div>
+                        </div>
+                    </div>
+                    <div className="ds-container">
+                        <div>
+                            <h4 className="ds-sub-header">Database Cache Settings</h4>
+                            <hr />
+                            <div>
+                                <label htmlFor="autoCacheChkbox" title="Set Database/Entry to be set automatically"><input
+                                    className="ds-left-indent" type="checkbox" id="autoCacheChkbox" checked={db_auto_checked}
+                                    onChange={this.select_auto_cache} /> Automatic Cache Tuning</label>
+                                {db_cache_form}
+                            </div>
+                        </div>
+                        <div className="ds-divider-lrg" />
+                        <div>
+                            <h4 className="ds-sub-header">Import Cache Settings</h4>
+                            <hr />
+                            <div>
+                                <label htmlFor="autoImportCacheChkbox"title="Set Database/Entry to be set automatically"><input
+                                    className="ds-left-indent" type="checkbox" id="autoImportCacheChkbox"
+                                    onChange={this.select_auto_import_cache}
+                                    checked={import_auto_checked} /> Automatic Import Cache Tuning</label>
+                                {import_cache_form}
+                            </div>
+                        </div>
+                    </div>
+                    <CustomCollapse>
+                        <div className="ds-accordion-panel">
+                            <div className="ds-container">
+                                <div className="ds-inline">
+                                    <div>
+                                        <label htmlFor="nsslapd-db-logdirectory" className="ds-config-label"
+                                            title="Database Transaction Log Location (nsslapd-db-logdirectory).">
+                                            Transaction Logs Directory</label><input id="txnlogdir" value={this.state.txnlogdir}
+                                            onChange={this.handleChange} className="ds-input" type="text" size="25" />
+                                    </div>
+                                    <div>
+                                        <label htmlFor="nsslapd-db-home-directory" className="ds-config-label"
+                                        title="Location for database memory mapped files.  You must specify a subdirectory of a tempfs type filesystem (nsslapd-db-home-directory).">
+                                            Database Home Directory</label><input id="dbhomedir" value={this.state.dbhomedir}
+                                            onChange={this.handleChange} className="ds-input" type="text" size="25" />
+                                    </div>
+                                    <div>
+                                        <label htmlFor="nsslapd-db-locks" className="ds-config-label"
+                                            title="The number of database locks (nsslapd-db-locks).">
+                                            Database Locks</label><input id="dblocks" value={this.state.dblocks}
+                                            onChange={this.handleChange} className="ds-input" type="text" size="25" />
+                                    </div>
+                                    <div>
+                                        <label htmlFor="nsslapd-db-checkpoint-interval" className="ds-config-label"
+                                            title="Amount of time in seconds after which the Directory Server sends a checkpoint entry to the database transaction log (nsslapd-db-checkpoint-interval).">
+                                            Database Checkpoint Interval</label><input id="chxpoint" value={this.state.chxpoint}
+                                            onChange={this.handleChange} className="ds-input" type="text" size="25" />
+                                    </div>
+                                    <div>
+                                        <label htmlFor="nsslapd-db-compactdb-interval" className="ds-config-label"
+                                            title="The interval in seconds when the database is compacted (nsslapd-db-compactdb-interval).">
+                                            Database Compact Interval</label><input id="compactinterval" value={this.state.compactinterval}
+                                            onChange={this.handleChange}className="ds-input" type="text" size="25" />
+                                    </div>
+                                </div>
+                            </div>
+                            <p />
+                        </div>
+                    </CustomCollapse>
+                    <hr />
+                    <div className="ds-save-btn">
+                        <button className="btn btn-primary save-button"
+                            onClick={this.save_db_config}>Save Configuration</button>
+                    </div>
+                </div>
+            </div>
+        );
+    }
+}
+
+// Property types and defaults
+
+GlobalDatabaseConfig.propTypes = {
+    serverId: PropTypes.string,
+    addNotification: PropTypes.func,
+    data: PropTypes.object,
+    reload: PropTypes.func,
+};
+
+GlobalDatabaseConfig.defaultProps = {
+    serverId: "",
+    addNotification: noop,
+    data: {},
+    reload: noop,
+};
diff --git a/src/cockpit/389-console/src/lib/database/databaseModal.jsx b/src/cockpit/389-console/src/lib/database/databaseModal.jsx
new file mode 100644
index 0000000..01db9bb
--- /dev/null
+++ b/src/cockpit/389-console/src/lib/database/databaseModal.jsx
@@ -0,0 +1,502 @@
+import React from "react";
+import {
+    Modal,
+    Row,
+    Col,
+    ControlLabel,
+    Icon,
+    Button,
+    Form,
+    FormControl,
+    Spinner,
+    noop
+} from "patternfly-react";
+import { LDIFTable } from "./databaseTables.jsx";
+import PropTypes from "prop-types";
+import "../../css/ds.css";
+
+class CreateLinkModal extends React.Component {
+    render() {
+        const {
+            showModal,
+            closeHandler,
+            handleChange,
+            saveHandler,
+            suffix,
+            pwdMatch,
+            error,
+        } = this.props;
+
+        return (
+            <Modal show={showModal} onHide={closeHandler}>
+                <div className="ds-no-horizontal-scrollbar">
+                    <Modal.Header>
+                        <button
+                            className="close"
+                            onClick={closeHandler}
+                            aria-hidden="true"
+                            aria-label="Close"
+                        >
+                            <Icon type="pf" name="close" />
+                        </button>
+                        <Modal.Title>
+                            Create Database Link
+                        </Modal.Title>
+                    </Modal.Header>
+                    <Modal.Body>
+                        <Form horizontal autoComplete="off">
+                            <div>
+                                <label htmlFor="createLinkSuffix" className="ds-config-label" title="The RDN of the link suffix">
+                                    Link Sub-Suffix</label><input className={error.createLinkSuffix ? "ds-input-bad ds-input-right" : "ds-input ds-input-right"} onChange={handleChange} type="text" id="createLinkSuffix" size="12" /><b><font color="blue"> ,{suffix}</font></b>
+                            </div>
+                            <div>
+                                <label htmlFor="createLinkName" className="ds-config-label" title="A name for the backend chaining database link">
+                                    Link Database Name</label><input onChange={handleChange} className={error.createLinkName ? "ds-input-bad" : "ds-input"} type="text" id="createLinkName" size="45" />
+                            </div>
+                            <div>
+                                <label htmlFor="createNsfarmserverurl" className="ds-config-label" title="The LDAP URL for the remote server.  Add additional failover LDAP URLs separated by a space. (nsfarmserverurl)">
+                                    Remote Server URL(s)</label><input className={error.createNsfarmserverurl ? "ds-input-bad" : "ds-input"} onChange={handleChange} type="text" id="createNsfarmserverurl" size="45" />
+                            </div>
+                            <div>
+                                <input type="checkbox" onChange={handleChange} className="ds-left-indent ds-config-checkbox" id="createUseStartTLS" /><label
+                                    htmlFor="createUseStartTLS" className="ds-label" title="Use StartTLS for the remote server LDAP URL"> Use StartTLS</label>
+                            </div>
+                            <div>
+                                <label htmlFor="createNsmultiplexorbinddn" className="ds-config-label" title="Bind DN used to authenticate against the remote server (nsmultiplexorbinddn).">Remote Server Bind DN</label><input
+                                    className={error.createNsmultiplexorbinddn ? "ds-input-bad" : "ds-input"} type="text" onChange={handleChange} placeholder="Bind DN" id="createNsmultiplexorbinddn" size="45" />
+                            </div>
+                            <div>
+                                <label htmlFor="createNsmultiplexorcredentials" className="ds-config-label" title="Replication Bind DN (nsDS5ReplicaCredentials).">Bind DN Credentials</label><input
+                                    className={error.createNsmultiplexorcredentials ? "ds-input-bad" : "ds-input"} type="password" onChange={handleChange} placeholder="Enter password" id="createNsmultiplexorcredentials" size="45" />
+                            </div>
+                            <div>
+                                <label htmlFor="createNsmultiplexorcredentialsConfirm" className="ds-config-label" title="Confirm password">Confirm Password</label><input
+                                    className={(error.createNsmultiplexorcredentialsConfirm || !pwdMatch) ? "ds-input-bad" : "ds-input"} type="password" onChange={handleChange} placeholder="Confirm password" id="createNsmultiplexorcredentialsConfirm" size="45" />
+                            </div>
+                            <div>
+                                <label htmlFor="createNsbindmechanism" className="ds-config-label" title="The bind method for contacting the remote server  (nsbindmechanism).">Bind Method</label><select
+                                    className="btn btn-default dropdown ds-dblink-dropdown" onChange={handleChange} id="createNsbindmechanism">
+                                    <option>Simple</option>
+                                    <option>SASL/DIGEST-MD5</option>
+                                    <option>SASL/GSSAPI</option>
+                                </select>
+                            </div>
+                        </Form>
+                    </Modal.Body>
+                    <Modal.Footer>
+                        <Button
+                            bsStyle="default"
+                            className="btn-cancel"
+                            onClick={closeHandler}
+                        >
+                            Cancel
+                        </Button>
+                        <Button
+                            bsStyle="primary"
+                            onClick={saveHandler}
+                        >
+                            Create Database Link
+                        </Button>
+                    </Modal.Footer>
+                </div>
+            </Modal>
+        );
+    }
+}
+
+class CreateSubSuffixModal extends React.Component {
+    render() {
+        const {
+            showModal,
+            closeHandler,
+            handleChange,
+            saveHandler,
+            suffix,
+            error
+        } = this.props;
+
+        return (
+            <Modal show={showModal} onHide={closeHandler}>
+                <div>
+                    <Modal.Header>
+                        <button
+                            className="close"
+                            onClick={closeHandler}
+                            aria-hidden="true"
+                            aria-label="Close"
+                        >
+                            <Icon type="pf" name="close" />
+                        </button>
+                        <Modal.Title>
+                            Create Sub Suffix
+                        </Modal.Title>
+                    </Modal.Header>
+                    <Modal.Body>
+                        <Form horizontal autoComplete="off">
+                            <Row title="Database Suffix DN (nsslapd-suffix)">
+                                <Col sm={3}>
+                                    <ControlLabel>Sub-Suffix DN</ControlLabel>
+                                </Col>
+                                <Col sm={3}>
+                                    <FormControl
+                                        type="text"
+                                        id="subSuffixValue"
+                                        className={error.subSuffixValue ? "ds-input-bad ds-input-right" : "ds-input-right"}
+                                        onChange={handleChange}
+                                    />
+                                </Col>
+                                <Col sm={6} className="ds-col-append">
+                                    <ControlLabel><b><font color="blue">,{suffix}</font></b></ControlLabel>
+                                </Col>
+                            </Row>
+                            <p />
+                            <Row title="Database backend name (nsslapd-backend)">
+                                <Col sm={3}>
+                                    <ControlLabel>Backend Name</ControlLabel>
+                                </Col>
+                                <Col sm={9}>
+                                    <FormControl
+                                        type="text"
+                                        id="subSuffixBeName"
+                                        className={error.subSuffixBeName ? "ds-input-bad" : ""}
+                                        onChange={handleChange}
+                                    />
+                                </Col>
+                            </Row>
+                        </Form>
+                    </Modal.Body>
+                    <Modal.Footer>
+                        <Button
+                            bsStyle="default"
+                            className="btn-cancel"
+                            onClick={closeHandler}
+                        >
+                            Cancel
+                        </Button>
+                        <Button
+                            bsStyle="primary"
+                            onClick={saveHandler}
+                        >
+                            Create Sub-Suffix
+                        </Button>
+                    </Modal.Footer>
+                </div>
+            </Modal>
+        );
+    }
+}
+
+class ExportModal extends React.Component {
+    render() {
+        const {
+            showModal,
+            closeHandler,
+            handleChange,
+            saveHandler,
+            spinning,
+            error
+        } = this.props;
+        let spinner = "";
+        if (spinning) {
+            spinner =
+                <Row>
+                    <div className="ds-modal-spinner">
+                        <Spinner loading inline size="lg" />Exporting database... <font size="1">(You can safely close this window)</font>
+                    </div>
+                </Row>;
+        }
+
+        return (
+            <Modal show={showModal} onHide={closeHandler}>
+                <div className="ds-no-horizontal-scrollbar">
+                    <Modal.Header>
+                        <button
+                            className="close"
+                            onClick={closeHandler}
+                            aria-hidden="true"
+                            aria-label="Close"
+                        >
+                            <Icon type="pf" name="close" />
+                        </button>
+                        <Modal.Title>
+                            Export Database To LDIF File
+                        </Modal.Title>
+                    </Modal.Header>
+                    <Modal.Body>
+                        <Form horizontal autoComplete="off">
+                            <Row title="Name of exported LDIF file">
+                                <Col sm={3}>
+                                    <ControlLabel>LDIF File Name</ControlLabel>
+                                </Col>
+                                <Col sm={9}>
+                                    <FormControl
+                                        type="text"
+                                        id="ldifLocation"
+                                        className={error.ldifLocation ? "ds-input-bad" : ""}
+                                        onChange={handleChange}
+                                    />
+                                </Col>
+                            </Row>
+                            <p />
+                            {spinner}
+                        </Form>
+                    </Modal.Body>
+                    <Modal.Footer>
+                        <Button
+                            bsStyle="default"
+                            className="btn-cancel"
+                            onClick={closeHandler}
+                        >
+                            Cancel
+                        </Button>
+                        <Button
+                            bsStyle="primary"
+                            onClick={saveHandler}
+                        >
+                            Export Database
+                        </Button>
+                    </Modal.Footer>
+                </div>
+            </Modal>
+        );
+    }
+}
+
+class ImportModal extends React.Component {
+    render() {
+        const {
+            showModal,
+            closeHandler,
+            handleChange,
+            saveHandler,
+            spinning,
+            rows,
+            suffix
+        } = this.props;
+
+        let suffixRows = [];
+        let spinner = "";
+        if (spinning) {
+            spinner =
+                <Row>
+                    <div className="ds-modal-spinner">
+                        <p />
+                        <Spinner loading inline size="lg" />Importing LDIF file... <font size="1">(You can safely close this window)</font>
+                    </div>
+                </Row>;
+        }
+        for (let idx in rows) {
+            if (rows[idx].suffix == suffix) {
+                suffixRows.push(rows[idx]);
+            }
+        }
+
+        return (
+            <Modal show={showModal} onHide={closeHandler}>
+                <div className="ds-no-horizontal-scrollbar">
+                    <Modal.Header>
+                        <button
+                            className="close"
+                            onClick={closeHandler}
+                            aria-hidden="true"
+                            aria-label="Close"
+                        >
+                            <Icon type="pf" name="close" />
+                        </button>
+                        <Modal.Title>
+                            Initialize Database via LDIF File
+                        </Modal.Title>
+                    </Modal.Header>
+                    <Modal.Body>
+                        <p />
+                        <LDIFTable
+                            rows={suffixRows}
+                            confirmImport={this.props.showConfirmImport}
+                        />
+                        <hr />
+                        <Form horizontal autoComplete="off">
+                            <Row title="The full path to the LDIF file.  The server must have permissions to read it">
+                                <Col sm={4}>
+                                    <ControlLabel>Or, enter LDIF location</ControlLabel>
+                                </Col>
+                                <Col sm={6}>
+                                    <FormControl
+                                        type="text"
+                                        id="ldifLocation"
+                                        onChange={handleChange}
+                                    />
+                                </Col>
+                                <Col sm={2}>
+                                    <Button
+                                        bsStyle="primary"
+                                        onClick={saveHandler}
+                                    >
+                                        Import
+                                    </Button>
+                                </Col>
+                            </Row>
+                            <p />
+                            {spinner}
+                        </Form>
+                    </Modal.Body>
+                    <Modal.Footer>
+                        <Button
+                            bsStyle="default"
+                            className="btn-cancel"
+                            onClick={closeHandler}
+                        >
+                            Close
+                        </Button>
+                    </Modal.Footer>
+                </div>
+            </Modal>
+        );
+    }
+}
+
+class ReindexModal extends React.Component {
+    render() {
+        const {
+            showModal,
+            closeHandler,
+            msg
+        } = this.props;
+
+        return (
+            <Modal show={showModal} onHide={closeHandler}>
+                <div className="ds-no-horizontal-scrollbar">
+                    <Modal.Header>
+                        <button
+                            className="close"
+                            onClick={closeHandler}
+                            aria-hidden="true"
+                            aria-label="Close"
+                        >
+                            <Icon type="pf" name="close" />
+                        </button>
+                        <Modal.Title>
+                            Index Attribute
+                        </Modal.Title>
+                    </Modal.Header>
+                    <Modal.Body>
+                        <Form horizontal autoComplete="off">
+                            <div className="ds-modal-spinner">
+                                <Spinner loading inline size="lg" /> Indexing <b>{msg}</b> ...
+                                <p><font size="1">(You can safely close this window)</font></p>
+                            </div>
+                        </Form>
+                    </Modal.Body>
+                    <Modal.Footer>
+                        <Button
+                            bsStyle="default"
+                            className="btn-cancel"
+                            onClick={closeHandler}
+                        >
+                            Close
+                        </Button>
+                    </Modal.Footer>
+                </div>
+            </Modal>
+        );
+    }
+}
+
+// Property types and defaults
+
+CreateLinkModal.propTypes = {
+    showModal: PropTypes.bool,
+    closeHandler: PropTypes.func,
+    handleChange: PropTypes.func,
+    saveHandler: PropTypes.func,
+    suffix: PropTypes.string,
+    pwdMatch: PropTypes.bool,
+    error: PropTypes.object,
+};
+
+CreateLinkModal.defaultProps = {
+    showModal: false,
+    closeHandler: noop,
+    handleChange: noop,
+    saveHandler: noop,
+    suffix: "",
+    pwdMatch: false,
+    error: {},
+};
+
+CreateSubSuffixModal.propTypes = {
+    showModal: PropTypes.bool,
+    closeHandler: PropTypes.func,
+    handleChange: PropTypes.func,
+    saveHandler: PropTypes.func,
+    suffix: PropTypes.string,
+    error: PropTypes.object,
+};
+
+CreateSubSuffixModal.defaultProps = {
+    showModal: false,
+    closeHandler: noop,
+    handleChange: noop,
+    saveHandler: noop,
+    suffix: "",
+    error: {},
+};
+
+ExportModal.propTypes = {
+    showModal: PropTypes.bool,
+    closeHandler: PropTypes.func,
+    handleChange: PropTypes.func,
+    saveHandler: PropTypes.func,
+    error: PropTypes.object,
+    spinning: PropTypes.bool
+};
+
+ExportModal.defaultProps = {
+    showModal: false,
+    closeHandler: noop,
+    handleChange: noop,
+    saveHandler: noop,
+    error: {},
+    spinning: false
+};
+
+ImportModal.propTypes = {
+    showModal: PropTypes.bool,
+    closeHandler: PropTypes.func,
+    handleChange: PropTypes.func,
+    saveHandler: PropTypes.func,
+    spinning: PropTypes.bool,
+    showConfirmImport: PropTypes.func,
+    rows: PropTypes.array,
+    suffix: PropTypes.string
+};
+
+ImportModal.defaultProps = {
+    showModal: false,
+    closeHandler: noop,
+    handleChange: noop,
+    saveHandler: noop,
+    spinning: false,
+    showConfirmImport: noop,
+    rows: [],
+    suffix: ""
+};
+
+ReindexModal.propTypes = {
+    showModal: PropTypes.bool,
+    closeHandler: PropTypes.func,
+    msg: PropTypes.string
+};
+
+ReindexModal.defaultProps = {
+    showModal: false,
+    closeHandler: noop,
+    msg: ""
+};
+
+export {
+    ReindexModal,
+    ImportModal,
+    ExportModal,
+    CreateSubSuffixModal,
+    CreateLinkModal,
+};
diff --git a/src/cockpit/389-console/src/lib/database/databaseTables.jsx b/src/cockpit/389-console/src/lib/database/databaseTables.jsx
new file mode 100644
index 0000000..adf535e
--- /dev/null
+++ b/src/cockpit/389-console/src/lib/database/databaseTables.jsx
@@ -0,0 +1,1018 @@
+import React from "react";
+import {
+    Button,
+    DropdownButton,
+    MenuItem,
+    actionHeaderCellFormatter,
+    sortableHeaderCellFormatter,
+    tableCellFormatter,
+    noop
+} from "patternfly-react";
+import { DSTable, DSShortTable } from "../dsTable.jsx";
+import PropTypes from "prop-types";
+import "../../css/ds.css";
+
+class ReferralTable extends React.Component {
+    constructor(props) {
+        super(props);
+
+        this.state = {
+            rowKey: "name",
+            columns: [
+                {
+                    property: "name",
+                    header: {
+                        label: "Referral",
+                        props: {
+                            index: 0,
+                            rowSpan: 1,
+                            colSpan: 1,
+                            sort: true
+                        },
+                        transforms: [],
+                        formatters: [],
+                        customFormatters: [sortableHeaderCellFormatter]
+                    },
+                    cell: {
+                        props: {
+                            index: 0
+                        },
+                        formatters: [tableCellFormatter]
+                    }
+                },
+                {
+                    property: "actions",
+                    header: {
+                        label: "Actions",
+                        props: {
+                            index: 1,
+                            rowSpan: 1,
+                            colSpan: 1
+                        },
+                        formatters: [actionHeaderCellFormatter]
+                    },
+                    cell: {
+                        props: {
+                            index: 2
+                        },
+                        formatters: [
+                            (value, { rowData }) => {
+                                return [
+                                    <td key={rowData.name[0]}>
+                                        <Button
+                                            onClick={() => {
+                                                this.props.loadModalHandler(rowData);
+                                            }}
+                                        >
+                                            Delete Referral
+                                        </Button>
+                                    </td>
+                                ];
+                            }
+                        ]
+                    }
+                }
+            ]
+        };
+        this.getColumns = this.getColumns.bind(this);
+    }
+
+    getSingleColumn () {
+        return [
+            {
+                property: "msg",
+                header: {
+                    label: "Referrals",
+                    props: {
+                        index: 0,
+                        rowSpan: 1,
+                        colSpan: 1,
+                        sort: true
+                    },
+                    transforms: [],
+                    formatters: [],
+                    customFormatters: [sortableHeaderCellFormatter]
+                },
+                cell: {
+                    props: {
+                        index: 0
+                    },
+                    formatters: [tableCellFormatter]
+                }
+            },
+        ];
+    }
+
+    getColumns() {
+        return this.state.columns;
+    }
+
+    render() {
+        let refTable;
+        if (this.props.rows.length == 0) {
+            refTable = <DSShortTable
+                getColumns={this.getSingleColumn}
+                rowKey={"msg"}
+                rows={[{msg: "No referrals"}]}
+            />;
+        } else {
+            refTable = <DSShortTable
+                getColumns={this.getColumns}
+                rowKey={this.state.rowKey}
+                rows={this.props.rows}
+                disableLoadingSpinner
+            />;
+        }
+        return (
+            <div>
+                {refTable}
+            </div>
+        );
+    }
+}
+
+class IndexTable extends React.Component {
+    constructor(props) {
+        super(props);
+
+        this.state = {
+            searchField: "Indexes",
+            fieldsToSearch: ["name"],
+            rowKey: "name",
+            columns: [
+                {
+                    property: "name",
+                    header: {
+                        label: "Attribute",
+                        props: {
+                            index: 0,
+                            rowSpan: 1,
+                            colSpan: 1,
+                            sort: true
+                        },
+                        transforms: [],
+                        formatters: [],
+                        customFormatters: [sortableHeaderCellFormatter]
+                    },
+                    cell: {
+                        props: {
+                            index: 0
+                        },
+                        formatters: [tableCellFormatter]
+                    }
+                },
+                {
+                    property: "types",
+                    header: {
+                        label: "Index Types",
+                        props: {
+                            index: 1,
+                            rowSpan: 1,
+                            colSpan: 1,
+                            sort: true
+                        },
+                        transforms: [],
+                        formatters: [],
+                        customFormatters: [sortableHeaderCellFormatter]
+                    },
+                    cell: {
+                        props: {
+                            index: 1
+                        },
+                        formatters: [tableCellFormatter]
+                    }
+                },
+                {
+                    property: "matchingrules",
+                    header: {
+                        label: "Matching Rules",
+                        props: {
+                            index: 2,
+                            rowSpan: 1,
+                            colSpan: 1,
+                            sort: true
+                        },
+                        transforms: [],
+                        formatters: [],
+                        customFormatters: [sortableHeaderCellFormatter]
+                    },
+                    cell: {
+                        props: {
+                            index: 2
+                        },
+                        formatters: [tableCellFormatter]
+                    }
+                },
+            ],
+        };
+
+        if (this.props.editable) {
+            this.state.columns.push(
+                {
+                    property: "actions",
+                    header: {
+                        props: {
+                            index: 3,
+                            rowSpan: 1,
+                            colSpan: 1
+                        },
+                        formatters: [actionHeaderCellFormatter]
+                    },
+                    cell: {
+                        props: {
+                            index: 3
+                        },
+                        formatters: [
+                            (value, { rowData }) => {
+                                return [
+                                    <td key={rowData.name[0]}>
+                                        <DropdownButton id={rowData.name[0]}
+                                            bsStyle="default" title="Actions">
+                                            <MenuItem eventKey="1" onClick={() => {
+                                                this.props.editIndex(rowData);
+                                            }}
+                                            >
+                                                Edit Index
+                                            </MenuItem>
+                                            <MenuItem eventKey="2" onClick={() => {
+                                                this.props.reindexIndex(rowData);
+                                            }}
+                                            >
+                                                Reindex Index
+                                            </MenuItem>
+                                            <MenuItem divider />
+                                            <MenuItem eventKey="3" onClick={() => {
+                                                this.props.deleteIndex(rowData);
+                                            }}
+                                            >
+                                                Delete Index
+                                            </MenuItem>
+                                        </DropdownButton>
+                                    </td>
+                                ];
+                            }
+                        ]
+                    }
+                }
+            );
+        }
+        this.getColumns = this.getColumns.bind(this);
+    } // Constructor
+
+    getColumns() {
+        return this.state.columns;
+    }
+
+    render() {
+        return (
+            <div className="ds-margin-top-xlg">
+                <DSTable
+                    getColumns={this.getColumns}
+                    fieldsToSearch={this.state.fieldsToSearch}
+                    toolBarSearchField={this.state.searchField}
+                    rowKey={this.state.rowKey}
+                    rows={this.props.rows}
+                    disableLoadingSpinner
+                    toolBarPagination={[6, 12, 24, 48, 96]}
+                    toolBarPaginationPerPage={6}
+                />
+            </div>
+
+        );
+    }
+}
+
+class EncryptedAttrTable extends React.Component {
+    constructor(props) {
+        super(props);
+
+        this.state = {
+            rowKey: "name",
+            columns: [
+                {
+                    property: "name",
+                    header: {
+                        label: "Encrypted Attribute",
+                        props: {
+                            index: 0,
+                            rowSpan: 1,
+                            colSpan: 1,
+                            sort: true
+                        },
+                        transforms: [],
+                        formatters: [],
+                        customFormatters: [sortableHeaderCellFormatter]
+                    },
+                    cell: {
+                        props: {
+                            index: 0
+                        },
+                        formatters: [tableCellFormatter]
+                    }
+                },
+                {
+                    property: "actions",
+                    header: {
+                        label: "Actions",
+                        props: {
+                            index: 1,
+                            rowSpan: 1,
+                            colSpan: 1
+                        },
+                        formatters: [actionHeaderCellFormatter]
+                    },
+                    cell: {
+                        props: {
+                            index: 2
+                        },
+                        formatters: [
+                            (value, { rowData }) => {
+                                return [
+                                    <td key={rowData.name[0]}>
+                                        <Button
+                                            onClick={() => {
+                                                this.props.loadModalHandler(rowData);
+                                            }}
+                                        >
+                                            Delete Attribute
+                                        </Button>
+                                    </td>
+                                ];
+                            }
+                        ]
+                    }
+                }
+            ]
+        };
+        this.getColumns = this.getColumns.bind(this);
+    }
+
+    getSingleColumn () {
+        return [
+            {
+                property: "msg",
+                header: {
+                    label: "Encrypted Attributes",
+                    props: {
+                        index: 0,
+                        rowSpan: 1,
+                        colSpan: 1,
+                        sort: true
+                    },
+                    transforms: [],
+                    formatters: [],
+                    customFormatters: [sortableHeaderCellFormatter]
+                },
+                cell: {
+                    props: {
+                        index: 0
+                    },
+                    formatters: [tableCellFormatter]
+                }
+            },
+        ];
+    }
+
+    getColumns() {
+        return this.state.columns;
+    }
+
+    render() {
+        let attrTable;
+        if (this.props.rows.length == 0) {
+            attrTable =
+                <DSShortTable
+                    getColumns={this.getSingleColumn}
+                    rowKey={"msg"}
+                    rows={[{msg: "No encrypted attributes"}]}
+                />;
+        } else {
+            attrTable =
+                <DSShortTable
+                    getColumns={this.getColumns}
+                    rowKey={this.state.rowKey}
+                    rows={this.props.rows}
+                    disableLoadingSpinner
+                />;
+        }
+        return (
+            <div>
+                {attrTable}
+            </div>
+        );
+    }
+}
+
+class LDIFTable extends React.Component {
+    constructor(props) {
+        super(props);
+        this.state = {
+            rowKey: "name",
+            columns: [
+                {
+                    property: "name",
+                    header: {
+                        label: "LDIF File",
+                        props: {
+                            index: 0,
+                            rowSpan: 1,
+                            colSpan: 1,
+                            sort: true
+                        },
+                        transforms: [],
+                        formatters: [],
+                        customFormatters: [sortableHeaderCellFormatter]
+                    },
+                    cell: {
+                        props: {
+                            index: 0
+                        },
+                        formatters: [tableCellFormatter]
+                    }
+                },
+                {
+                    property: "date",
+                    header: {
+                        label: "Creation Date",
+                        props: {
+                            index: 1,
+                            rowSpan: 1,
+                            colSpan: 1,
+                            sort: true
+                        },
+                        transforms: [],
+                        formatters: [],
+                        customFormatters: [sortableHeaderCellFormatter]
+                    },
+                    cell: {
+                        props: {
+                            index: 1
+                        },
+                        formatters: [tableCellFormatter]
+                    }
+                },
+                {
+                    property: "size",
+                    header: {
+                        label: "Size",
+                        props: {
+                            index: 2,
+                            rowSpan: 1,
+                            colSpan: 1,
+                            sort: true
+                        },
+                        transforms: [],
+                        formatters: [],
+                        customFormatters: [sortableHeaderCellFormatter]
+                    },
+                    cell: {
+                        props: {
+                            index: 2
+                        },
+                        formatters: [tableCellFormatter]
+                    }
+                },
+                {
+                    property: "actions",
+                    header: {
+                        props: {
+                            index: 3,
+                            rowSpan: 1,
+                            colSpan: 1
+                        },
+                        formatters: [actionHeaderCellFormatter]
+                    },
+                    cell: {
+                        props: {
+                            index: 3
+                        },
+                        formatters: [
+                            (value, { rowData }) => {
+                                return [
+                                    <td key={rowData.name[0]}>
+                                        <Button
+                                            bsStyle="primary"
+                                            onClick={() => {
+                                                this.props.confirmImport(rowData);
+                                            }}
+                                        >
+                                            Import
+                                        </Button>
+                                    </td>
+                                ];
+                            }
+                        ]
+                    }
+                }
+            ]
+        };
+
+        this.getColumns = this.getColumns.bind(this);
+    }
+
+    getSingleColumn () {
+        return [
+            {
+                property: "msg",
+                header: {
+                    label: "LDIF Files",
+                    props: {
+                        index: 0,
+                        rowSpan: 1,
+                        colSpan: 1,
+                        sort: true
+                    },
+                    transforms: [],
+                    formatters: [],
+                    customFormatters: [sortableHeaderCellFormatter]
+                },
+                cell: {
+                    props: {
+                        index: 0
+                    },
+                    formatters: [tableCellFormatter]
+                }
+            },
+        ];
+    }
+
+    getColumns() {
+        return this.state.columns;
+    }
+
+    render() {
+        let LDIFTable;
+        if (this.props.rows.length == 0) {
+            LDIFTable = <DSShortTable
+                getColumns={this.getSingleColumn}
+                rowKey={"msg"}
+                rows={[{msg: "No LDIF files"}]}
+            />;
+        } else {
+            LDIFTable =
+                <DSTable
+                    noSearchBar
+                    getColumns={this.getColumns}
+                    rowKey={this.state.rowKey}
+                    rows={this.props.rows}
+                    toolBarPagination={[6, 12, 24, 48, 96]}
+                    toolBarPaginationPerPage={6}
+                />;
+        }
+        return (
+            <div>
+                {LDIFTable}
+            </div>
+        );
+    }
+}
+
+class LDIFManageTable extends React.Component {
+    constructor(props) {
+        super(props);
+
+        this.state = {
+            rowKey: "name",
+            columns: [
+                {
+                    property: "name",
+                    header: {
+                        label: "LDIF File",
+                        props: {
+                            index: 0,
+                            rowSpan: 1,
+                            colSpan: 1,
+                            sort: true
+                        },
+                        transforms: [],
+                        formatters: [],
+                        customFormatters: [sortableHeaderCellFormatter]
+                    },
+                    cell: {
+                        props: {
+                            index: 0
+                        },
+                        formatters: [tableCellFormatter]
+                    }
+                },
+                {
+                    property: "suffix",
+                    header: {
+                        label: "Suffix",
+                        props: {
+                            index: 1,
+                            rowSpan: 1,
+                            colSpan: 1,
+                            sort: true
+                        },
+                        transforms: [],
+                        formatters: [],
+                        customFormatters: [sortableHeaderCellFormatter]
+                    },
+                    cell: {
+                        props: {
+                            index: 1
+                        },
+                        formatters: [tableCellFormatter]
+                    }
+                },
+                {
+                    property: "date",
+                    header: {
+                        label: "Creation Date",
+                        props: {
+                            index: 2,
+                            rowSpan: 1,
+                            colSpan: 1,
+                            sort: true
+                        },
+                        transforms: [],
+                        formatters: [],
+                        customFormatters: [sortableHeaderCellFormatter]
+                    },
+                    cell: {
+                        props: {
+                            index: 2
+                        },
+                        formatters: [tableCellFormatter]
+                    }
+                },
+                {
+                    property: "size",
+                    header: {
+                        label: "Size",
+                        props: {
+                            index: 3,
+                            rowSpan: 1,
+                            colSpan: 1,
+                            sort: true
+                        },
+                        transforms: [],
+                        formatters: [],
+                        customFormatters: [sortableHeaderCellFormatter]
+                    },
+                    cell: {
+                        props: {
+                            index: 3
+                        },
+                        formatters: [tableCellFormatter]
+                    }
+                },
+                {
+                    property: "actions",
+                    header: {
+                        props: {
+                            index: 4,
+                            rowSpan: 1,
+                            colSpan: 1
+                        },
+                        formatters: [actionHeaderCellFormatter]
+                    },
+                    cell: {
+                        props: {
+                            index: 4
+                        },
+                        formatters: [
+                            (value, { rowData }) => {
+                                return [
+                                    <td key={rowData.name[0]}>
+                                        <DropdownButton id={rowData.name[0]}
+                                            bsStyle="primary" title="Actions">
+                                            <MenuItem eventKey="1" onClick={() => {
+                                                this.props.confirmImport(rowData);
+                                            }}
+                                            >
+                                                Import LDIF File
+                                            </MenuItem>
+
+                                            <MenuItem divider />
+                                            <MenuItem eventKey="3" onClick={() => {
+                                                this.props.confirmDelete(rowData);
+                                            }}
+                                            >
+                                                Delete LDIF File
+                                            </MenuItem>
+                                        </DropdownButton>
+                                    </td>
+                                ];
+                            }
+                        ]
+                    }
+                }
+            ],
+        };
+
+        this.getColumns = this.getColumns.bind(this);
+    } // Constructor
+
+    getColumns() {
+        return this.state.columns;
+    }
+
+    getSingleColumn () {
+        return [
+            {
+                property: "msg",
+                header: {
+                    label: "LDIF Files",
+                    props: {
+                        index: 0,
+                        rowSpan: 1,
+                        colSpan: 1,
+                        sort: true
+                    },
+                    transforms: [],
+                    formatters: [],
+                    customFormatters: [sortableHeaderCellFormatter]
+                },
+                cell: {
+                    props: {
+                        index: 0
+                    },
+                    formatters: [tableCellFormatter]
+                }
+            },
+        ];
+    }
+
+    render() {
+        let LDIFTable;
+        if (this.props.rows.length == 0) {
+            LDIFTable = <DSShortTable
+                getColumns={this.getSingleColumn}
+                rowKey={"msg"}
+                rows={[{msg: "No LDIF files"}]}
+            />;
+        } else {
+            LDIFTable =
+                <DSTable
+                    noSearchBar
+                    getColumns={this.getColumns}
+                    rowKey={this.state.rowKey}
+                    rows={this.props.rows}
+                    toolBarPagination={[6, 12, 24, 48, 96]}
+                    toolBarPaginationPerPage={6}
+                />;
+        }
+        return (
+            <div>
+                {LDIFTable}
+            </div>
+        );
+    }
+}
+
+class BackupTable extends React.Component {
+    constructor(props) {
+        super(props);
+
+        this.state = {
+            rowKey: "name",
+            columns: [
+                {
+                    property: "name",
+                    header: {
+                        label: "Backup",
+                        props: {
+                            index: 0,
+                            rowSpan: 1,
+                            colSpan: 1,
+                            sort: true
+                        },
+                        transforms: [],
+                        formatters: [],
+                        customFormatters: [sortableHeaderCellFormatter]
+                    },
+                    cell: {
+                        props: {
+                            index: 0
+                        },
+                        formatters: [tableCellFormatter]
+                    }
+                },
+                {
+                    property: "date",
+                    header: {
+                        label: "Creation Date",
+                        props: {
+                            index: 1,
+                            rowSpan: 1,
+                            colSpan: 1,
+                            sort: true
+                        },
+                        transforms: [],
+                        formatters: [],
+                        customFormatters: [sortableHeaderCellFormatter]
+                    },
+                    cell: {
+                        props: {
+                            index: 1
+                        },
+                        formatters: [tableCellFormatter]
+                    }
+                },
+                {
+                    property: "size",
+                    header: {
+                        label: "Size",
+                        props: {
+                            index: 2,
+                            rowSpan: 1,
+                            colSpan: 1,
+                            sort: true
+                        },
+                        transforms: [],
+                        formatters: [],
+                        customFormatters: [sortableHeaderCellFormatter]
+                    },
+                    cell: {
+                        props: {
+                            index: 2
+                        },
+                        formatters: [tableCellFormatter]
+                    }
+                },
+                {
+                    property: "actions",
+                    header: {
+                        props: {
+                            index: 3,
+                            rowSpan: 1,
+                            colSpan: 1
+                        },
+                        formatters: [actionHeaderCellFormatter]
+                    },
+                    cell: {
+                        props: {
+                            index: 3
+                        },
+                        formatters: [
+                            (value, { rowData }) => {
+                                return [
+                                    <td key={rowData.name[0]}>
+                                        <DropdownButton id={rowData.name[0]}
+                                            bsStyle="primary" title="Actions">
+                                            <MenuItem eventKey="1" onClick={() => {
+                                                this.props.confirmRestore(rowData);
+                                            }}
+                                            >
+                                                Restore Backup
+                                            </MenuItem>
+
+                                            <MenuItem divider />
+                                            <MenuItem eventKey="3" onClick={() => {
+                                                this.props.confirmDelete(rowData);
+                                            }}
+                                            >
+                                                Delete Backup
+                                            </MenuItem>
+                                        </DropdownButton>
+                                    </td>
+                                ];
+                            }
+                        ]
+                    }
+                }
+            ],
+        };
+
+        this.getColumns = this.getColumns.bind(this);
+    } // Constructor
+
+    getColumns() {
+        return this.state.columns;
+    }
+
+    getSingleColumn () {
+        return [
+            {
+                property: "msg",
+                header: {
+                    label: "Backup",
+                    props: {
+                        index: 0,
+                        rowSpan: 1,
+                        colSpan: 1,
+                        sort: true
+                    },
+                    transforms: [],
+                    formatters: [],
+                    customFormatters: [sortableHeaderCellFormatter]
+                },
+                cell: {
+                    props: {
+                        index: 0
+                    },
+                    formatters: [tableCellFormatter]
+                }
+            },
+        ];
+    }
+
+    render() {
+        let backupTable;
+        if (this.props.rows.length == 0) {
+            backupTable = <DSShortTable
+                getColumns={this.getSingleColumn}
+                rowKey={"msg"}
+                rows={[{msg: "No Backups"}]}
+            />;
+        } else {
+            backupTable =
+                <DSTable
+                    noSearchBar
+                    getColumns={this.getColumns}
+                    rowKey={this.state.rowKey}
+                    rows={this.props.rows}
+                    toolBarPagination={[6, 12, 24, 48, 96]}
+                    toolBarPaginationPerPage={6}
+                />;
+        }
+        return (
+            <div>
+                {backupTable}
+            </div>
+        );
+    }
+}
+
+// Property types and defaults
+
+BackupTable.propTypes = {
+    rows: PropTypes.array,
+    confirmRestore: PropTypes.func,
+    confirmDelete: PropTypes.func
+};
+
+BackupTable.defaultProps = {
+    rows: [],
+    confirmRestore: noop,
+    confirmDelete: noop
+};
+
+LDIFTable.propTypes = {
+    rows: PropTypes.array,
+    confirmImport: PropTypes.func,
+};
+
+LDIFTable.defaultProps = {
+    rows: [],
+    confirmImport: noop
+};
+
+LDIFManageTable.propTypes = {
+    rows: PropTypes.array,
+    confirmImport: PropTypes.func,
+    confirmDelete: PropTypes.func
+};
+
+LDIFManageTable.defaultProps = {
+    rows: [],
+    confirmImport: noop,
+    confirmDelete: noop
+};
+
+ReferralTable.propTypes = {
+    rows: PropTypes.array,
+    loadModalHandler: PropTypes.func
+};
+
+ReferralTable.defaultProps = {
+    rows: [],
+    loadModalHandler: noop
+};
+
+IndexTable.propTypes = {
+    editable: PropTypes.bool,
+    rows: PropTypes.array,
+    editIndex: PropTypes.func,
+    reindexIndex: PropTypes.func,
+    deleteIndex: PropTypes.func,
+};
+
+IndexTable.defaultProps = {
+    editable: false,
+    rows: [],
+    editIndex: noop,
+    reindexIndex: noop,
+    deleteIndex: noop,
+};
+
+EncryptedAttrTable.propTypes = {
+    loadModalHandler: PropTypes.func,
+    rows: PropTypes.array,
+};
+
+EncryptedAttrTable.defaultProps = {
+    loadModalHandler: noop,
+    rows: [],
+};
+
+export {
+    ReferralTable,
+    IndexTable,
+    EncryptedAttrTable,
+    LDIFTable,
+    LDIFManageTable,
+    BackupTable
+};
diff --git a/src/cockpit/389-console/src/lib/database/indexes.jsx b/src/cockpit/389-console/src/lib/database/indexes.jsx
new file mode 100644
index 0000000..34c246b
--- /dev/null
+++ b/src/cockpit/389-console/src/lib/database/indexes.jsx
@@ -0,0 +1,949 @@
+import cockpit from "cockpit";
+import React from "react";
+import { ConfirmPopup } from "../notifications.jsx";
+import { IndexTable } from "./databaseTables.jsx";
+import { ReindexModal } from "./databaseModal.jsx";
+import { log_cmd } from "../tools.jsx";
+import {
+    Nav,
+    NavItem,
+    TabContent,
+    TabPane,
+    Modal,
+    Row,
+    Checkbox,
+    Col,
+    Icon,
+    Button,
+    Form,
+    noop
+} from "patternfly-react";
+import PropTypes from "prop-types";
+import { Typeahead } from "react-bootstrap-typeahead";
+import "../../css/ds.css";
+
+export class SuffixIndexes extends React.Component {
+    constructor (props) {
+        super(props);
+        this.state = {
+            // indexes
+            showIndexModal: false,
+            showEditIndexModal: false,
+            showReindexModal: false,
+            reindexMsg: "",
+            editIndexName: "",
+            types: [],
+            attributes: [],
+            matchingRules: [],
+            mrs: [],
+            _mrs: [],
+            showConfirmReindex: false,
+            reindexAttrName: "",
+            showConfirmDeleteIndex: false,
+            deleteAttrName: "",
+            // Add indexes
+            addIndexName: [],
+            addIndexTypeEq: false,
+            addIndexTypePres: false,
+            addIndexTypeSub: false,
+            addIndexTypeApprox: false,
+            reindexOnAdd: false,
+            // Edit indexes
+            errObj: {},
+            _isMounted: true
+        };
+
+        this.loadIndexes = this.loadIndexes.bind(this);
+        this.showIndexModal = this.showIndexModal.bind(this);
+        this.closeIndexModal = this.closeIndexModal.bind(this);
+        this.handleChange = this.handleChange.bind(this);
+        this.handleTypeaheadChange = this.handleTypeaheadChange.bind(this);
+        this.saveIndex = this.saveIndex.bind(this);
+        this.saveEditIndex = this.saveEditIndex.bind(this);
+        this.reindexIndex = this.reindexIndex.bind(this);
+        this.deleteIndex = this.deleteIndex.bind(this);
+        this.showEditIndexModal = this.showEditIndexModal.bind(this);
+        this.closeEditIndexModal = this.closeEditIndexModal.bind(this);
+        this.showConfirmReindex = this.showConfirmReindex.bind(this);
+        this.closeConfirmReindex = this.closeConfirmReindex.bind(this);
+        this.showConfirmDeleteIndex = this.showConfirmDeleteIndex.bind(this);
+        this.closeConfirmDeleteIndex = this.closeConfirmDeleteIndex.bind(this);
+        this.closeReindexModal = this.closeReindexModal.bind(this);
+    }
+
+    componentWillMount () {
+        this.loadIndexes();
+    }
+
+    componentWillUnmount() {
+        this.state._isMounted = false;
+    }
+
+    loadIndexes () {
+        // Get all the attributes and matching rules now
+        const cmd = [
+            "dsconf", "-j", "ldapi://%2fvar%2frun%2fslapd-" + this.props.serverId + ".socket",
+            "schema", "matchingrules", "list"
+        ];
+        log_cmd("loadIndexes (suffix config)", "Get matching rules", cmd);
+        cockpit
+                .spawn(cmd, { superuser: true, err: "message" })
+                .done(content => {
+                    const mrContent = JSON.parse(content);
+                    let mrs = [];
+                    for (let i = 0; i < mrContent['items'].length; i++) {
+                        if (mrContent['items'][i].name != "") {
+                            mrs.push(mrContent['items'][i].name);
+                        }
+                    }
+
+                    const idx_cmd = [
+                        "dsconf", "-j", "ldapi://%2fvar%2frun%2fslapd-" + this.props.serverId + ".socket",
+                        "backend", "index", "list", "--just-names", this.props.suffix
+                    ];
+                    log_cmd("loadIndexes (suffix config)", "Get current index list", idx_cmd);
+                    cockpit
+                            .spawn(idx_cmd, { superuser: true, err: "message" })
+                            .done(content => {
+                                let idxContent = JSON.parse(content);
+                                let indexList = idxContent['items'];
+                                const attr_cmd = [
+                                    "dsconf", "-j", "ldapi://%2fvar%2frun%2fslapd-" + this.props.serverId + ".socket",
+                                    "schema", "attributetypes", "list"
+                                ];
+                                log_cmd("loadIndexes (suffix config)", "Get attrs", attr_cmd);
+                                cockpit
+                                        .spawn(attr_cmd, { superuser: true, err: "message" })
+                                        .done(content => {
+                                            const attrContent = JSON.parse(content);
+                                            let attrs = [];
+                                            for (let content of attrContent['items']) {
+                                                if (indexList.indexOf(content.name) == -1) {
+                                                    // Attribute is not a current index, add it to the list
+                                                    // of available attributes to index
+                                                    attrs.push(content.name);
+                                                }
+                                            }
+                                            if (this.state._isMounted) {
+                                                this.setState({
+                                                    matchingRules: mrs,
+                                                    attributes: attrs,
+                                                });
+                                            }
+                                        })
+                                        .fail(err => {
+                                            this.props.addNotification(
+                                                "error",
+                                                `Failed to get attributes - ${err}`
+                                            );
+                                        });
+                            });
+                })
+                .fail(err => {
+                    this.props.addNotification(
+                        "error",
+                        `Failed to get matching rules - ${err}`
+                    );
+                });
+    }
+
+    //
+    // Index Modal functions
+    //
+    showIndexModal() {
+        this.setState({
+            showIndexModal: true,
+            errObj: {},
+            mrs: [],
+            addIndexName: [],
+            addIndexTypeEq: "",
+            addIndexTypeSub: "",
+            addIndexTypePres:"",
+            addIndexTypeApprox: "",
+        });
+    }
+
+    closeIndexModal() {
+        this.setState({
+            showIndexModal: false
+        });
+    }
+
+    handleChange(e) {
+        const value = e.target.type === 'checkbox' ? e.target.checked : e.target.value;
+        let valueErr = false;
+        let errObj = this.state.errObj;
+        if (value == "") {
+            valueErr = true;
+        }
+        errObj[e.target.id] = valueErr;
+        this.setState({
+            [e.target.id]: value,
+            errObj: errObj
+        });
+    }
+
+    saveIndex() {
+        // Validate the form
+        if (!this.state.addIndexTypeEq && !this.state.addIndexTypePres &&
+            !this.state.addIndexTypeSub && !this.state.addIndexTypeApprox) {
+            this.props.addNotification(
+                "warning",
+                "You must select at least one 'Index Type'"
+            );
+            return;
+        }
+        if (this.state.addIndexName == "" || this.state.addIndexName.length == 0) {
+            this.props.addNotification(
+                "warning",
+                "You must select an attribute to index"
+            );
+            return;
+        }
+
+        let cmd = [
+            "dsconf", "-j", "ldapi://%2fvar%2frun%2fslapd-" + this.props.serverId + ".socket",
+            "backend", "index", "add", "--attr=" + this.state.addIndexName[0].id,
+            this.props.suffix,
+        ];
+
+        if (this.state.addIndexTypeEq) {
+            cmd.push('--index-type=eq');
+        }
+        if (this.state.addIndexTypePres) {
+            cmd.push('--index-type=pres');
+        }
+        if (this.state.addIndexTypeSub) {
+            cmd.push('--index-type=sub');
+        }
+        if (this.state.addIndexTypeApprox) {
+            cmd.push('--index-type=approx');
+        }
+        for (let i = 0; i < this.state.mrs.length; i++) {
+            cmd.push('--matching-rule=' + this.state.mrs[i].id);
+        }
+        if (this.state.reindexOnAdd) {
+            cmd.push('--reindex');
+        }
+
+        log_cmd("saveIndex", "Create new index", cmd);
+        cockpit
+                .spawn(cmd, { superuser: true, err: "message" })
+                .done(content => {
+                    // this.loadIndexes();
+                    this.props.reload(this.props.suffix);
+                    this.closeIndexModal();
+                    if (this.state.reindexOnAdd) {
+                        this.reindexAttr(this.state.addIndexName[0].id);
+                    }
+                    this.props.addNotification(
+                        "success",
+                        `Successfully created new index`
+                    );
+                })
+                .fail(err => {
+                    // this.loadIndexes();
+                    this.props.reload(this.props.suffix);
+                    this.closeIndexModal();
+                    this.props.addNotification(
+                        "error",
+                        `Error creating index - ${err}`
+                    );
+                });
+    }
+
+    showEditIndexModal(item) {
+        // Set the state types and matching Rules
+        let currentMRS = [];
+        if (item.matchingrules !== undefined &&
+            item.matchingrules.length > 0 &&
+            item.matchingrules[0].length > 0) {
+            let parts = item.matchingrules[0].split(",").map(item => item.trim());
+            for (let part of parts) {
+                currentMRS.push({
+                    id: part,
+                    label: part
+                });
+            }
+        }
+        this.setState({
+            editIndexName: item.name[0],
+            types: item.types,
+            mrs: currentMRS,
+            _mrs: currentMRS,
+            showEditIndexModal: true,
+            errObj: {},
+            reindexOnAdd: false,
+            editIndexTypeEq: item.types[0].includes("eq"),
+            editIndexTypeSub: item.types[0].includes("sub"),
+            editIndexTypePres: item.types[0].includes("pres"),
+            editIndexTypeApprox: item.types[0].includes("approx"),
+            _eq: item.types[0].includes("eq"),
+            _sub: item.types[0].includes("sub"),
+            _pres: item.types[0].includes("pres"),
+            _approx: item.types[0].includes("approx"),
+        });
+    }
+
+    closeEditIndexModal() {
+        this.setState({
+            showEditIndexModal: false
+        });
+    }
+
+    handleTypeaheadChange(values, item) {
+        if (item == "matchingRules") {
+            this.setState({
+                mrs: values
+            });
+        } else if (item == "indexName") {
+            this.setState({
+                addIndexName: values
+            });
+        }
+    }
+
+    reindexAttr(attr) {
+        const reindex_cmd = [
+            "dsconf", "-j", "ldapi://%2fvar%2frun%2fslapd-" + this.props.serverId + ".socket",
+            "backend", "index", "reindex", "--wait", "--attr=" + attr, this.props.suffix,
+        ];
+
+        // Open spinner modal
+        const msg = <p>Indexing attribute:  <b>{attr}</b> ...</p>;
+        this.setState({
+            showReindexModal: true,
+            reindexMsg: msg
+        });
+        log_cmd("reindexAttr", "index attribute", reindex_cmd);
+        cockpit
+                .spawn(reindex_cmd, { superuser: true, err: "message" })
+                .done(content => {
+                    this.props.addNotification(
+                        "success",
+                        "Attribute (" + attr + ") has successfully been reindexed"
+                    );
+                    this.setState({
+                        showReindexModal: false,
+                    });
+                })
+                .fail(err => {
+                    this.props.addNotification(
+                        "error",
+                        `Error indexing attribute ${attr} - ${err}`
+                    );
+                });
+    }
+
+    saveEditIndex() {
+        const origMRS = this.state._mrs;
+        const newMRS = this.state.mrs;
+        const cmd = [
+            "dsconf", "-j", "ldapi://%2fvar%2frun%2fslapd-" + this.props.serverId + ".socket",
+            "backend", "index", "set", "--attr=" + this.state.editIndexName,
+            this.props.suffix,
+        ];
+
+        // Make sure we have at least one index type
+        if (!this.state.editIndexTypeEq && !this.state.editIndexTypeSub &&
+            !this.state.editIndexTypePres && !this.state.editIndexTypeApprox) {
+            this.props.addNotification(
+                "warning",
+                "You must have at least one index type"
+            );
+            return;
+        }
+
+        // Check if we have to add mrs
+        for (let newMR of newMRS) {
+            let found = false;
+            for (let origMR of origMRS) {
+                if (origMR.id == newMR.id) {
+                    found = true;
+                    break;
+                }
+            }
+            if (!found) {
+                cmd.push('--add-mr=' + newMR.id);
+            }
+        }
+        // Check if we have to remove mrs
+        for (let origMR of origMRS) {
+            let found = false;
+            for (let newMR of newMRS) {
+                if (newMR.id == origMR.id) {
+                    console.log("Found mr no need to delete");
+                    found = true;
+                    break;
+                }
+            }
+            if (!found) {
+                cmd.push('--del-mr=' + origMR.id);
+            }
+        }
+
+        // Check if we have to add/delete index types
+        if (this.state.editIndexTypeEq && !this.state._eq) {
+            cmd.push('--add-type=eq');
+        } else if (!this.state.editIndexTypeEq && this.state._eq) {
+            cmd.push('--del-type=eq');
+        }
+        if (this.state.editIndexTypeSub && !this.state._sub) {
+            cmd.push('--add-type=sub');
+        } else if (!this.state.editIndexTypeSub && this.state._sub) {
+            cmd.push('--del-type=sub');
+        }
+        if (this.state.editIndexTypePres && !this.state._pres) {
+            cmd.push('--add-type=pres');
+        } else if (!this.state.editIndexTypePres && this.state._pres) {
+            cmd.push('--del-type=pres');
+        }
+        if (this.state.editIndexTypeApprox && !this.state._approx) {
+            cmd.push('--add-type=approx');
+        } else if (!this.state.editIndexTypeApprox && this.state._approx) {
+            cmd.push('--del-type=approx');
+        }
+
+        if (cmd.length > 8) {
+            // We have changes, do it
+            log_cmd("saveEditIndex", "Edit index", cmd);
+            cockpit
+                    .spawn(cmd, { superuser: true, err: "message" })
+                    .done(content => {
+                        this.props.reload(this.props.suffix);
+                        this.closeEditIndexModal();
+                        this.props.addNotification(
+                            "success",
+                            `Successfully edited index`
+                        );
+                        if (this.state.reindexOnAdd) {
+                            this.reindexAttr(this.state.editIndexName);
+                        }
+                    })
+                    .fail(err => {
+                        this.props.reload(this.props.suffix);
+                        this.closeEditIndexModal();
+                        this.props.addNotification(
+                            "error",
+                            `Error editing index - ${err}`
+                        );
+                    });
+        }
+    }
+
+    showConfirmReindex(item) {
+        this.setState({
+            reindexAttrName: item.name,
+            showConfirmReindex: true
+        });
+    }
+
+    closeConfirmReindex(item) {
+        this.setState({
+            reindexAttrName: "",
+            showConfirmReindex: false
+        });
+    }
+
+    showConfirmDeleteIndex(item) {
+        this.setState({
+            deleteAttrName: item.name,
+            showConfirmDeleteIndex: true
+        });
+    }
+
+    closeConfirmDeleteIndex(item) {
+        this.setState({
+            deleteAttrName: "",
+            showConfirmDeleteIndex: false
+        });
+    }
+
+    reindexIndex(attr) {
+        this.reindexAttr(attr);
+    }
+
+    closeReindexModal() {
+        this.setState({
+            showReindexModal: false
+        });
+    }
+
+    deleteIndex(idxName) {
+        const cmd = [
+            "dsconf", "-j", "ldapi://%2fvar%2frun%2fslapd-" + this.props.serverId + ".socket",
+            "backend", "index", "delete", "--attr=" + idxName,
+            this.props.suffix,
+        ];
+
+        log_cmd("deleteIndex", "deleteEdit index", cmd);
+        cockpit
+                .spawn(cmd, { superuser: true, err: "message" })
+                .done(content => {
+                    this.props.reload(this.props.suffix);
+                    this.props.addNotification(
+                        "success",
+                        "Successfully deleted index: " + idxName
+                    );
+                })
+                .fail(err => {
+                    this.props.reload(this.props.suffix);
+                    this.props.addNotification(
+                        "error",
+                        `Error deleting index - ${err}`
+                    );
+                });
+    }
+
+    render() {
+        const reindex_attr = <b>{this.state.reindexAttrName}</b>;
+        const delete_attr = <b>{this.state.deleteAttrName}</b>;
+
+        return (
+            <div>
+                <Nav bsClass="nav nav-tabs nav-tabs-pf">
+                    <NavItem className="ds-nav-med" eventKey={1}>
+                        <div dangerouslySetInnerHTML={{__html: 'Database Indexes'}} />
+                    </NavItem>
+                    <NavItem className="ds-nav-med" eventKey={2}>
+                        <div dangerouslySetInnerHTML={{__html: 'System Indexes'}} />
+                    </NavItem>
+                </Nav>
+                <TabContent>
+                    <TabPane eventKey={1}>
+                        <div className="ds-indent">
+                            <IndexTable
+                                editable
+                                rows={this.props.indexRows}
+                                editIndex={this.showEditIndexModal}
+                                reindexIndex={this.showConfirmReindex}
+                                deleteIndex={this.showConfirmDeleteIndex}
+                            />
+                            <button className="btn btn-primary ds-margin-top" type="button" onClick={this.showIndexModal} >Add Index</button>
+                        </div>
+                    </TabPane>
+                    <TabPane eventKey={2}>
+                        <div className="ds-indent">
+                            <IndexTable
+                                rows={this.props.systemIndexRows}
+                            />
+                        </div>
+                    </TabPane>
+                </TabContent>
+
+                <AddIndexModal
+                    showModal={this.state.showIndexModal}
+                    closeHandler={this.closeIndexModal}
+                    handleChange={this.handleChange}
+                    saveHandler={this.saveIndex}
+                    matchingRules={this.state.matchingRules}
+                    attributes={this.state.attributes}
+                    mrs={this.state.mrs}
+                    attributeName={this.state.addIndexName}
+                    handleTypeaheadChange={this.handleTypeaheadChange}
+                />
+                <EditIndexModal
+                    showModal={this.state.showEditIndexModal}
+                    closeHandler={this.closeEditIndexModal}
+                    handleChange={this.handleChange}
+                    saveHandler={this.saveEditIndex}
+                    types={this.state.types}
+                    mrs={this.state.mrs}
+                    matchingRules={this.state.matchingRules}
+                    indexName={this.state.editIndexName}
+                    handleTypeaheadChange={this.handleTypeaheadChange}
+                />
+                <ConfirmPopup
+                    showModal={this.state.showConfirmReindex}
+                    closeHandler={this.closeConfirmReindex}
+                    actionFunc={this.reindexIndex}
+                    actionParam={this.state.reindexAttrName}
+                    msg="Are you sure you want to reindex this attribute?"
+                    msgContent={reindex_attr}
+                />
+                <ConfirmPopup
+                    showModal={this.state.showConfirmDeleteIndex}
+                    closeHandler={this.closeConfirmDeleteIndex}
+                    actionFunc={this.deleteIndex}
+                    actionParam={this.state.deleteAttrName}
+                    msg="Are you sure you want to delete this attribute index?"
+                    msgContent={delete_attr}
+                />
+                <ReindexModal
+                    showModal={this.state.showReindexModal}
+                    closeHandler={this.closeReindexModal}
+                    msg={this.state.reindexMsg}
+                />
+            </div>
+        );
+    }
+}
+
+class AddIndexModal extends React.Component {
+    render() {
+        const {
+            showModal,
+            closeHandler,
+            handleChange,
+            saveHandler,
+            matchingRules,
+            attributes,
+            mrs,
+            handleTypeaheadChange,
+            attributeName
+        } = this.props;
+
+        let availMR = [];
+        for (let mr of matchingRules) {
+            availMR.push({
+                id: mr,
+                label: mr
+            });
+        }
+        let availAttrs = [];
+        for (let attr of attributes) {
+            availAttrs.push({
+                id: attr,
+                label: attr
+            });
+        }
+
+        return (
+            <Modal show={showModal} onHide={closeHandler}>
+                <div className="ds-no-horizontal-scrollbar">
+                    <Modal.Header>
+                        <button
+                            className="close"
+                            onClick={closeHandler}
+                            aria-hidden="true"
+                            aria-label="Close"
+                        >
+                            <Icon type="pf" name="close" />
+                        </button>
+                        <Modal.Title>
+                            Add Database Index
+                        </Modal.Title>
+                    </Modal.Header>
+                    <Modal.Body>
+                        <Form horizontal autoComplete="off">
+                            <label className="ds-config-label" htmlFor="ds-index-form-list" title="Select an attribute to index">Select An Attribute</label>
+                            <Typeahead
+                                id="indexAttributeName"
+                                onChange={values => {
+                                    handleTypeaheadChange(values, "indexName");
+                                }}
+                                selected={attributeName}
+                                maxResults={1000}
+                                options={availAttrs}
+                                placeholder="Type a attribute name to index..."
+                            />
+                            <p className="ds-margin-top"><b>Index Types</b></p>
+                            <div className="ds-indent">
+                                <Row>
+                                    <Col sm={5}>
+                                        <Checkbox id="addIndexTypeEq" onChange={handleChange}> Equailty Indexing</Checkbox>
+                                    </Col>
+                                </Row>
+                                <Row>
+                                    <Col sm={5}>
+                                        <Checkbox id="addIndexTypePres" onChange={handleChange}> Presence Indexing</Checkbox>
+                                    </Col>
+                                </Row>
+                                <Row>
+                                    <Col sm={5}>
+                                        <Checkbox id="addIndexTypeSub" onChange={handleChange}> Substring Indexing</Checkbox>
+                                    </Col>
+                                </Row>
+                                <Row>
+                                    <Col sm={5}>
+                                        <Checkbox id="addIndexTypeApprox" onChange={handleChange}> Approximate Indexing</Checkbox>
+                                    </Col>
+                                </Row>
+                            </div>
+                            <p />
+                            <Row className="ds-margin-top-lg">
+                                <Col sm={12} title="List of matching rules separated by a 'space'">
+                                    <p><b>Matching Rules</b></p>
+                                    <div className="ds-indent">
+                                        <Typeahead
+                                            multiple
+                                            id="matchingRules"
+                                            onChange={values => {
+                                                handleTypeaheadChange(values, "matchingRules");
+                                            }}
+                                            maxResults={1000}
+                                            selected={mrs}
+                                            options={availMR}
+                                            placeholder="Type a matching rule name..."
+                                        />
+                                    </div>
+                                </Col>
+                            </Row>
+                            <hr />
+                            <Row>
+                                <Col sm={12}>
+                                    <Checkbox className="ds-float-right" id="reindexOnAdd" onChange={handleChange}>
+                                        Index attribute after creation
+                                    </Checkbox>
+                                </Col>
+                            </Row>
+                        </Form>
+                    </Modal.Body>
+                    <Modal.Footer>
+                        <Button
+                            bsStyle="default"
+                            className="btn-cancel"
+                            onClick={closeHandler}
+                        >
+                            Cancel
+                        </Button>
+                        <Button
+                            bsStyle="primary"
+                            onClick={saveHandler}
+                        >
+                            Create Index
+                        </Button>
+                    </Modal.Footer>
+                </div>
+            </Modal>
+        );
+    }
+}
+
+class EditIndexModal extends React.Component {
+    constructor(props) {
+        super(props);
+        this.state = {
+            mrs: [],
+        };
+    }
+
+    render() {
+        const {
+            showModal,
+            closeHandler,
+            handleChange,
+            saveHandler,
+            indexName,
+            types,
+            mrs,
+            matchingRules,
+            handleTypeaheadChange,
+        } = this.props;
+
+        let attrTypes = "";
+        if (types != "" && types.length > 0) {
+            attrTypes = types[0].split(",").map(item => item.trim());
+        }
+
+        const currentMrs = mrs;
+        let availMR = [];
+        for (let mr of matchingRules) {
+            availMR.push({
+                id: mr,
+                label: mr
+            });
+        }
+
+        // Default settings
+        let eq = <div>
+            <Checkbox id="editIndexTypeEq" onChange={handleChange}> Equailty Indexing</Checkbox>
+        </div>;
+        let pres = <div>
+            <Checkbox id="editIndexTypePres" onChange={handleChange}> Presence Indexing</Checkbox>
+        </div>;
+        let sub = <div>
+            <Checkbox id="editIndexTypeSub" onChange={handleChange}> Substring Indexing</Checkbox>
+        </div>;
+        let approx = <div>
+            <Checkbox id="editIndexTypeApprox" onChange={handleChange}> Approximate Indexing</Checkbox>
+        </div>;
+
+        if (attrTypes.includes('eq')) {
+            eq = <div>
+                <Checkbox id="editIndexTypeEq" onChange={handleChange} defaultChecked>
+                    Equality Indexing
+                </Checkbox>
+            </div>;
+        }
+        if (attrTypes.includes('pres')) {
+            pres = <div>
+                <Checkbox id="editIndexTypePres" onChange={handleChange} defaultChecked>
+                    Presence Indexing
+                </Checkbox>
+            </div>;
+        }
+        if (attrTypes.includes('sub')) {
+            sub = <div>
+                <Checkbox id="editIndexTypeSub" onChange={handleChange} defaultChecked>
+                    Substring Indexing
+                </Checkbox>
+            </div>;
+        }
+        if (attrTypes.includes('approx')) {
+            approx = <div>
+                <Checkbox id="editIndexTypeApprox" onChange={handleChange} defaultChecked>
+                    Approximate Indexing
+                </Checkbox>
+            </div>;
+        }
+
+        return (
+            <Modal show={showModal} onHide={closeHandler}>
+                <div>
+                    <Modal.Header>
+                        <button
+                            className="close"
+                            onClick={closeHandler}
+                            aria-hidden="true"
+                            aria-label="Close"
+                        >
+                            <Icon type="pf" name="close" />
+                        </button>
+                        <Modal.Title>
+                            Edit Database Index ({indexName})
+                        </Modal.Title>
+                    </Modal.Header>
+                    <Modal.Body>
+                        <Form horizontal autoComplete="off">
+                            <p><Icon type="pf" style={{'marginRight': '15px'}} name="edit" /><font size="4"><b>{indexName}</b></font></p>
+                            <hr />
+                            <p><b>Index Types</b></p>
+                            <div className="ds-indent">
+                                <Row>
+                                    <Col sm={9}>
+                                        {eq}
+                                    </Col>
+                                </Row>
+                                <Row>
+                                    <Col sm={9}>
+                                        {pres}
+                                    </Col>
+                                </Row>
+                                <Row>
+                                    <Col sm={9}>
+                                        {sub}
+                                    </Col>
+                                </Row>
+                                <Row>
+                                    <Col sm={9}>
+                                        {approx}
+                                    </Col>
+                                </Row>
+                            </div>
+                            <p />
+                            <Row className="ds-margin-top-lg">
+                                <Col sm={12}>
+                                    <p><b>Matching Rules</b></p>
+                                    <div className="ds-indent">
+                                        <Typeahead
+                                            multiple
+                                            id="matchingRulesEdit"
+                                            onChange={values => {
+                                                handleTypeaheadChange(values, "matchingRules");
+                                            }}
+                                            selected={currentMrs}
+                                            options={availMR}
+                                            placeholder="Type a matching rule name..."
+                                        />
+                                    </div>
+                                </Col>
+                            </Row>
+                            <hr />
+                            <Row>
+                                <Col sm={12}>
+                                    <Checkbox className="ds-float-right" id="reindexOnAdd" onChange={handleChange}>
+                                        Reindex Attribute After Saving
+                                    </Checkbox>
+                                </Col>
+                            </Row>
+                        </Form>
+                    </Modal.Body>
+                    <Modal.Footer>
+                        <Button
+                            bsStyle="default"
+                            className="btn-cancel"
+                            onClick={closeHandler}
+                        >
+                            Cancel
+                        </Button>
+                        <Button
+                            bsStyle="primary"
+                            onClick={saveHandler}
+                        >
+                            Save Index
+                        </Button>
+                    </Modal.Footer>
+                </div>
+            </Modal>
+        );
+    }
+}
+
+// Property types and defaults
+
+SuffixIndexes.propTypes = {
+    systemIndexRows: PropTypes.array,
+    indexRows: PropTypes.array,
+    serverId: PropTypes.string,
+    suffix: PropTypes.string,
+    addNotification: PropTypes.func,
+    reload: PropTypes.func,
+};
+
+SuffixIndexes.defaultProps = {
+    systemIndexRows: [],
+    indexRows: [],
+    serverId: "",
+    suffix: "",
+    addNotification: noop,
+    reload: noop,
+};
+
+AddIndexModal.propTypes = {
+    showModal: PropTypes.bool,
+    closeHandler: PropTypes.func,
+    handleChange: PropTypes.func,
+    saveHandler: PropTypes.func,
+    matchingRules: PropTypes.array,
+    attributes: PropTypes.array,
+    mrs: PropTypes.array,
+    attributeName: PropTypes.array,
+    handleTypeaheadChange: PropTypes.func,
+};
+
+AddIndexModal.defaultProps = {
+    showModal: false,
+    closeHandler: noop,
+    handleChange: noop,
+    saveHandler: noop,
+    matchingRules: [],
+    attributes: [],
+    mrs: [],
+    attributeName: [],
+    handleTypeaheadChange: noop,
+};
+
+EditIndexModal.propTypes = {
+    showModal: PropTypes.bool,
+    closeHandler: PropTypes.func,
+    handleChange: PropTypes.func,
+    saveHandler: PropTypes.func,
+    matchingRules: PropTypes.array,
+    types: PropTypes.array,
+    mrs: PropTypes.array,
+    indexName: PropTypes.string,
+    handleTypeaheadChange: PropTypes.func,
+};
+
+EditIndexModal.defaultProps = {
+    showModal: false,
+    closeHandler: noop,
+    handleChange: noop,
+    saveHandler: noop,
+    matchingRules: [],
+    types: [],
+    mrs: [],
+    indexName: "",
+    handleTypeaheadChange: noop,
+};
diff --git a/src/cockpit/389-console/src/lib/database/referrals.jsx b/src/cockpit/389-console/src/lib/database/referrals.jsx
new file mode 100644
index 0000000..d86c8c4
--- /dev/null
+++ b/src/cockpit/389-console/src/lib/database/referrals.jsx
@@ -0,0 +1,414 @@
+import cockpit from "cockpit";
+import React from "react";
+import { ConfirmPopup } from "../notifications.jsx";
+import { ReferralTable } from "./databaseTables.jsx";
+import {
+    Modal,
+    Row,
+    ControlLabel,
+    Col,
+    Icon,
+    Button,
+    Form,
+    noop
+} from "patternfly-react";
+import { log_cmd } from "../tools.jsx";
+import PropTypes from "prop-types";
+import "../../css/ds.css";
+
+export class SuffixReferrals extends React.Component {
+    constructor (props) {
+        super(props);
+        this.state = {
+            showConfirmRefDelete: false,
+            showRefModal: false,
+            removeRef: "",
+            refProtocol: "ldap://",
+            refHost: "",
+            refPort: "",
+            refSuffix: "",
+            refFilter: "",
+            refScope: "",
+            refAttrs: "",
+            refValue: "",
+            errObj: {},
+        };
+
+        // Delete referral and confirmation
+        this.showConfirmRefDelete = this.showConfirmRefDelete.bind(this);
+        this.closeConfirmRefDelete = this.closeConfirmRefDelete.bind(this);
+        this.deleteRef = this.deleteRef.bind(this);
+        this.saveRef = this.saveRef.bind(this);
+        // Referral modal
+        this.showRefModal = this.showRefModal.bind(this);
+        this.closeRefModal = this.closeRefModal.bind(this);
+        this.handleRefChange = this.handleRefChange.bind(this);
+        this.buildRef = this.buildRef.bind(this);
+    }
+
+    showConfirmRefDelete(item) {
+        this.setState({
+            removeRef: item.name,
+            showConfirmRefDelete: true
+        });
+    }
+
+    showRefModal() {
+        this.setState({
+            showRefModal: true,
+            errObj: {},
+            refValue: ""
+        });
+    }
+
+    closeConfirmRefDelete() {
+        this.setState({
+            showConfirmRefDelete: false
+        });
+    }
+
+    closeRefModal() {
+        this.setState({
+            showRefModal: false
+        });
+    }
+
+    deleteRef() {
+        // take state.removeRef and remove it from ldap
+        const cmd = [
+            "dsconf", "-j", "ldapi://%2fvar%2frun%2fslapd-" + this.props.serverId + ".socket",
+            "backend", "suffix", "set", "--del-referral=" + this.state.removeRef, this.props.suffix
+        ];
+        log_cmd("deleteRef", "Delete suffix referral", cmd);
+        cockpit
+                .spawn(cmd, { superuser: true, err: "message" })
+                .done(content => {
+                    this.props.reload(this.props.suffix);
+                    this.props.addNotification(
+                        "success",
+                        `Referral successfully deleted`
+                    );
+                })
+                .fail(err => {
+                    this.props.reload(this.props.suffix);
+                    this.props.addNotification(
+                        "error",
+                        `Failure deleting referral - ${err}`
+                    );
+                });
+    }
+
+    // Create referral
+    saveRef() {
+        // validate
+        let missingArgs = {
+            refHost: false,
+            refPort: false
+        };
+        let errors = false;
+        if (this.state.refHost == "") {
+            this.props.addNotification(
+                "warning",
+                `Missing hostname for LDAP URL`
+            );
+            missingArgs.refHost = true;
+            errors = true;
+        }
+        if (this.state.refPort == "") {
+            this.props.addNotification(
+                "warning",
+                `Missing port for LDAP URL`
+            );
+            missingArgs.refPort = true;
+            errors = true;
+        }
+        if (errors) {
+            this.setState({
+                errObj: missingArgs
+            });
+            return;
+        }
+
+        // Add referral
+        const cmd = [
+            "dsconf", "-j", "ldapi://%2fvar%2frun%2fslapd-" + this.props.serverId + ".socket",
+            "backend", "suffix", "set", "--add-referral=" + this.state.refValue, this.props.suffix
+        ];
+        log_cmd("saveRef", "Add referral", cmd);
+        cockpit
+                .spawn(cmd, { superuser: true, err: "message" })
+                .done(content => {
+                    this.props.reload(this.props.suffix);
+                    this.closeRefModal();
+                    this.props.addNotification(
+                        "success",
+                        `Referral successfully created`
+                    );
+                })
+                .fail(err => {
+                    this.props.reload(this.props.suffix);
+                    this.closeRefModal();
+                    this.props.addNotification(
+                        "error",
+                        `Failure creating referral - ${err}`
+                    );
+                });
+    }
+
+    buildRef() {
+        let previewRef = this.state.refProtocol + this.state.refHost;
+        let ref_port = this.state.refPort;
+        let ref_suffix = this.state.refSuffix;
+        let ref_attrs = this.state.refAttrs;
+        let ref_filter = this.state.refFilter;
+        let ref_scope = this.state.refScope;
+
+        if (ref_port != "") {
+            previewRef += ":" + ref_port;
+        }
+        if (ref_suffix != "" || ref_attrs != "" || ref_filter != "" || ref_scope != "") {
+            previewRef += "/" + encodeURIComponent(ref_suffix);
+            if (ref_attrs != "") {
+                previewRef += "?" + encodeURIComponent(ref_attrs);
+            } else if (ref_filter != "" || ref_scope != "") {
+                previewRef += "?";
+            }
+            if (ref_scope != "") {
+                previewRef += "?" + encodeURIComponent(ref_scope);
+            } else if (ref_filter != "") {
+                previewRef += "?";
+            }
+            if (ref_filter != "") {
+                previewRef += "?" + encodeURIComponent(ref_filter);
+            }
+        }
+
+        // Update referral value
+        this.setState({
+            refValue: previewRef
+        });
+    }
+
+    handleRefChange(e) {
+        const value = e.target.value;
+        const key = e.target.id;
+        let errObj = this.state.errObj;
+        let valueErr = false;
+
+        if (value == "") {
+            if (key == "refHost" || key == "refPort") {
+                valueErr = true;
+            }
+        }
+        errObj[e.target.id] = valueErr;
+        this.setState({
+            [e.target.id]: value,
+            errObj: errObj
+        }, this.buildRef);
+    }
+
+    render() {
+        let refs = [];
+        for (let row of this.props.rows) {
+            refs.push({name: row});
+        }
+
+        return (
+            <div className="ds-sub-header">
+                <ReferralTable
+                    rows={refs}
+                    loadModalHandler={this.showConfirmRefDelete}
+                />
+                <button className="btn btn-primary ds-margin-top" onClick={this.showRefModal} type="button">Create Referral</button>
+                <ConfirmPopup
+                    showModal={this.state.showConfirmRefDelete}
+                    closeHandler={this.closeConfirmRefDelete}
+                    actionFunc={this.deleteRef}
+                    actionParam={this.state.removeRef}
+                    msg="Are you sure you want to delete this referral?"
+                    msgContent={this.state.removeRef}
+                />
+                <AddReferralModal
+                    showModal={this.state.showRefModal}
+                    closeHandler={this.closeRefModal}
+                    handleChange={this.handleRefChange}
+                    saveHandler={this.saveRef}
+                    previewValue={this.state.refValue}
+                    error={this.state.errObj}
+                />
+            </div>
+        );
+    }
+}
+
+class AddReferralModal extends React.Component {
+    render() {
+        let {
+            showModal,
+            closeHandler,
+            handleChange,
+            saveHandler,
+            previewValue,
+            error
+        } = this.props;
+
+        if (previewValue == "") {
+            previewValue = "ldap://";
+        }
+
+        return (
+            <Modal show={showModal} onHide={closeHandler}>
+                <div className="ds-no-horizontal-scrollbar">
+                    <Modal.Header>
+                        <button
+                            className="close"
+                            onClick={closeHandler}
+                            aria-hidden="true"
+                            aria-label="Close"
+                        >
+                            <Icon type="pf" name="close" />
+                        </button>
+                        <Modal.Title>
+                            Add Database Referral
+                        </Modal.Title>
+                    </Modal.Header>
+                    <Modal.Body>
+                        <Form horizontal autoComplete="off">
+                            <Row>
+                                <Col sm={3}>
+                                    <ControlLabel>Protocol</ControlLabel>
+                                </Col>
+                                <Col sm={9}>
+                                    <select
+                                        defaultValue="ldap://" onChange={this.props.handleChange} className="btn btn-default dropdown" id="refProtocol">
+                                        <option>ldap://</option>
+                                        <option>ldaps://</option>
+                                    </select>
+                                </Col>
+                            </Row>
+                            <p />
+                            <Row>
+                                <Col sm={3}>
+                                    <ControlLabel>Host Name</ControlLabel>
+                                </Col>
+                                <Col sm={9}>
+                                    <input className={error.refHost ? "ds-input-auto-bad" : "ds-input-auto"} type="text" onChange={handleChange} id="refHost" />
+                                </Col>
+                            </Row>
+                            <p />
+                            <Row>
+                                <Col sm={3}>
+                                    <ControlLabel>Port Number</ControlLabel>
+                                </Col>
+                                <Col sm={9}>
+                                    <input className={error.refPort ? "ds-input-auto-bad" : "ds-input-auto"} type="text" onChange={handleChange} id="refPort" />
+                                </Col>
+                            </Row>
+                            <p />
+                            <Row>
+                                <Col sm={3}>
+                                    <ControlLabel>Suffix</ControlLabel>
+                                </Col>
+                                <Col sm={9}>
+                                    <input className="ds-input-auto" onChange={handleChange} type="text" id="refSuffix" />
+                                </Col>
+                            </Row>
+                            <p />
+                            <Row title="Comma separated list of attributes to return">
+                                <Col sm={3}>
+                                    <ControlLabel>Attributes</ControlLabel>
+                                </Col>
+                                <Col sm={9}>
+                                    <input className="ds-input-auto" onChange={handleChange} type="text" id="refAttrs" />
+                                </Col>
+                            </Row>
+                            <p />
+                            <Row>
+                                <Col sm={3}>
+                                    <ControlLabel>Filter</ControlLabel>
+                                </Col>
+                                <Col sm={9}>
+                                    <input onChange={handleChange} className="ds-input-auto" type="text" id="refFilter" />
+                                </Col>
+                            </Row>
+                            <p />
+                            <Row>
+                                <Col sm={3}>
+                                    <ControlLabel>Scope</ControlLabel>
+                                </Col>
+                                <Col sm={9}>
+                                    <select className="btn btn-default dropdown" onChange={handleChange} defaultValue="" name="refScope">
+                                        <option />
+                                        <option>sub</option>
+                                        <option>one</option>
+                                        <option>base</option>
+                                    </select>
+                                </Col>
+                            </Row>
+                            <hr />
+                            <Row>
+                                <Col sm={3}>
+                                    <label className="ds-label-sm">Computed Referral</label>
+                                </Col>
+                                <Col sm={9}>
+                                    <input className="ds-input-auto" value={previewValue} readOnly />
+                                </Col>
+                            </Row>
+                        </Form>
+                    </Modal.Body>
+                    <Modal.Footer>
+                        <Button
+                            bsStyle="default"
+                            className="btn-cancel"
+                            onClick={closeHandler}
+                        >
+                            Cancel
+                        </Button>
+                        <Button
+                            bsStyle="primary"
+                            onClick={saveHandler}
+                        >
+                            Create Referral
+                        </Button>
+                    </Modal.Footer>
+                </div>
+            </Modal>
+        );
+    }
+}
+
+// Property types and defaults
+
+SuffixReferrals.propTypes = {
+    rows: PropTypes.array,
+    suffix: PropTypes.string,
+    reload: PropTypes.func,
+    addNotification: PropTypes.func,
+    serverId: PropTypes.string,
+};
+
+SuffixReferrals.defaultProps = {
+    rows: [],
+    suffix: "",
+    reload: noop,
+    addNotification: noop,
+    serverId: "",
+};
+
+AddReferralModal.propTypes = {
+    showModal: PropTypes.bool,
+    closeHandler: PropTypes.func,
+    handleChange: PropTypes.func,
+    saveHandler: PropTypes.func,
+    previewValue: PropTypes.string,
+    error: PropTypes.object,
+};
+
+AddReferralModal.defaultProps = {
+    showModal: noop,
+    closeHandler: noop,
+    handleChange: noop,
+    saveHandler: noop,
+    previewValue: "",
+    error: {},
+};
diff --git a/src/cockpit/389-console/src/lib/database/suffix.jsx b/src/cockpit/389-console/src/lib/database/suffix.jsx
new file mode 100644
index 0000000..aa3b99c
--- /dev/null
+++ b/src/cockpit/389-console/src/lib/database/suffix.jsx
@@ -0,0 +1,906 @@
+import cockpit from "cockpit";
+import React from "react";
+import { ConfirmPopup } from "../notifications.jsx";
+import { AttrEncryption } from "./attrEncryption.jsx";
+import { SuffixConfig } from "./suffixConfig.jsx";
+import { SuffixReferrals } from "./referrals.jsx";
+import { SuffixIndexes } from "./indexes.jsx";
+import { VLVIndexes } from "./vlvIndexes.jsx";
+import { log_cmd } from "../tools.jsx";
+import {
+    ImportModal,
+    ExportModal,
+    ReindexModal,
+    CreateSubSuffixModal,
+    CreateLinkModal,
+} from "./databaseModal.jsx";
+import {
+    DropdownButton,
+    MenuItem,
+    Nav,
+    NavItem,
+    Row,
+    Col,
+    ControlLabel,
+    Icon,
+    TabContent,
+    TabPane,
+    TabContainer,
+    noop
+} from "patternfly-react";
+import PropTypes from "prop-types";
+import "../../css/ds.css";
+
+export class Suffix extends React.Component {
+    constructor (props) {
+        super(props);
+        this.state = {
+            loading: false,
+            activeKey: 1,
+            notifications: [],
+            errObj: {},
+            refRows: this.props.data.refRows,
+            encAttrsRows: this.props.data.encAttrsRows,
+            vlvItems: this.props.data.vlvItems,
+            autoTuning: this.props.data.autoTuning,
+            // Suffix configuration
+            cachememsize: this.props.data.cachememsize,
+            cachesize: this.props.data.cachesize,
+            dncachememsize: this.props.data.dncachememsize,
+            readOnly: this.props.data.readOnly,
+            requireIndex: this.props.data.requireIndex,
+            _cachememsize: this.props.data.cachememsize,
+            _cachesize: this.props.data.cachesize,
+            _dncachememsize: this.props.data.dncachememsize,
+            _readOnly: this.props.data.readOnly,
+            _requireIndex: this.props.data.requireIndex,
+
+            // Import/Export modals
+            showImportModal: false,
+            showExportModal: false,
+            ldifLocation: "",
+            attrEncryption: false,
+            exportSpinner: false,
+            importSpinner: false,
+            showConfirmLDIFImport: false,
+            deleleLDIFName: "",
+            // Reindex all
+            showReindexConfirm: false,
+            // Create Sub Suffix
+            showSubSuffixModal: false,
+            subSuffixValue: "",
+            subSuffixBeName: "",
+            // Create Link
+            showLinkModal: false,
+            createLinkSuffix: "",
+            createLinkName: "",
+            createNsfarmserverurl: "",
+            createNsmultiplexorbinddn: "",
+            createNsmultiplexorcredentials: "",
+            createNsmultiplexorcredentialsConfirm: "",
+            createUseStartTLS: false,
+            createNsbindmechanism: "SIMPLE",
+            linkPwdMatch: false,
+            // Delete
+            showDeleteConfirm: false,
+        };
+
+        // General bindings
+        this.handleNavSelect = this.handleNavSelect.bind(this);
+        // Import modal
+        this.showImportModal = this.showImportModal.bind(this);
+        this.closeImportModal = this.closeImportModal.bind(this);
+        this.handleChange = this.handleChange.bind(this);
+        this.doImport = this.doImport.bind(this);
+        this.importLDIF = this.importLDIF.bind(this);
+        this.showConfirmLDIFImport = this.showConfirmLDIFImport.bind(this);
+        this.closeConfirmLDIFImport = this.closeConfirmLDIFImport.bind(this);
+        // Export modal
+        this.showExportModal = this.showExportModal.bind(this);
+        this.closeExportModal = this.closeExportModal.bind(this);
+        this.doExport = this.doExport.bind(this);
+        // Reindex Suffix Modal
+        this.showReindexConfirm = this.showReindexConfirm.bind(this);
+        this.closeReindexConfirm = this.closeReindexConfirm.bind(this);
+        this.doReindex = this.doReindex.bind(this);
+        // Create sub suffix modal
+        this.showSubSuffixModal = this.showSubSuffixModal.bind(this);
+        this.closeSubSuffixModal = this.closeSubSuffixModal.bind(this);
+        this.createSubSuffix = this.createSubSuffix.bind(this);
+        // Create link modal
+        this.showLinkModal = this.showLinkModal.bind(this);
+        this.closeLinkModal = this.closeLinkModal.bind(this);
+        this.createLink = this.createLink.bind(this);
+        this.handleLinkChange = this.handleLinkChange.bind(this);
+        // Suffix config
+        this.saveSuffixConfig = this.saveSuffixConfig.bind(this);
+        // Attr Encrypt Modal
+        this.showDeleteConfirm = this.showDeleteConfirm.bind(this);
+        this.closeDeleteConfirm = this.closeDeleteConfirm.bind(this);
+        this.doDelete = this.doDelete.bind(this);
+    }
+
+    handleNavSelect(key) {
+        this.setState({ activeKey: key });
+    }
+
+    //
+    // Import Modal
+    //
+    showImportModal() {
+        this.setState({
+            ldifLocation: "",
+            attrEncryption: false,
+            showImportModal: true,
+            importSpinner: false,
+            errObj: {},
+        });
+    }
+
+    closeImportModal() {
+        this.setState({
+            showImportModal: false
+        });
+    }
+
+    handleChange(e) {
+        const value = e.target.type === 'checkbox' ? e.target.checked : e.target.value;
+        let valueErr = false;
+        let errObj = this.state.errObj;
+        if (value == "") {
+            valueErr = true;
+        }
+        errObj[e.target.id] = valueErr;
+        this.setState({
+            [e.target.id]: value,
+            errObj: errObj
+        });
+    }
+
+    showConfirmLDIFImport (item) {
+        // call deleteLDIF
+        this.setState({
+            showConfirmLDIFImport: true,
+            importLDIFName: item.name,
+        });
+    }
+
+    closeConfirmLDIFImport () {
+        // call importLDIF
+        this.setState({
+            showConfirmLDIFImport: false,
+        });
+    }
+
+    importLDIF (ldif) {
+        // Do import
+        let import_cmd = [
+            "dsconf", "-j", "ldapi://%2fvar%2frun%2fslapd-" + this.props.serverId + ".socket",
+            "backend", "import", this.props.suffix, ldif, "--encrypted"
+        ];
+
+        this.setState({
+            importSpinner: true,
+        });
+
+        log_cmd("doImport", "Do online import", import_cmd);
+        cockpit
+                .spawn(import_cmd, { superuser: true, err: "message" })
+                .done(content => {
+                    this.props.addNotification(
+                        "success",
+                        `Import successfully initiated`
+                    );
+                    this.setState({
+                        showImportModal: false
+                    });
+                })
+                .fail(err => {
+                    this.props.addNotification(
+                        "error",
+                        `Error importing LDIF file - ${err}`
+                    );
+                    this.setState({
+                        showImportModal: false
+                    });
+                });
+    }
+
+    doImport() {
+        // Validate form before proceeding
+        if (this.state.ldifLocation != "") {
+            this.setState({
+                showConfirmLDIFImport: true,
+                importLDIFName: this.state.ldifLocation,
+            });
+        }
+    }
+
+    //
+    // Export modal
+    //
+    showExportModal() {
+        this.setState({
+            ldifLocation: "",
+            attrEncryption: false,
+            showExportModal: true,
+            exportSpinner: false,
+            errObj: {},
+        });
+    }
+
+    closeExportModal() {
+        this.setState({
+            showExportModal: false,
+            exportSpinner: false
+        });
+    }
+
+    doExport() {
+        let missingArgs = {ldifLocation: false};
+        if (this.state.ldifLocation == "") {
+            this.props.addNotification(
+                "warning",
+                `LDIF name is empty`
+            );
+            missingArgs.ldifLocation = true;
+            this.setState({
+                errObj: missingArgs
+            });
+            return;
+        }
+
+        // Do import
+        let export_cmd = [
+            "dsconf", "-j", "ldapi://%2fvar%2frun%2fslapd-" + this.props.serverId + ".socket",
+            "backend", "export", this.props.suffix, "--ldif=" + this.state.ldifLocation, "--encrypted"
+        ];
+
+        if (this.state.attrEncrpytion) {
+            export_cmd.push("--encrypted");
+        }
+
+        this.setState({
+            exportSpinner: true,
+        });
+
+        log_cmd("doExport", "Do online export", export_cmd);
+        cockpit
+                .spawn(export_cmd, { superuser: true, err: "message" })
+                .done(content => {
+                    this.props.reloadLDIFs();
+                    this.props.addNotification(
+                        "success",
+                        `Database export complete`
+                    );
+                    this.setState({
+                        showExportModal: false,
+                    });
+                })
+                .fail(err => {
+                    this.loadLDIFs();
+                    this.props.addNotification(
+                        "error",
+                        `Error exporting database - ${err}`
+                    );
+                    this.setState({
+                        showExportModal: false,
+                    });
+                });
+    }
+
+    //
+    // Reindex entire database
+    //
+    showReindexConfirm() {
+        this.setState({
+            showReindexConfirm: true
+        });
+    }
+
+    closeReindexConfirm() {
+        this.setState({
+            showReindexConfirm: false
+        });
+    }
+
+    closeReindexModal() {
+        this.setState({
+            showReindexModal: false
+        });
+    }
+
+    doReindex() {
+        // Show index status modal
+        this.setState({
+            showReindexModal: true
+        });
+        const cmd = ["dsconf", "-j", "ldapi://%2fvar%2frun%2fslapd-" + this.props.serverId + ".socket",
+            "backend", "index", "reindex", "--wait", this.props.suffix];
+        log_cmd("doReindex", "Reindex all attributes", cmd);
+        cockpit
+                .spawn(cmd, { superuser: true, err: "message" })
+                .done(content => {
+                    this.props.addNotification(
+                        "success",
+                        `Database has successfully been reindexed`
+                    );
+                    this.setState({
+                        showReindexModal: false,
+                    });
+                })
+                .fail(err => {
+                    this.props.addNotification(
+                        "error",
+                        `Failed to reindex database - ${err}`
+                    );
+                    this.setState({
+                        showReindexModal: false,
+                    });
+                });
+    }
+
+    //
+    // Create sub suffix
+    //
+    showSubSuffixModal() {
+        this.setState({
+            showSubSuffixModal: true,
+            errObj: {},
+        });
+    }
+
+    closeSubSuffixModal() {
+        this.setState({
+            showSubSuffixModal: false
+        });
+    }
+
+    createSubSuffix() {
+        let missingArgs = {
+            createSuffix: false,
+            createBeName: false
+        };
+        let errors = false;
+        if (this.state.subSuffixValue == "") {
+            this.props.addNotification(
+                "warning",
+                `Missing Suffix`
+            );
+            missingArgs.subSuffixValue = true;
+            errors = true;
+        }
+        if (this.state.subSuffixBeName == "") {
+            this.props.addNotification(
+                "warning",
+                `Missing backend name`
+            );
+            missingArgs.subSuffixBeName = true;
+            errors = true;
+        }
+        if (errors) {
+            this.setState({
+                errObj: missingArgs
+            });
+            return;
+        }
+
+        // Create a new suffix
+        const cmd = [
+            "dsconf", "-j", "ldapi://%2fvar%2frun%2fslapd-" + this.props.serverId + ".socket",
+            "backend", "create", "--be-name", this.state.subSuffixBeName,
+            "--suffix=" + this.state.subSuffixValue + "," + this.props.suffix,
+            "--parent-suffix=" + this.props.suffix
+        ];
+
+        log_cmd("createSubSuffix", "Create a sub suffix", cmd);
+        cockpit
+                .spawn(cmd, { superuser: true, err: "message" })
+                .done(content => {
+                    this.props.loadSuffixTree(false);
+                    this.closeSubSuffixModal();
+                    this.props.addNotification(
+                        "success",
+                        `Successfully created new sub-suffix`
+                    );
+                })
+                .fail(err => {
+                    this.props.loadSuffixTree(false);
+                    this.closeSubSuffixModal();
+                    this.props.addNotification(
+                        "error",
+                        `Error creating sub-suffix - ${err}`
+                    );
+                });
+    }
+
+    //
+    // Create Chaining Link
+    //
+    showLinkModal() {
+        this.setState({
+            showLinkModal: true,
+            linkPwdMatch: true,
+            errObj: {},
+        });
+    }
+
+    closeLinkModal() {
+        this.setState({
+            showLinkModal: false
+        });
+    }
+
+    createLink() {
+        // Check for required paramters
+        let formError = false;
+        let missingArgs = {
+            createLinkSuffix: false,
+            createNsfarmserverurl: false,
+            createLinkName: false,
+            createNsmultiplexorbinddn: false,
+            createNsmultiplexorcredentials: false,
+            createNsmultiplexorcredentialsConfirm: false
+        };
+        if (this.state.createLinkSuffix == "") {
+            this.props.addNotification(
+                "warning",
+                `Missing subsuffix!`
+            );
+            missingArgs.createLinkSuffix = true;
+            formError = true;
+        }
+        if (this.state.createNsfarmserverurl == "") {
+            this.props.addNotification(
+                "warning",
+                `Missing Server URL!`
+            );
+            missingArgs.createNsfarmserverurl = true;
+            formError = true;
+        }
+        if (this.state.createLinkName == "") {
+            this.props.addNotification(
+                "warning",
+                `Missing Link Name`
+            );
+            missingArgs.createLinkName = true;
+            formError = true;
+        }
+        if (this.state.createNsmultiplexorbinddn == "") {
+            this.props.addNotification(
+                "warning",
+                `Missing Bind DN`
+            );
+            missingArgs.createNsmultiplexorbinddn = true;
+            formError = true;
+        }
+        // Check passwords match
+        if (this.state.createNsmultiplexorcredentials == "" &&
+            this.state.createNsmultiplexorcredentialsConfirm == "") {
+            this.props.addNotification(
+                "warning",
+                `Missing Bind Password`
+            );
+            missingArgs.createNsmultiplexorcredentialsConfirm = true;
+            missingArgs.createNsmultiplexorcredentials = true;
+            formError = true;
+        }
+        if (this.state.createNsmultiplexorcredentials != this.state.createNsmultiplexorcredentialsConfirm) {
+            this.props.addNotification(
+                "warning",
+                `Passwords do not match`
+            );
+            missingArgs.createNsmultiplexorcredentialsConfirm = true;
+            missingArgs.createNsmultiplexorcredentials = false;
+            formError = true;
+        }
+        if (formError) {
+            this.setState({
+                errObj: missingArgs
+            });
+            return;
+        }
+
+        // Add chaining link
+        let cmd = [
+            "dsconf", "-j", "ldapi://%2fvar%2frun%2fslapd-" + this.props.serverId + ".socket",
+            "chaining", "link-create",
+            "--suffix=" + this.state.createLinkSuffix + "," + this.props.suffix,
+            "--server-url=" + this.state.createNsfarmserverurl,
+            "--bind-mech=" + this.state.createNsbindmechanism,
+            "--bind-dn=" + this.state.createNsmultiplexorbinddn,
+            "--bind-pw=" + this.state.createNsmultiplexorcredentials,
+            this.state.createLinkName
+        ];
+        if (this.state.createUseStartTLS) {
+            cmd.push("--use-starttls");
+        }
+        log_cmd("createLink", "Create database link", cmd);
+        cockpit
+                .spawn(cmd, { superuser: true, err: "message" })
+                .done(content => {
+                    this.props.loadSuffixTree(false);
+                    this.closeLinkModal();
+                    this.props.addNotification(
+                        "success",
+                        `Successfully created database link`
+                    );
+                })
+                .fail(err => {
+                    this.props.loadSuffixTree(false);
+                    this.closeLinkModal();
+                    this.props.addNotification(
+                        "error",
+                        `Error creating database link - ${err}`
+                    );
+                });
+    }
+
+    checkPasswords() {
+        let pwdMatch = false;
+        if (this.state.createNsmultiplexorcredentials == this.state.createNsmultiplexorcredentialsConfirm) {
+            pwdMatch = true;
+        }
+        this.setState({
+            linkPwdMatch: pwdMatch
+        });
+    }
+
+    handleLinkChange(e) {
+        // Check for matching credentials
+        const value = e.target.type === 'checkbox' ? e.target.checked : e.target.value;
+        let valueErr = false;
+        let errObj = this.state.errObj;
+        if (value == "") {
+            valueErr = true;
+        }
+        errObj[e.target.id] = valueErr;
+        this.setState({
+            [e.target.id]: value,
+            errObj: errObj
+        }, this.checkPasswords);
+    }
+
+    //
+    // Delete suffix
+    //
+    showDeleteConfirm(item) {
+        this.setState({
+            showDeleteConfirm: true
+        });
+    }
+
+    closeDeleteConfirm() {
+        this.setState({
+            showDeleteConfirm: false
+        });
+    }
+
+    doDelete() {
+        // Delete suffix
+        const cmd = [
+            "dsconf", "-j", "ldapi://%2fvar%2frun%2fslapd-" + this.props.serverId + ".socket",
+            "backend", "delete", this.props.suffix
+        ];
+        log_cmd("doDelete", "Delete database", cmd);
+        cockpit
+                .spawn(cmd, { superuser: true, err: "message" })
+                .done(content => {
+                    this.props.loadSuffixTree(true);
+                    this.closeLinkModal();
+                    this.props.addNotification(
+                        "success",
+                        `Successfully deleted database`
+                    );
+                })
+                .fail(err => {
+                    this.props.loadSuffixTree(true);
+                    this.closeLinkModal();
+                    this.props.addNotification(
+                        "error",
+                        `Error deleting database - ${err}`
+                    );
+                });
+    }
+
+    // Save config
+    saveSuffixConfig() {
+        console.log("Save suffix config: ", this.props.suffix);
+        let cmd = [
+            'dsconf', '-j', 'ldapi://%2fvar%2frun%2fslapd-' + this.props.serverId + '.socket',
+            'backend', 'suffix', 'set', this.props.suffix
+        ];
+        let requireRestart = false;
+        if (this.state._readOnly != this.state.readOnly) {
+            if (this.state.readOnly) {
+                cmd.push("--enable-readonly");
+            } else {
+                cmd.push("--disable-readonly");
+            }
+        }
+        if (this.state._requireIndex != this.state.requireIndex) {
+            if (this.state.requireIndex) {
+                cmd.push("--require-index");
+            } else {
+                cmd.push("--ignore-index");
+            }
+        }
+        if (this.state._cachememsize != this.state.cachememsize) {
+            cmd.push("--cache-memsize=" + this.state.cachememsize);
+            requireRestart = true;
+        }
+        if (this.state._cachesize != this.state.cachesize) {
+            cmd.push("--cache-size=" + this.state.cachesize);
+            requireRestart = true;
+        }
+        if (this.state._dncachememsize != this.state.dncachememsize) {
+            cmd.push("--dncache-memsize=" + this.state.dncachememsize);
+            requireRestart = true;
+        }
+        if (cmd.length > 7) {
+            log_cmd("saveSuffixConfig", "Save suffix config", cmd);
+            let msg = "Successfully updated suffix configuration";
+            if (requireRestart) {
+                msg = ("Successfully updated suffix configuration.  These " +
+                    "changes require the server to be restarted to take effect");
+            }
+            cockpit
+                    .spawn(cmd, {superuser: true, "err": "message"})
+                    .done(content => {
+                        // Continue with the next mod
+                        this.props.reload(this.props.suffix);
+                        this.props.addNotification(
+                            "success",
+                            msg
+                        );
+                    })
+                    .fail(err => {
+                        this.props.reload(this.props.suffix);
+                        this.props.addNotification(
+                            "error",
+                            `Error updating suffix configuration - ${err}`
+                        );
+                    });
+        }
+    }
+
+    //
+    // Render the component
+    //
+    render () {
+        let suffixIcon = "tree";
+        if (this.props.dbtype == "subsuffix") {
+            suffixIcon = "leaf";
+        }
+
+        const confirm_msg =
+            <span>
+                Are you sure you want to import: <b>{this.state.importLDIFName}</b> ?
+            </span>;
+
+        return (
+            <div className="container-fluid" id="suffix-page">
+                <Row>
+                    <Col sm={10} className="ds-word-wrap">
+                        <ControlLabel className="ds-suffix-header"><Icon type="fa" name={suffixIcon} /> {this.props.suffix} (<i>{this.props.bename}</i>)</ControlLabel>
+                    </Col>
+                    <Col sm={2}>
+                        <div>
+                            <DropdownButton bsStyle="primary" title="Suffix Tasks" id="mydropdown">
+                                <MenuItem eventKey="1" onClick={this.showImportModal} title="Import an LDIF file to initialize the database">
+                                    Initialize Suffix
+                                </MenuItem>
+                                <MenuItem eventKey="2" onClick={this.showExportModal} title="Export the database to an LDIF file">
+                                    Export Suffix
+                                </MenuItem>
+                                <MenuItem eventKey="3" onClick={this.showReindexConfirm} title="Reindex the entire database">
+                                    Reindex Suffix
+                                </MenuItem>
+                                <MenuItem eventKey="4" onClick={this.showSubSuffixModal} title="Create a sub-suffix under this suffix">
+                                    Create Sub-Suffix
+                                </MenuItem>
+                                <MenuItem eventKey="5" onClick={this.showLinkModal} title="Create a database chaining link subtree">
+                                    Create Database Link
+                                </MenuItem>
+                                <MenuItem divider />
+                                <MenuItem eventKey="6" onClick={this.showDeleteConfirm} title="This will permanently delete the database">
+                                    Delete Suffix
+                                </MenuItem>
+                            </DropdownButton>
+                        </div>
+                    </Col>
+                </Row>
+                <p />
+
+                <TabContainer id="basic-tabs-pf" onSelect={this.handleNavSelect} activeKey={this.state.activeKey}>
+                    <div>
+                        <Nav bsClass="nav nav-tabs nav-tabs-pf">
+                            <NavItem eventKey={1}>
+                                <div dangerouslySetInnerHTML={{__html: 'Settings'}} />
+                            </NavItem>
+                            <NavItem eventKey={2}>
+                                <div dangerouslySetInnerHTML={{__html: 'Referrals'}} />
+                            </NavItem>
+                            <NavItem eventKey={3}>
+                                <div dangerouslySetInnerHTML={{__html: 'Indexes'}} />
+                            </NavItem>
+                            <NavItem eventKey={5}>
+                                <div dangerouslySetInnerHTML={{__html: 'VLV Indexes'}} />
+                            </NavItem>
+                            <NavItem eventKey={4}>
+                                <div dangerouslySetInnerHTML={{__html: 'Encrypted Attributes'}} />
+                            </NavItem>
+                        </Nav>
+                        <TabContent>
+
+                            <TabPane eventKey={1}>
+                                <SuffixConfig
+                                    cachememsize={this.state.cachememsize}
+                                    cachesize={this.state.cachesize}
+                                    dncachememsize={this.state.dncachememsize}
+                                    readOnly={this.state.readOnly}
+                                    requireIndex={this.state.requireIndex}
+                                    autoTuning={this.state.autoTuning}
+                                    handleChange={this.handleChange}
+                                    saveHandler={this.saveSuffixConfig}
+                                />
+                            </TabPane>
+
+                            <TabPane eventKey={2}>
+                                <SuffixReferrals
+                                    rows={this.props.data.refRows}
+                                    suffix={this.props.suffix}
+                                    reload={this.props.reloadRefs}
+                                    addNotification={this.props.addNotification}
+                                    serverId={this.props.serverId}
+                                    key={this.state.refRows}
+                                />
+                            </TabPane>
+
+                            <TabPane eventKey={3}>
+                                <div className="ds-indent ds-tab-table">
+                                    <TabContainer id="index-tabs" defaultActiveKey={1}>
+                                        <SuffixIndexes
+                                            systemIndexRows={this.props.data.systemIndexRows}
+                                            indexRows={this.props.data.indexRows}
+                                            suffix={this.props.suffix}
+                                            serverId={this.props.serverId}
+                                            addNotification={this.props.addNotification}
+                                            reload={this.props.reloadIndexes}
+                                        />
+                                    </TabContainer>
+                                </div>
+                            </TabPane>
+                            <TabPane eventKey={4}>
+                                <div className="ds-sub-header">
+                                    <AttrEncryption
+                                        rows={this.props.data.encAttrsRows}
+                                        suffix={this.props.suffix}
+                                        serverId={this.props.serverId}
+                                        addNotification={this.props.addNotification}
+                                        attrs={this.props.attrs}
+                                        reload={this.props.reloadAttrEnc}
+                                    />
+                                </div>
+                            </TabPane>
+                            <TabPane eventKey={5}>
+                                <VLVIndexes
+                                    suffix={this.props.suffix}
+                                    serverId={this.props.serverId}
+                                    vlvItems={this.props.data.vlvItems}
+                                    addNotification={this.props.addNotification}
+                                    attrs={this.props.attrs}
+                                    reload={this.props.reloadVLV}
+                                />
+                            </TabPane>
+                        </TabContent>
+                    </div>
+                </TabContainer>
+
+                <ConfirmPopup
+                    showModal={this.state.showDeleteConfirm}
+                    closeHandler={this.closeDeleteConfirm}
+                    actionFunc={this.doDelete}
+                    actionParam={this.props.suffix}
+                    msg="Are you really sure you want to delete the database?"
+                    msgContent={this.props.suffix}
+                />
+                <CreateLinkModal
+                    showModal={this.state.showLinkModal}
+                    closeHandler={this.closeLinkModal}
+                    handleChange={this.handleLinkChange}
+                    saveHandler={this.createLink}
+                    suffix={this.props.suffix}
+                    pwdMatch={this.state.linkPwdMatch}
+                    error={this.state.errObj}
+                />
+                <CreateSubSuffixModal
+                    showModal={this.state.showSubSuffixModal}
+                    closeHandler={this.closeSubSuffixModal}
+                    handleChange={this.handleChange}
+                    saveHandler={this.createSubSuffix}
+                    suffix={this.props.suffix}
+                    error={this.state.errObj}
+                />
+                <ImportModal
+                    showModal={this.state.showImportModal}
+                    closeHandler={this.closeImportModal}
+                    handleChange={this.handleChange}
+                    saveHandler={this.doImport}
+                    showConfirmImport={this.showConfirmLDIFImport}
+                    spinning={this.state.importSpinner}
+                    rows={this.props.LDIFRows}
+                    suffix={this.props.suffix}
+                />
+                <ConfirmPopup
+                    showModal={this.state.showConfirmLDIFImport}
+                    closeHandler={this.closeConfirmLDIFImport}
+                    actionFunc={this.importLDIF}
+                    actionParam={this.state.importLDIFName}
+                    msg={confirm_msg}
+                    msgContent="WARNING: This action will permanently overwrite the current database!"
+                />
+
+                <ExportModal
+                    showModal={this.state.showExportModal}
+                    closeHandler={this.closeExportModal}
+                    handleChange={this.handleChange}
+                    saveHandler={this.doExport}
+                    spinning={this.state.exportSpinner}
+                    error={this.state.errObj}
+                />
+                <ConfirmPopup
+                    showModal={this.state.showReindexConfirm}
+                    closeHandler={this.closeReindexConfirm}
+                    actionFunc={this.doReindex}
+                    actionParam={this.props.suffix}
+                    msg="Are you sure you want to reindex all the attribute indexes?"
+                    msgContent=""
+                />
+                <ReindexModal
+                    showModal={this.state.showReindexModal}
+                    closeHandler={this.closeReindexModal}
+                    msg="Reindexing All Attribute Indexes"
+                />
+            </div>
+        );
+    }
+}
+
+// Property types and defaults
+
+Suffix.propTypes = {
+    serverId: PropTypes.string,
+    suffix: PropTypes.string,
+    bename: PropTypes.string,
+    loadSuffixTree: PropTypes.func,
+    reload: PropTypes.func,
+    reloadRefs: PropTypes.func,
+    reloadIndexes: PropTypes.func,
+    reloadVLV: PropTypes.func,
+    reloadAttrEnc: PropTypes.func,
+    reloadLDIFs: PropTypes.func,
+    addNotification: PropTypes.func,
+    dbtype: PropTypes.string,
+    data: PropTypes.object,
+    attrs: PropTypes.array,
+    LDIFRows: PropTypes.array,
+};
+
+Suffix.defaultProps = {
+    serverId: "",
+    suffix: "",
+    bename: "",
+    loadSuffixTree: noop,
+    reload: noop,
+    reloadRefs: noop,
+    reloadIndexes: noop,
+    reloadVLV: noop,
+    reloadAttrEnc: noop,
+    reloadLDIFs: noop,
+    addNotification: noop,
+    dbtype: "",
+    data: {},
+    attrs: [],
+    LDIFRows: []
+};
diff --git a/src/cockpit/389-console/src/lib/database/suffixConfig.jsx b/src/cockpit/389-console/src/lib/database/suffixConfig.jsx
new file mode 100644
index 0000000..ec9cd60
--- /dev/null
+++ b/src/cockpit/389-console/src/lib/database/suffixConfig.jsx
@@ -0,0 +1,89 @@
+import React from "react";
+import "../../css/ds.css";
+import PropTypes from "prop-types";
+import { noop } from "patternfly-react";
+
+export class SuffixConfig extends React.Component {
+    render() {
+        let cacheInputs;
+        if (this.props.autoTuning) {
+            const cacheValue = this.props.cachesize + "  (auto-sized)";
+            const cachememValue = this.props.cachememsize + "  (auto-sized)";
+            cacheInputs =
+                <div>
+                    <div title="The entry cache size setting is being auto-sized and is read-only - see Global Database Configuration">
+                        <label htmlFor="cachememsize" className="ds-config-label-lrg">
+                            Entry Cache Size (bytes)</label><input disabled value={cachememValue} className="ds-input" type="text" id="cachememsize" size="45" />
+                    </div>
+                    <div title="The entry cache max entries setting is being auto-sized and is read-only - see Global Database Configuration">
+                        <label htmlFor="cachesize" className="ds-config-label-lrg">
+                            Entry Cache Max Entries</label><input disabled value={cacheValue} className="ds-input" id="cachesize" type="text" size="45" />
+                    </div>
+                    <div>
+                        <label htmlFor="dncachememsize" className="ds-config-label-lrg" title="the available memory space for the DN cache. The DN cache is similar to the entry cache for a database, only its table stores only the entry ID and the entry DN (nsslapd-dncachememsize).">
+                            DN Cache Size (bytes)</label><input onChange={this.props.handleChange} value={this.props.dncachememsize} className="ds-input" type="text" id="dncachememsize" size="45" />
+                    </div>
+                </div>;
+        } else {
+            cacheInputs =
+                <div>
+                    <div>
+                        <label htmlFor="cachememsize" className="ds-config-label-lrg" title="The size for the available memory space for the entry cache (nsslapd-cachememsize).">
+                            Entry Cache Size (bytes)</label><input onChange={this.props.handleChange} value={this.props.cachememsize} className="ds-input" type="text" id="cachememsize" size="30" />
+                    </div>
+                    <div>
+                        <label htmlFor="cachesize" className="ds-config-label-lrg" title="The number of entries to keep in the entry cache, use'-1' for unlimited (nsslapd-cachesize).">
+                            Entry Cache Max Entries</label><input onChange={this.props.handleChange} value={this.props.cachesize} className="ds-input" type="text" id="cachesize" size="30" />
+                    </div>
+                    <div>
+                        <label htmlFor="dncachememsize" className="ds-config-label-lrg" title="the available memory space for the DN cache. The DN cache is similar to the entry cache for a database, only its table stores only the entry ID and the entry DN (nsslapd-dncachememsize).">
+                            DN Cache Size (bytes)</label><input onChange={this.props.handleChange} value={this.props.dncachememsize} className="ds-input" type="text" id="dncachememsize" size="30" />
+                    </div>
+                </div>;
+        }
+        return (
+            <div className="ds-margin-top-lg">
+                <p />
+                {cacheInputs}
+                <p />
+                <div>
+                    <div>
+                        <input type="checkbox" onChange={this.props.handleChange} checked={this.props.readOnly} className="ds-config-checkbox" id="readOnly" /><label
+                            htmlFor="readOnly" className="ds-label" title="Put database in Read-Only mode (nsslapd-readonly)."> Database Read-Only Mode</label>
+                    </div>
+                    <div>
+                        <input type="checkbox" onChange={this.props.handleChange} checked={this.props.requireIndex} className="ds-config-checkbox" id="requireIndex" /><label
+                            htmlFor="requireIndex" className="ds-label" title="Block unindexed searches on this suffix (nsslapd-require-index)."> Block Unindexed Searches</label>
+                    </div>
+                </div>
+                <div className="ds-save-btn">
+                    <button className="btn btn-primary save-button" onClick={this.props.saveHandler}>Save Configuration</button>
+                </div>
+            </div>
+        );
+    }
+}
+
+// Property types and defaults
+
+SuffixConfig.propTypes = {
+    cachememsize: PropTypes.string,
+    cachesize: PropTypes.string,
+    dncachememsize: PropTypes.string,
+    readOnly: PropTypes.bool,
+    requireIndex: PropTypes.bool,
+    autoTuning: PropTypes.bool,
+    handleChange: PropTypes.func,
+    saveHandler: PropTypes.func,
+};
+
+SuffixConfig.defaultProps = {
+    cachememsize: "",
+    cachesize: "",
+    dncachememsize: "",
+    readOnly: false,
+    requireIndex: false,
+    autoTuning: false,
+    handleChange: noop,
+    saveHandler: noop,
+};
diff --git a/src/cockpit/389-console/src/lib/database/vlvIndexes.jsx b/src/cockpit/389-console/src/lib/database/vlvIndexes.jsx
new file mode 100644
index 0000000..674f8ec
--- /dev/null
+++ b/src/cockpit/389-console/src/lib/database/vlvIndexes.jsx
@@ -0,0 +1,951 @@
+import cockpit from "cockpit";
+import React from "react";
+import { ConfirmPopup } from "../notifications.jsx";
+import { log_cmd } from "../tools.jsx";
+import {
+    DropdownButton,
+    MenuItem,
+    ListView,
+    ListViewItem,
+    ListViewIcon,
+    Modal,
+    Row,
+    Checkbox,
+    Col,
+    ControlLabel,
+    Icon,
+    Button,
+    Form,
+    sortableHeaderCellFormatter,
+    actionHeaderCellFormatter,
+    tableCellFormatter,
+    noop
+} from "patternfly-react";
+import PropTypes from "prop-types";
+import { Typeahead } from "react-bootstrap-typeahead";
+import { DSShortTable } from "../dsTable.jsx";
+import "../../css/ds.css";
+
+export class VLVIndexes extends React.Component {
+    constructor (props) {
+        super(props);
+        this.state = {
+            vlvItems: [],
+            showVLVModal: false,
+            showVLVEditModal: false,
+            showDeleteConfirm: false,
+            showReindexConfirm: false,
+            errObj: {},
+            vlvName: "",
+            vlvBase: "",
+            vlvScope: "subtree",
+            vlvFilter: "",
+            vlvSortList: [],
+            _vlvName: "",
+            _vlvBase: "",
+            _vlvScope: "",
+            _vlvFilter: "",
+            _vlvSortList: [],
+        };
+
+        // Create VLV Modal
+        this.showVLVModal = this.showVLVModal.bind(this);
+        this.closeVLVModal = this.closeVLVModal.bind(this);
+        this.handleVLVChange = this.handleVLVChange.bind(this);
+        this.handleVLVSortChange = this.handleVLVSortChange.bind(this);
+        this.saveVLV = this.saveVLV.bind(this);
+        this.saveEditVLV = this.saveEditVLV.bind(this);
+        this.deleteVLV = this.deleteVLV.bind(this);
+        this.reindexVLV = this.reindexVLV.bind(this);
+        // Edit VLV modal
+        this.showVLVEditModal = this.showVLVEditModal.bind(this);
+        this.closeVLVEditModal = this.closeVLVEditModal.bind(this);
+        this.showDeleteConfirm = this.showDeleteConfirm.bind(this);
+        this.closeDeleteConfirm = this.closeDeleteConfirm.bind(this);
+        this.showReindexConfirm = this.showReindexConfirm.bind(this);
+        this.closeReindexConfirm = this.closeReindexConfirm.bind(this);
+    }
+
+    //
+    // VLV index functions
+    //
+    showVLVModal() {
+        this.setState({
+            showVLVModal: true,
+            errObj: {},
+            vlvName: "",
+            vlvBase: "",
+            vlvScope: "subtree",
+            vlvFilter: "",
+            vlvSortList: [],
+            vlvSortRows: [],
+        });
+    }
+
+    closeVLVModal() {
+        this.setState({
+            showVLVModal: false
+        });
+    }
+
+    handleVLVChange(e) {
+        const value = e.target.value;
+        let valueErr = false;
+        let errObj = this.state.errObj;
+        if (value == "") {
+            valueErr = true;
+        }
+        errObj[e.target.id] = valueErr;
+        this.setState({
+            [e.target.id]: value,
+            errObj: errObj
+        });
+    }
+
+    handleVLVSortChange(sorts) {
+        // "sorts" is a table obj that uses the key "sortName"
+        let sortList = [];
+        for (let sort of sorts) {
+            // Create array of sorts from array of objs
+            sortList.push(sort.sortName);
+        }
+        this.setState({
+            vlvSortList: sortList
+        });
+    }
+
+    // Edit VLVIndex
+    showVLVEditModal(e) {
+        const vlvName = e.target.name;
+        for (let item of this.props.vlvItems) {
+            const vlvAttrs = item.attrs;
+            if (vlvAttrs.cn[0] == vlvName) {
+                let sortRows = [];
+                let sortList = [];
+                for (let vlvSort of item.sorts) {
+                    sortRows.push({sortName: vlvSort.attrs.vlvsort[0]});
+                    sortList.push(vlvSort.attrs.vlvsort[0]);
+                }
+                this.setState({
+                    showVLVEditModal: true,
+                    errObj: {},
+                    vlvName: vlvAttrs.cn[0],
+                    vlvBase: vlvAttrs.vlvbase[0],
+                    vlvScope: this.getScopeKey(vlvAttrs.vlvscope[0]),
+                    vlvFilter: vlvAttrs.vlvfilter[0],
+                    vlvSortList: sortList,
+                    vlvSortRows: sortRows,
+                    _vlvName: vlvAttrs.cn[0],
+                    _vlvBase: vlvAttrs.vlvbase[0],
+                    _vlvScope: this.getScopeKey(vlvAttrs.vlvscope[0]),
+                    _vlvFilter: vlvAttrs.vlvfilter[0],
+                    _vlvSortList: sortList,
+                    _vlvSortRows: sortRows,
+                });
+                break;
+            }
+        }
+    }
+
+    closeVLVEditModal() {
+        this.setState({
+            showVLVEditModal: false
+        });
+    }
+
+    getScopeVal(scope) {
+        let mapping = {
+            'subtree': '2',
+            'one': '1',
+            'base': '0'
+        };
+        return mapping[scope];
+    }
+
+    getScopeKey(scope) {
+        let mapping = {
+            '2': 'subtree',
+            '1': 'one',
+            '0': 'base'
+        };
+        return mapping[scope];
+    }
+
+    saveEditVLV() {
+        let missingArgs = {};
+        let errors = false;
+        if (this.state.vlvBase == "") {
+            this.props.addNotification(
+                "warning",
+                `Missing VLV search base`
+            );
+            missingArgs.vlvBase = true;
+            errors = true;
+        }
+        if (this.state.vlvFilter == "") {
+            this.props.addNotification(
+                "warning",
+                `Missing VLV search filter`
+            );
+            missingArgs.vlvFilter = true;
+            errors = true;
+        }
+        if (errors) {
+            this.setState({
+                errObj: missingArgs
+            });
+            return;
+        }
+
+        let cmd = [
+            "dsconf", "-j", "ldapi://%2fvar%2frun%2fslapd-" + this.props.serverId + ".socket",
+            "backend", "vlv-index", "edit-search", "--name=" + this.state.vlvName,
+            this.props.suffix
+        ];
+        if (this.state.vlvBase != this.state._vlvBase) {
+            cmd.push("--search-base=" + this.state.vlvBase);
+        }
+        if (this.state.vlvScope != this.state._vlvScope) {
+            cmd.push("--search-scope=" + this.getScopeVal(this.state.vlvScope));
+        }
+        if (this.state.vlvFilter != this.state._vlvFilter) {
+            cmd.push("--search-filter=" + this.state.vlvFilter);
+        }
+        if (cmd.length > 8) {
+            log_cmd("saveEditVLV", "Add vlv search", cmd);
+            cockpit
+                    .spawn(cmd, { superuser: true, err: "message" })
+                    .done(content => {
+                        this.closeVLVEditModal();
+                        this.props.reload(this.props.suffix);
+                        this.props.addNotification(
+                            "success",
+                            "Successfully edited VLV search"
+                        );
+                    })
+                    .fail(err => {
+                        this.closeVLVEditModal();
+                        this.props.reload(this.props.suffix);
+                        this.props.addNotification(
+                            "error",
+                            `Failed to edit VLV search - ${err}`
+                        );
+                    });
+        }
+
+        // Check the sort indexes now
+        // Loop over sorts and create indexes or each one
+        let addIndexList = [];
+        let delIndexList = [];
+        for (let sort of this.state.vlvSortList) {
+            if (this.state._vlvSortList.indexOf(sort) == -1) {
+                // Add sort index
+                addIndexList.push(sort);
+            }
+        }
+        for (let sort of this.state._vlvSortList) {
+            if (this.state.vlvSortList.indexOf(sort) == -1) {
+                // Del sort index
+                delIndexList.push(sort);
+            }
+        }
+
+        // Add VLV index/sort
+        for (let index of addIndexList) {
+            cmd = [
+                "dsconf", "-j", "ldapi://%2fvar%2frun%2fslapd-" + this.props.serverId + ".socket",
+                "backend", "vlv-index", "add-index", "--parent-name=" + this.state.vlvName,
+                "--index-name=" + this.state.vlvName + " - " + index,
+                "--sort=" + index, this.props.suffix
+            ];
+            if (this.state.reindexVLV) {
+                cmd.push("--index-it");
+            }
+            log_cmd("saveEditVLV", "Add index", cmd);
+            cockpit
+                    .spawn(cmd, { superuser: true, err: "message" })
+                    .done(content => {
+                        this.closeVLVEditModal();
+                        this.props.reload(this.props.suffix);
+                        this.props.addNotification(
+                            "success",
+                            "Successfully added VLV index " + this.state.vlvName + " - " + index
+                        );
+                    })
+                    .fail(err => {
+                        this.closeVLVEditModal();
+                        this.props.reload(this.props.suffix);
+                        this.props.addNotification(
+                            "error",
+                            `Failed to add VLV index entry - ${err}`
+                        );
+                    });
+        }
+
+        // Del VLV index/sort
+        for (let index of delIndexList) {
+            cmd = [
+                "dsconf", "-j", "ldapi://%2fvar%2frun%2fslapd-" + this.props.serverId + ".socket",
+                "backend", "vlv-index", "del-index", "--parent-name=" + this.state.vlvName,
+                "--sort=" + index, this.props.suffix
+            ];
+            if (this.state.reindexVLV) {
+                cmd.push("--index-it");
+            }
+            log_cmd("saveEditVLV", "delete index", cmd);
+            cockpit
+                    .spawn(cmd, { superuser: true, err: "message" })
+                    .done(content => {
+                        this.closeVLVEditModal();
+                        this.props.reload(this.props.suffix);
+                        this.props.addNotification(
+                            "success",
+                            "Successfully added VLV index " + this.state.vlvName + " - " + index
+                        );
+                    })
+                    .fail(err => {
+                        this.closeVLVEditModal();
+                        this.props.reload(this.props.suffix);
+                        this.props.addNotification(
+                            "error",
+                            `Failed to add VLV index entry - ${err}`
+                        );
+                    });
+        }
+    }
+
+    saveVLV() {
+        let missingArgs = {};
+        let errors = false;
+        if (this.state.vlvName == "") {
+            this.props.addNotification(
+                "warning",
+                `Missing VLV Search Name`
+            );
+            missingArgs.vlvName = true;
+            errors = true;
+        }
+        if (this.state.vlvBase == "") {
+            this.props.addNotification(
+                "warning",
+                `Missing VLV search base`
+            );
+            missingArgs.vlvBase = true;
+            errors = true;
+        }
+        if (this.state.vlvFilter == "") {
+            this.props.addNotification(
+                "warning",
+                `Missing VLV search filter`
+            );
+            missingArgs.vlvFilter = true;
+            errors = true;
+        }
+        if (errors) {
+            this.setState({
+                errObj: missingArgs
+            });
+            return;
+        }
+
+        let cmd = [
+            "dsconf", "-j", "ldapi://%2fvar%2frun%2fslapd-" + this.props.serverId + ".socket",
+            "backend", "vlv-index", "add-search",
+            "--name=" + this.state.vlvName,
+            "--search-base=" + this.state.vlvBase,
+            "--search-filter=" + this.state.vlvFilter,
+            "--search-scope=" + this.getScopeVal(this.state.vlvScope),
+            this.props.suffix
+        ];
+        log_cmd("saveVLV", "Add vlv search", cmd);
+        cockpit
+                .spawn(cmd, { superuser: true, err: "message" })
+                .done(content => {
+                    this.props.reload(this.props.suffix);
+                    this.props.addNotification(
+                        "success",
+                        "Successfully added VLV search: " + this.state.vlvName
+                    );
+                    // Loop over sorts and create indexes or each one
+                    for (let sort of this.state.vlvSortList) {
+                        const indexName = this.state.vlvName + " - " + sort;
+                        let idx_cmd = [
+                            "dsconf", "-j", "ldapi://%2fvar%2frun%2fslapd-" + this.props.serverId + ".socket",
+                            "backend", "vlv-index", "add-index",
+                            "--parent-name=" + this.state.vlvName,
+                            "--index-name=" + indexName,
+                            "--sort=" + sort,
+                            this.props.suffix
+                        ];
+                        if (this.state.reindexVLV) {
+                            idx_cmd.push("--index");
+                        }
+                        log_cmd("saveVLV", "Add vlv index", idx_cmd);
+                        cockpit
+                                .spawn(idx_cmd, { superuser: true, err: "message" })
+                                .done(content => {
+                                    this.props.reload(this.props.suffix);
+                                    this.props.addNotification(
+                                        "success",
+                                        "Successfully added VLV index: " + indexName
+                                    );
+                                })
+                                .fail(err => {
+                                    this.props.addNotification(
+                                        "error",
+                                        `Failed create VLV index entry - ${err}`
+                                    );
+                                });
+                    }
+                })
+                .fail(err => {
+                    this.props.addNotification(
+                        "error",
+                        `Failed create VLV search entry - ${err}`
+                    );
+                });
+        this.closeVLVModal();
+    }
+
+    renderVLVActions(id) {
+        return (
+            <div>
+                <DropdownButton bsStyle="default" title="Actions" id={id}>
+                    <MenuItem eventKey="1" name={id} onClick={this.showVLVEditModal}>
+                        Edit VLV Index
+                    </MenuItem>
+                    <MenuItem eventKey="2" name={id} onClick={this.showReindexConfirm}>
+                        Reindex VLV Index
+                    </MenuItem>
+                    <MenuItem divider />
+                    <MenuItem eventKey="3" name={id} onClick={this.showDeleteConfirm}>
+                        Delete VLV Index
+                    </MenuItem>
+                </DropdownButton>
+            </div>
+        );
+    }
+
+    showDeleteConfirm (e) {
+        this.setState({
+            showDeleteConfirm: true,
+            deleteVLVName: e.target.name
+        });
+    }
+
+    closeDeleteConfirm () {
+        this.setState({
+            showDeleteConfirm: false,
+        });
+    }
+
+    deleteVLV(vlv) {
+        let cmd = [
+            "dsconf", "-j", "ldapi://%2fvar%2frun%2fslapd-" + this.props.serverId + ".socket",
+            "backend", "vlv-index", "del-search", "--name=" + vlv, this.props.suffix
+        ];
+        log_cmd("deleteVLV", "delete LV search and indexes", cmd);
+        cockpit
+                .spawn(cmd, { superuser: true, err: "message" })
+                .done(content => {
+                    this.props.reload(this.props.suffix);
+                    this.props.addNotification(
+                        "success",
+                        `Successfully deleted VLV index`
+                    );
+                })
+                .fail(err => {
+                    this.props.reload(this.props.suffix);
+                    this.props.addNotification(
+                        "error",
+                        `Failed to deletre VLV index - ${err}`
+                    );
+                });
+    }
+
+    showReindexConfirm (e) {
+        this.setState({
+            showReindexConfirm: true,
+            reindexVLVName: e.target.name
+        });
+    }
+
+    closeReindexConfirm () {
+        this.setState({
+            showReindexConfirm: false,
+        });
+    }
+
+    reindexVLV(vlv) {
+        let cmd = [
+            "dsconf", "-j", "ldapi://%2fvar%2frun%2fslapd-" + this.props.serverId + ".socket",
+            "backend", "vlv-index", "reindex", "--parent-name=" + vlv, this.props.suffix
+        ];
+        log_cmd("reindexVLV", "reindex VLV indexes", cmd);
+        cockpit
+                .spawn(cmd, { superuser: true, err: "message" })
+                .done(content => {
+                    this.props.reload(this.props.suffix);
+                    this.props.addNotification(
+                        "success",
+                        `Successfully completed VLV indexing`
+                    );
+                })
+                .fail(err => {
+                    this.props.reload(this.props.suffix);
+                    this.props.addNotification(
+                        "error",
+                        `Failed to index VLV index - ${err}`
+                    );
+                });
+    }
+
+    render() {
+        const vlvIndexes = this.props.vlvItems.map((vlvItem) =>
+            <ListViewItem
+                actions={this.renderVLVActions(vlvItem.attrs.cn[0])}
+                leftContent={<ListViewIcon name="list" />}
+                key={vlvItem.attrs.cn[0]}
+                heading={vlvItem.attrs.cn[0]}
+            >
+                <Row>
+                    <Col sm={11} key={vlvItem.dn}>
+                        <p key={vlvItem.dn + "-p"}><label className="ds-vlv-label">Base</label>{vlvItem.attrs.vlvbase[0]}</p>
+                        <p><label className="ds-vlv-label">Filter</label>{vlvItem.attrs.vlvfilter[0]}</p>
+                        <p><label className="ds-vlv-label">Scope</label>{this.getScopeKey(vlvItem.attrs.vlvscope[0])}</p>
+                        <hr />
+                        {
+                            vlvItem.sorts.map(sort => {
+                                let indexState;
+                                if (sort.attrs.vlvenabled[0] == "0") {
+                                    indexState = <font size="1" color="#d01c8b"><b>Disabled</b></font>;
+                                } else {
+                                    indexState = <font size="1" color="#4dac26"><b>Uses: </b>{sort.attrs.vlvuses[0]}</font>;
+                                }
+                                return (<p key={sort.dn + sort.attrs.vlvsort[0]}><label className="ds-vlv-label">Sort</label>{sort.attrs.vlvsort[0]} ({indexState})</p>);
+                            })
+                        }
+                    </Col>
+                </Row>
+            </ListViewItem>
+        );
+
+        return (
+            <div className="ds-tab-table">
+                <h5>Virtual List View Indexes</h5>
+                <ListView>
+                    {vlvIndexes}
+                </ListView>
+                <button className="btn btn-primary ds-margin-top" onClick={this.showVLVModal} type="button">Create VLV Index</button>
+                <AddVLVModal
+                    showModal={this.state.showVLVModal}
+                    closeHandler={this.closeVLVModal}
+                    handleChange={this.handleVLVChange}
+                    handleSortChange={this.handleVLVSortChange}
+                    saveHandler={this.saveVLV}
+                    error={this.state.errObj}
+                    attrs={this.props.attrs}
+                />
+                <AddVLVModal
+                    showModal={this.state.showVLVEditModal}
+                    closeHandler={this.closeVLVEditModal}
+                    handleChange={this.handleVLVChange}
+                    handleSortChange={this.handleVLVSortChange}
+                    saveHandler={this.saveEditVLV}
+                    edit
+                    error={this.state.errObj}
+                    attrs={this.props.attrs}
+                    vlvName={this.state.vlvName}
+                    vlvBase={this.state.vlvBase}
+                    vlvScope={this.state.vlvScope}
+                    vlvFilter={this.state.vlvFilter}
+                    vlvSortList={this.state.vlvSortRows}
+                />
+                <ConfirmPopup
+                    showModal={this.state.showDeleteConfirm}
+                    closeHandler={this.closeDeleteConfirm}
+                    actionFunc={this.deleteVLV}
+                    actionParam={this.state.deleteVLVName}
+                    msg="Are you sure you want to delete this VLV index?"
+                    msgContent={this.state.deleteVLVName}
+                />
+                <ConfirmPopup
+                    showModal={this.state.showReindexConfirm}
+                    closeHandler={this.closeReindexConfirm}
+                    actionFunc={this.reindexVLV}
+                    actionParam={this.state.reindexVLVName}
+                    msg="Are you sure you want to reindex this VLV index?"
+                    msgContent={this.state.reindexVLVName}
+                />
+            </div>
+        );
+    }
+}
+
+// Add and edit modal
+class AddVLVModal extends React.Component {
+    constructor(props) {
+        super(props);
+        let sortRows = [];
+        if (this.props.edit !== undefined && this.props.vlvSortList !== undefined) {
+            sortRows = this.props.vlvSortList;
+        }
+        this.state = {
+            sortRows: sortRows,
+            sortValue: "",
+            columns: [],
+            edit: false,
+        };
+
+        this.getColumns = this.getColumns.bind(this);
+        this.getSingleColumn = this.getSingleColumn.bind(this);
+        this.updateSorts = this.updateSorts.bind(this);
+        this.handleVLVSortChange = this.handleVLVSortChange.bind(this);
+        this.close = this.close.bind(this);
+        this.save = this.save.bind(this);
+    }
+
+    getSingleColumn () {
+        return [
+            {
+                property: "msg",
+                header: {
+                    label: "VLV Sort Indexes",
+                    props: {
+                        index: 0,
+                        rowSpan: 1,
+                        colSpan: 1,
+                        sort: true
+                    },
+                    transforms: [],
+                    formatters: [],
+                    customFormatters: [sortableHeaderCellFormatter]
+                },
+                cell: {
+                    props: {
+                        index: 0
+                    },
+                    formatters: [tableCellFormatter]
+                }
+            },
+        ];
+    }
+
+    getColumns () {
+        return [
+            {
+                property: "sortName",
+                header: {
+                    label: "VLV Sort Indexes",
+                    props: {
+                        index: 0,
+                        rowSpan: 1,
+                        colSpan: 1,
+                        sort: true
+                    },
+                    transforms: [],
+                    formatters: [],
+                    customFormatters: [sortableHeaderCellFormatter]
+                },
+                cell: {
+                    props: {
+                        index: 0
+                    },
+                    formatters: [tableCellFormatter]
+                }
+            },
+            {
+                property: "actions",
+                header: {
+                    label: "",
+                    props: {
+                        index: 1,
+                        rowSpan: 1,
+                        colSpan: 1
+                    },
+                    formatters: [actionHeaderCellFormatter]
+                },
+                cell: {
+                    props: {
+                        index: 2
+                    },
+                    formatters: [
+                        (value, { rowData }) => {
+                            return [
+                                <td key={rowData.sortName[0]}>
+                                    <Button
+                                        onClick={() => {
+                                            this.handleVLVSortChange(
+                                                rowData
+                                            );
+                                        }}
+                                    >
+                                        Remove
+                                    </Button>
+                                </td>
+                            ];
+                        }
+                    ]
+                }
+            }
+        ];
+    }
+
+    handleVLVSortChange(e) {
+        // VLV index was removed from table
+        let rows = this.state.sortRows;
+        for (let i = 0; i < rows.length; i++) {
+            if (rows[i].sortName == e.sortName) {
+                rows.splice(i, 1);
+                this.setState({
+                    sortRows: rows
+                });
+                this.props.handleSortChange(rows);
+                return;
+            }
+        }
+    }
+
+    handleTypeaheadChange(values) {
+        const value = values.join(' ');
+        this.setState({
+            sortValue: value
+        });
+    }
+
+    updateSorts() {
+        let rows = this.state.sortRows;
+        if (this.state.sortValue != "") {
+            rows.push({sortName: this.state.sortValue});
+            this.typeahead.getInstance().clear();
+            this.setState({
+                sortRows: rows,
+                sortValue: ""
+            });
+            this.props.handleSortChange(rows);
+        }
+    }
+
+    save() {
+        // reset the rows, and call the save handler
+        this.state.sortRows = [];
+        this.props.saveHandler();
+    }
+
+    close() {
+        this.state.sortRows = [];
+        this.props.closeHandler();
+    }
+
+    render() {
+        const {
+            showModal,
+            closeHandler,
+            handleChange,
+            error,
+            attrs
+        } = this.props;
+        let title;
+        let nameInput;
+        let base = "";
+        let scope = "subtree";
+        let filter = "";
+        let sortTable;
+
+        if (this.props.edit) {
+            title = "Edit VLV Index";
+            nameInput = <input className="ds-input-auto" type="text" value={this.props.vlvName} readOnly />;
+            base = this.props.vlvBase;
+            scope = this.props.vlvScope;
+            filter = this.props.vlvFilter;
+            if (this.props.vlvSortList !== undefined) {
+                // {sortName: "value"},
+                this.state.sortRows = this.props.vlvSortList;
+            }
+        } else {
+            // Create new index
+            // this.state.sortRows = [];
+            title = "Create VLV Index";
+            nameInput = <input className={error.vlvName ? "ds-input-auto-bad" : "ds-input-auto"} type="text" onChange={handleChange} id="vlvName" />;
+        }
+
+        let vlvscope =
+            <Row>
+                <Col sm={3}>
+                    <ControlLabel>Search Scope</ControlLabel>
+                </Col>
+                <Col sm={9}>
+                    <select defaultValue={scope}
+                        onChange={this.props.handleChange} className="btn btn-default dropdown" id="vlvScope">
+                        <option>subtree</option>
+                        <option>one</option>
+                        <option>base</option>
+                    </select>
+                </Col>
+            </Row>;
+
+        if (this.state.sortRows.length == 0) {
+            sortTable = <DSShortTable
+                getColumns={this.getSingleColumn}
+                rowKey={"msg"}
+                rows={[{msg: "No sort indexes"}]}
+            />;
+        } else {
+            sortTable = <DSShortTable
+                getColumns={this.getColumns}
+                rowKey={"sortName"}
+                rows={this.state.sortRows}
+            />;
+        }
+
+        return (
+            <Modal show={showModal} onHide={this.close}>
+                <div>
+                    <Modal.Header>
+                        <button
+                            className="close"
+                            onClick={closeHandler}
+                            aria-hidden="true"
+                            aria-label="Close"
+                        >
+                            <Icon type="pf" name="close" />
+                        </button>
+                        <Modal.Title>
+                            {title}
+                        </Modal.Title>
+                    </Modal.Header>
+                    <Modal.Body>
+                        <Form horizontal autoComplete="off">
+                            <Row>
+                                <Col sm={3}>
+                                    <ControlLabel>VLV Index Name</ControlLabel>
+                                </Col>
+                                <Col sm={9}>
+                                    {nameInput}
+                                </Col>
+                            </Row>
+                            <p />
+                            <Row>
+                                <Col sm={3}>
+                                    <ControlLabel>Search Base</ControlLabel>
+                                </Col>
+                                <Col sm={9}>
+                                    <input className={error.vlvBase ? "ds-input-auto-bad" : "ds-input-auto"}
+                                        onChange={handleChange} type="text" id="vlvBase" defaultValue={base} />
+                                </Col>
+                            </Row>
+                            <p />
+                            <Row>
+                                <Col sm={3}>
+                                    <ControlLabel>Search Filter</ControlLabel>
+                                </Col>
+                                <Col sm={9}>
+                                    <input className={error.vlvFilter ? "ds-input-auto-bad" : "ds-input-auto"}
+                                        onChange={handleChange} type="text" id="vlvFilter" defaultValue={filter} />
+                                </Col>
+                            </Row>
+                            <p />
+                            {vlvscope}
+                            <hr />
+                            <div>
+                                <p />
+                                <div>
+                                    {sortTable}
+                                    <p />
+                                    <Typeahead
+                                        multiple
+                                        id="vlvsortindex"
+                                        onChange={values => {
+                                            this.handleTypeaheadChange(values);
+                                        }}
+                                        maxResults={1000}
+                                        options={attrs}
+                                        placeholder="Start typing attribute names to create a sort index"
+                                        ref={(typeahead) => { this.typeahead = typeahead }}
+                                    />
+                                    <p />
+                                    <button type="button" onClick={this.updateSorts}>Add Sort Index</button>
+                                </div>
+                            </div>
+                            <hr />
+                            <Row>
+                                <Col sm={12}>
+                                    <Checkbox className="ds-float-right" id="reindexVLV" onChange={handleChange}>
+                                        Index VLV on Save
+                                    </Checkbox>
+                                </Col>
+                            </Row>
+                        </Form>
+                    </Modal.Body>
+                    <Modal.Footer>
+                        <Button
+                            bsStyle="default"
+                            className="btn-cancel"
+                            onClick={this.close}
+                        >
+                            Cancel
+                        </Button>
+                        <Button
+                            bsStyle="primary"
+                            onClick={this.save}
+                        >
+                            Save VLV Index
+                        </Button>
+                    </Modal.Footer>
+                </div>
+            </Modal>
+        );
+    }
+}
+
+// Property types and defaults
+
+VLVIndexes.propTypes = {
+    suffix: PropTypes.string,
+    serverId: PropTypes.string,
+    vlvItems: PropTypes.array,
+    addNotification: PropTypes.func,
+    attrs: PropTypes.array,
+    reload: PropTypes.func,
+};
+
+VLVIndexes.defaultProps = {
+    suffix: "",
+    serverId: "",
+    vlvItems: [],
+    addNotification: noop,
+    attrs: [],
+    reload: noop,
+};
+
+AddVLVModal.propTypes = {
+    showModal: PropTypes.bool,
+    closeHandler: PropTypes.func,
+    handleChange: PropTypes.func,
+    handleSortChange: PropTypes.func,
+    saveHandler: PropTypes.func,
+    edit: PropTypes.bool,
+    error: PropTypes.object,
+    attrs: PropTypes.array,
+    vlvName: PropTypes.string,
+    vlvBase: PropTypes.string,
+    vlvScope: PropTypes.string,
+    vlvFilter: PropTypes.string,
+    vlvSortList: PropTypes.array,
+};
+
+AddVLVModal.defaultProps = {
+    showModal: false,
+    closeHandler: noop,
+    handleChange: noop,
+    handleSortChange: noop,
+    saveHandler: noop,
+    edit: false,
+    error: {},
+    attrs: [],
+    vlvName: "",
+    vlvBase: "",
+    vlvScope: "",
+    vlvFilter: "",
+    vlvSortList: [],
+};
diff --git a/src/cockpit/389-console/src/lib/dsTable.jsx b/src/cockpit/389-console/src/lib/dsTable.jsx
new file mode 100644
index 0000000..4b17840
--- /dev/null
+++ b/src/cockpit/389-console/src/lib/dsTable.jsx
@@ -0,0 +1,412 @@
+import React from "react";
+import {
+    PaginationRow,
+    paginate,
+    Table,
+    customHeaderFormattersDefinition,
+    defaultSortingOrder,
+    TABLE_SORT_DIRECTION,
+    PAGINATION_VIEW
+} from "patternfly-react";
+import PropTypes from "prop-types";
+import { orderBy } from "lodash";
+import * as sort from "sortabular";
+import * as resolve from "table-resolver";
+import { compose } from "recompose";
+import { searchFilter } from "./tools.jsx";
+import CustomTableToolbar from "./customTableToolbar.jsx";
+import "../css/ds.css";
+
+class DSTable extends React.Component {
+    // props:
+    // getColumns={this.getColumns}
+    // fieldsToSearch={this.state.fieldsToSearch}
+    // searchField={this.state.searchField}
+    // rowKey
+    // rows: table rows
+    //
+    constructor(props) {
+        super(props);
+
+        // Point the transform to your sortingColumns. React state can work for this purpose
+        // but you can use a state manager as well.
+        const getSortingColumns = () => this.state.sortingColumns || {};
+        let pagination_list = [6, 12, 24, 48, 96];
+        let pagination_per_page = 12;
+        if (this.props.toolBarPagination !== undefined) {
+            pagination_list = this.props.toolBarPagination;
+        }
+        if (this.props.toolBarPaginationPerPage !== undefined) {
+            pagination_per_page = this.props.toolBarPaginationPerPage;
+        }
+
+        const sortableTransform = sort.sort({
+            getSortingColumns,
+            onSort: selectedColumn => {
+                this.setState({
+                    sortingColumns: sort.byColumn({
+                        sortingColumns: this.state.sortingColumns,
+                        sortingOrder: defaultSortingOrder,
+                        selectedColumn
+                    })
+                });
+            },
+            // Use property or index dependening on the sortingColumns structure specified
+            strategy: sort.strategies.byProperty
+        });
+
+        const sortingFormatter = sort.header({
+            sortableTransform,
+            getSortingColumns,
+            strategy: sort.strategies.byProperty
+        });
+
+        // Update column formatter stuff
+        let customColumns = this.props.getColumns();
+        for (let customColumn of customColumns) {
+            if (customColumn.header.formatters.length == 0) {
+                customColumn.header.formatters = [sortingFormatter];
+                customColumn.header.transforms = [sortableTransform];
+            }
+        }
+
+        // Enables our custom header formatters extensions to reactabular
+        this.customHeaderFormatters = customHeaderFormattersDefinition;
+
+        this.handleSearchValueChange = this.handleSearchValueChange.bind(this);
+        this.totalPages = this.totalPages.bind(this);
+        this.onPageInput = this.onPageInput.bind(this);
+        this.onSubmit = this.onSubmit.bind(this);
+        this.setPage = this.setPage.bind(this);
+        this.onPerPageSelect = this.onPerPageSelect.bind(this);
+        this.onFirstPage = this.onFirstPage.bind(this);
+        this.onPreviousPage = this.onPreviousPage.bind(this);
+        this.onNextPage = this.onNextPage.bind(this);
+        this.onLastPage = this.onLastPage.bind(this);
+        this.currentRows = this.currentRows.bind(this);
+        this.filteredSearchedRows = this.filteredSearchedRows.bind(this);
+
+        this.state = {
+            searchFilterValue: "",
+            fieldsToSearch: this.props.fieldsToSearch,
+            // Sort the first column in an ascending way by default.
+            sortingColumns: {
+                name: {
+                    direction: TABLE_SORT_DIRECTION.ASC,
+                    position: 0
+                }
+            },
+            columns: customColumns,
+
+            // pagination default states
+            pagination: {
+                page: 1,
+                perPage: pagination_per_page,
+                perPageOptions: pagination_list
+            },
+
+            // page input value
+            pageChangeValue: 1
+        };
+    }
+
+    handleSearchValueChange(event) {
+        this.setState({ searchFilterValue: event.target.value });
+    }
+
+    totalPages() {
+        const { rows } = this.props;
+        const { perPage } = this.state.pagination;
+        return Math.ceil(rows.length / perPage);
+    }
+
+    onPageInput(e) {
+        this.setState({ pageChangeValue: e.target.value });
+    }
+
+    onSubmit() {
+        this.setPage(this.state.pageChangeValue);
+    }
+
+    setPage(value) {
+        const page = Number(value);
+        if (
+            !Number.isNaN(value) &&
+            value !== "" &&
+            page > 0 &&
+            page <= this.totalPages()
+        ) {
+            let newPaginationState = Object.assign({}, this.state.pagination);
+            newPaginationState.page = page;
+            this.setState({
+                pagination: newPaginationState,
+                pageChangeValue: page
+            });
+        }
+    }
+
+    onPerPageSelect(eventKey, e) {
+        let newPaginationState = Object.assign({}, this.state.pagination);
+        newPaginationState.perPage = eventKey;
+        newPaginationState.page = 1;
+        this.setState({ pagination: newPaginationState });
+    }
+
+    onFirstPage() {
+        this.setPage(1);
+    }
+
+    onPreviousPage() {
+        if (this.state.pagination.page > 1) {
+            this.setPage(this.state.pagination.page - 1);
+        }
+    }
+
+    onNextPage() {
+        const { page } = this.state.pagination;
+        if (page < this.totalPages()) {
+            this.setPage(this.state.pagination.page + 1);
+        }
+    }
+
+    onLastPage() {
+        const { page } = this.state.pagination;
+        const totalPages = this.totalPages();
+        if (page < totalPages) {
+            this.setPage(totalPages);
+        }
+    }
+
+    currentRows(filteredRows) {
+        const { sortingColumns, columns, pagination } = this.state;
+        return compose(
+            paginate(pagination),
+            sort.sorter({
+                columns: columns,
+                sortingColumns,
+                sort: orderBy,
+                strategy: sort.strategies.byProperty
+            })
+        )(filteredRows);
+    }
+
+    filteredSearchedRows() {
+        const { rows } = this.props;
+        const { fieldsToSearch, searchFilterValue } = this.state;
+        if (searchFilterValue) {
+            return searchFilter(searchFilterValue, fieldsToSearch, rows);
+        }
+        return rows;
+    }
+
+    render() {
+        const {
+            columns,
+            pagination,
+            sortingColumns,
+            pageChangeValue
+        } = this.state;
+        const filteredRows = this.filteredSearchedRows();
+        const sortedPaginatedRows = this.currentRows(filteredRows);
+        let dsSearchBar =
+            <CustomTableToolbar
+                searchFilterValue={this.state.searchFilterValue}
+                handleValueChange={this.handleSearchValueChange}
+                children={this.props.toolBarChildren}
+                className={this.props.toolBarClassName}
+                placeholder={this.props.toolBarPlaceholder}
+                modelToSearch={this.props.toolBarSearchField}
+                loading={this.props.toolBarLoading}
+                disableLoadingSpinner={this.props.toolBarDisableLoadingSpinner}
+            />;
+        if (this.props.noSearchBar) {
+            dsSearchBar = "";
+        }
+
+        return (
+            <div>
+                {dsSearchBar}
+                <Table.PfProvider
+                    className="display ds-db-table"
+                    striped
+                    hover
+                    dataTable
+                    columns={columns}
+                    components={{
+                        header: {
+                            cell: cellProps => {
+                                return this.customHeaderFormatters({
+                                    cellProps,
+                                    columns,
+                                    sortingColumns,
+                                    rows: sortedPaginatedRows.rows
+                                });
+                            }
+                        }
+                    }}
+                >
+                    <Table.Header
+                        className="ds-table-header"
+                        headerRows={resolve.headerRows({ columns })}
+                    />
+                    <Table.Body
+                        rows={sortedPaginatedRows.rows}
+                        rowKey={this.props.rowKey}
+                        onRow={() => ({
+                            role: "row"
+                        })}
+                    />
+                </Table.PfProvider>
+                <PaginationRow
+                    viewType={PAGINATION_VIEW.TABLE}
+                    className="ds-table-pagination"
+                    pagination={pagination}
+                    pageInputValue={pageChangeValue}
+                    amountOfPages={sortedPaginatedRows.amountOfPages}
+                    itemCount={sortedPaginatedRows.itemCount}
+                    itemsStart={sortedPaginatedRows.itemsStart}
+                    itemsEnd={sortedPaginatedRows.itemsEnd}
+                    onPerPageSelect={this.onPerPageSelect}
+                    onFirstPage={this.onFirstPage}
+                    onPreviousPage={this.onPreviousPage}
+                    onPageInput={this.onPageInput}
+                    onNextPage={this.onNextPage}
+                    onLastPage={this.onLastPage}
+                    onSubmit={this.onSubmit}
+                    id={this.props.searchField}
+                />
+            </div>
+        );
+    }
+}
+
+class DSShortTable extends React.Component {
+    // This table is designed for smaller tables that don't need pagination or filtering,
+    // and can be empty.  So log a nice "empty" value we need the columns to be dynamic
+    // and relaoded every time we render
+    constructor(props) {
+        super(props);
+
+        // Enables our custom header formatters extensions to reactabular
+        this.customHeaderFormatters = customHeaderFormattersDefinition;
+        this.currentRows = this.currentRows.bind(this);
+
+        this.state = {
+            // Sort the first column in an ascending way by default.
+            sortingColumns: {
+                name: {
+                    direction: TABLE_SORT_DIRECTION.ASC,
+                    position: 0
+                }
+            },
+        };
+    }
+
+    currentRows(rows, columns) {
+        const { sortingColumns } = this.state;
+        return compose(
+            sort.sorter({
+                columns: columns,
+                sortingColumns,
+                sort: orderBy,
+                strategy: sort.strategies.byProperty
+            })
+        )(rows);
+    }
+
+    render() {
+        const sortingColumns = this.state.sortingColumns;
+        const getSortingColumns = () => this.state.sortingColumns || {};
+        const sortableTransform = sort.sort({
+            getSortingColumns,
+            onSort: selectedColumn => {
+                this.setState({
+                    sortingColumns: sort.byColumn({
+                        sortingColumns: this.state.sortingColumns,
+                        sortingOrder: defaultSortingOrder,
+                        selectedColumn
+                    })
+                });
+            },
+            // Use property or index dependening on the sortingColumns structure specified
+            strategy: sort.strategies.byProperty
+        });
+
+        const sortingFormatter = sort.header({
+            sortableTransform,
+            getSortingColumns,
+            strategy: sort.strategies.byProperty
+        });
+
+        let columns = this.props.getColumns();
+        for (let column of columns) {
+            if (column.header.formatters.length == 0) {
+                column.header.formatters = [sortingFormatter];
+                column.header.transforms = [sortableTransform];
+            }
+        }
+        const sortedRows = this.currentRows(this.props.rows, columns);
+
+        return (
+            <div>
+                <Table.PfProvider
+                    className="display ds-db-table"
+                    striped
+                    hover
+                    dataTable
+                    columns={columns}
+                    components={{
+                        header: {
+                            cell: cellProps => {
+                                return this.customHeaderFormatters({
+                                    cellProps,
+                                    columns,
+                                    sortingColumns,
+                                    rows: sortedRows.rows
+                                });
+                            }
+                        }
+                    }}
+                >
+                    <Table.Header
+                        className="ds-table-header"
+                        headerRows={resolve.headerRows({ columns })}
+                    />
+                    <Table.Body
+                        rows={sortedRows}
+                        rowKey={this.props.rowKey}
+                        onRow={() => ({
+                            role: "row"
+                        })}
+                    />
+                </Table.PfProvider>
+            </div>
+        );
+    }
+}
+
+// Properties
+
+DSTable.propTypes = {
+    getColumns: PropTypes.func,
+    fieldsToSearch: PropTypes.array,
+    rowKey: PropTypes.string,
+    rows: PropTypes.array,
+    toolBarSearchField: PropTypes.string,
+    toolBarChildren: PropTypes.any,
+    toolBarClassName: PropTypes.string,
+    toolBarPlaceholder: PropTypes.string,
+    toolBarLoading: PropTypes.bool,
+    toolBarDisableLoadingSpinner: PropTypes.bool,
+    toolBarPagination: PropTypes.array,
+    toolBarPaginationPerPage: PropTypes.number,
+    noSearchBar: PropTypes.bool
+};
+
+DSShortTable.propTypes = {
+    getColumns: PropTypes.func,
+    rowKey: PropTypes.string,
+    rows: PropTypes.array
+};
+
+export { DSTable, DSShortTable };
diff --git a/src/cockpit/389-console/src/lib/notifications.jsx b/src/cockpit/389-console/src/lib/notifications.jsx
index 06ad141..a2b23e5 100644
--- a/src/cockpit/389-console/src/lib/notifications.jsx
+++ b/src/cockpit/389-console/src/lib/notifications.jsx
@@ -1,6 +1,8 @@
 import React from "react";
 import PropTypes from "prop-types";
 import {
+    Icon,
+    MessageDialog,
     TimedToastNotification,
     ToastNotificationList
 } from "patternfly-react";
@@ -8,7 +10,6 @@ import {
 class NotificationController extends React.Component {
     render() {
         const { notifications, removeNotificationAction } = this.props;
-
         return (
             <ToastNotificationList>
                 {notifications.map(notification => (
@@ -23,7 +24,11 @@ class NotificationController extends React.Component {
                             {notification.header && (
                                 <strong>{notification.header}</strong>
                             )}
-                            {notification.message}
+                            {notification.type == "error" ? (
+                                <pre>{notification.message}</pre>
+                            ) : (
+                                <span>{notification.message}</span>
+                            )}
                         </span>
                     </TimedToastNotification>
                 ))}
@@ -41,4 +46,61 @@ NotificationController.defaultProps = {
     notifications: []
 };
 
-export default NotificationController;
+class ConfirmPopup extends React.Component {
+    constructor(props) {
+        super(props);
+        this.state = {};
+
+        // Chaining OIDs
+        this.primaryAction = this.primaryAction.bind(this);
+    }
+
+    primaryAction() {
+        this.props.actionFunc(this.props.actionParam);
+        this.props.closeHandler();
+    }
+
+    render() {
+        const {
+            showModal,
+            closeHandler,
+        } = this.props;
+
+        let secondaryContent = "";
+        if (this.props.msgContent !== undefined) {
+            if (this.props.msgContent.constructor === Array) {
+                // Comma separate the lines of this list
+                secondaryContent = this.props.msgContent.map((item) =>
+                    <p key={item}><b>{item}</b></p>);
+            } else {
+                secondaryContent = <p><b>{this.props.msgContent}</b></p>;
+            }
+        }
+
+        const icon = <Icon type="pf" style={{'fontSize':'30px', 'marginRight': '15px'}}
+            name="warning-triangle-o" />;
+        const msg = <p className="lead">{this.props.msg}</p>;
+
+        return (
+            <React.Fragment>
+                <MessageDialog
+                    className="ds-confirm"
+                    show={showModal}
+                    onHide={closeHandler}
+                    primaryAction={this.primaryAction}
+                    secondaryAction={closeHandler}
+                    primaryActionButtonContent="Yes"
+                    secondaryActionButtonContent="No"
+                    title="Confirmation"
+                    icon={icon}
+                    primaryContent={msg}
+                    secondaryContent={secondaryContent}
+                    accessibleName="questionDialog"
+                    accessibleDescription="questionDialogContent"
+                />
+            </React.Fragment>
+        );
+    }
+}
+
+export { NotificationController, ConfirmPopup };
diff --git a/src/cockpit/389-console/src/lib/plugins/pluginModal.jsx b/src/cockpit/389-console/src/lib/plugins/pluginModal.jsx
index d8358e9..7b21201 100644
--- a/src/cockpit/389-console/src/lib/plugins/pluginModal.jsx
+++ b/src/cockpit/389-console/src/lib/plugins/pluginModal.jsx
@@ -67,7 +67,7 @@ class PluginEditModal extends React.Component {
                                 controlId="currentPluginEnabled"
                                 disabled={false}
                             >
-                                <Col componentClass={ControlLabel} sm={6}>
+                                <Col componentClass={ControlLabel} sm={5}>
                                     Plugin Status
                                 </Col>
                                 <Col sm={6}>
@@ -83,7 +83,7 @@ class PluginEditModal extends React.Component {
                             </FormGroup>
                             {Object.entries(modalFields).map(([id, value]) => (
                                 <FormGroup key={id} controlId={id} disabled={false}>
-                                    <Col componentClass={ControlLabel} sm={6}>
+                                    <Col componentClass={ControlLabel} sm={5}>
                                         Plugin {id.replace("currentPlugin", "")}
                                     </Col>
                                     <Col sm={6}>
diff --git a/src/cockpit/389-console/src/lib/plugins/pluginTable.jsx b/src/cockpit/389-console/src/lib/plugins/pluginTable.jsx
index ca69207..6c29e6b 100644
--- a/src/cockpit/389-console/src/lib/plugins/pluginTable.jsx
+++ b/src/cockpit/389-console/src/lib/plugins/pluginTable.jsx
@@ -1,82 +1,22 @@
 import React from "react";
 import {
-    PaginationRow,
-    paginate,
-    Table,
     Button,
     noop,
     actionHeaderCellFormatter,
-    customHeaderFormattersDefinition,
-    defaultSortingOrder,
     sortableHeaderCellFormatter,
     tableCellFormatter,
-    TABLE_SORT_DIRECTION,
-    PAGINATION_VIEW
 } from "patternfly-react";
 import PropTypes from "prop-types";
-import { orderBy } from "lodash";
-import * as sort from "sortabular";
-import * as resolve from "table-resolver";
-import { compose } from "recompose";
-import { searchFilter } from "../tools.jsx";
-import CustomTableToolbar from "../customTableToolbar.jsx";
+import { DSTable } from "../dsTable.jsx";
 import "../../css/ds.css";
 
 class PluginTable extends React.Component {
     constructor(props) {
         super(props);
 
-        // Point the transform to your sortingColumns. React state can work for this purpose
-        // but you can use a state manager as well.
-        const getSortingColumns = () => this.state.sortingColumns || {};
-
-        const sortableTransform = sort.sort({
-            getSortingColumns,
-            onSort: selectedColumn => {
-                this.setState({
-                    sortingColumns: sort.byColumn({
-                        sortingColumns: this.state.sortingColumns,
-                        sortingOrder: defaultSortingOrder,
-                        selectedColumn
-                    })
-                });
-            },
-            // Use property or index dependening on the sortingColumns structure specified
-            strategy: sort.strategies.byProperty
-        });
-
-        const sortingFormatter = sort.header({
-            sortableTransform,
-            getSortingColumns,
-            strategy: sort.strategies.byProperty
-        });
-
-        // Enables our custom header formatters extensions to reactabular
-        this.customHeaderFormatters = customHeaderFormattersDefinition;
-
-        this.handleSearchValueChange = this.handleSearchValueChange.bind(this);
-        this.totalPages = this.totalPages.bind(this);
-        this.onPageInput = this.onPageInput.bind(this);
-        this.onSubmit = this.onSubmit.bind(this);
-        this.setPage = this.setPage.bind(this);
-        this.onPerPageSelect = this.onPerPageSelect.bind(this);
-        this.onFirstPage = this.onFirstPage.bind(this);
-        this.onPreviousPage = this.onPreviousPage.bind(this);
-        this.onNextPage = this.onNextPage.bind(this);
-        this.onLastPage = this.onLastPage.bind(this);
-        this.currentRows = this.currentRows.bind(this);
-        this.filteredSearchedRows = this.filteredSearchedRows.bind(this);
-
         this.state = {
             searchFilterValue: "",
             fieldsToSearch: ["cn", "nsslapd-pluginType"],
-            // Sort the first column in an ascending way by default.
-            sortingColumns: {
-                name: {
-                    direction: TABLE_SORT_DIRECTION.ASC,
-                    position: 0
-                }
-            },
             columns: [
                 {
                     property: "cn",
@@ -88,8 +28,8 @@ class PluginTable extends React.Component {
                             colSpan: 1,
                             sort: true
                         },
-                        transforms: [sortableTransform],
-                        formatters: [sortingFormatter],
+                        transforms: [],
+                        formatters: [],
                         customFormatters: [sortableHeaderCellFormatter]
                     },
                     cell: {
@@ -109,8 +49,8 @@ class PluginTable extends React.Component {
                             colSpan: 1,
                             sort: true
                         },
-                        transforms: [sortableTransform],
-                        formatters: [sortingFormatter],
+                        transforms: [],
+                        formatters: [],
                         customFormatters: [sortableHeaderCellFormatter]
                     },
                     cell: {
@@ -130,8 +70,8 @@ class PluginTable extends React.Component {
                             colSpan: 1,
                             sort: true
                         },
-                        transforms: [sortableTransform],
-                        formatters: [sortingFormatter],
+                        transforms: [],
+                        formatters: [],
                         customFormatters: [sortableHeaderCellFormatter]
                     },
                     cell: {
@@ -176,173 +116,24 @@ class PluginTable extends React.Component {
                     }
                 }
             ],
-
-            // pagination default states
-            pagination: {
-                page: 1,
-                perPage: 12,
-                perPageOptions: [6, 12, 24]
-            },
-
-            // page input value
-            pageChangeValue: 1
         };
+        this.getColumns = this.getColumns.bind(this);
     }
 
-    handleSearchValueChange(event) {
-        this.setState({ searchFilterValue: event.target.value });
-    }
-
-    totalPages() {
-        const { rows } = this.props;
-        const { perPage } = this.state.pagination;
-        return Math.ceil(rows.length / perPage);
-    }
-
-    onPageInput(e) {
-        this.setState({ pageChangeValue: e.target.value });
-    }
-
-    onSubmit() {
-        this.setPage(this.state.pageChangeValue);
-    }
-
-    setPage(value) {
-        const page = Number(value);
-        if (
-            !Number.isNaN(value) &&
-            value !== "" &&
-            page > 0 &&
-            page <= this.totalPages()
-        ) {
-            let newPaginationState = Object.assign({}, this.state.pagination);
-            newPaginationState.page = page;
-            this.setState({
-                pagination: newPaginationState,
-                pageChangeValue: page
-            });
-        }
-    }
-
-    onPerPageSelect(eventKey, e) {
-        let newPaginationState = Object.assign({}, this.state.pagination);
-        newPaginationState.perPage = eventKey;
-        newPaginationState.page = 1;
-        this.setState({ pagination: newPaginationState });
-    }
-
-    onFirstPage() {
-        this.setPage(1);
-    }
-
-    onPreviousPage() {
-        if (this.state.pagination.page > 1) {
-            this.setPage(this.state.pagination.page - 1);
-        }
-    }
-
-    onNextPage() {
-        const { page } = this.state.pagination;
-        if (page < this.totalPages()) {
-            this.setPage(this.state.pagination.page + 1);
-        }
-    }
-
-    onLastPage() {
-        const { page } = this.state.pagination;
-        const totalPages = this.totalPages();
-        if (page < totalPages) {
-            this.setPage(totalPages);
-        }
-    }
-
-    currentRows(filteredRows) {
-        const { sortingColumns, columns, pagination } = this.state;
-        return compose(
-            paginate(pagination),
-            sort.sorter({
-                columns: columns,
-                sortingColumns,
-                sort: orderBy,
-                strategy: sort.strategies.byProperty
-            })
-        )(filteredRows);
-    }
-
-    filteredSearchedRows() {
-        const { rows } = this.props;
-        const { fieldsToSearch, searchFilterValue } = this.state;
-        if (searchFilterValue) {
-            return searchFilter(searchFilterValue, fieldsToSearch, rows);
-        }
-        return rows;
+    getColumns() {
+        return this.state.columns;
     }
 
     render() {
-        const {
-            columns,
-            pagination,
-            sortingColumns,
-            pageChangeValue
-        } = this.state;
-
-        const filteredRows = this.filteredSearchedRows();
-        const sortedPaginatedRows = this.currentRows(filteredRows);
-
         return (
             <div>
-                <CustomTableToolbar
-                    modelToSearch="Plugins"
-                    searchFilterValue={this.state.searchFilterValue}
-                    handleValueChange={this.handleSearchValueChange}
-                    disableLoadingSpinner
-                />
-                <Table.PfProvider
-                    className="display ds-repl-table"
-                    striped
-                    hover
-                    dataTable
-                    columns={columns}
-                    components={{
-                        header: {
-                            cell: cellProps => {
-                                return this.customHeaderFormatters({
-                                    cellProps,
-                                    columns,
-                                    sortingColumns,
-                                    rows: sortedPaginatedRows.rows
-                                });
-                            }
-                        }
-                    }}
-                >
-                    <Table.Header
-                        className="ds-table-header"
-                        headerRows={resolve.headerRows({ columns })}
-                    />
-                    <Table.Body
-                        rows={sortedPaginatedRows.rows}
-                        rowKey="cn"
-                        onRow={() => ({
-                            role: "row"
-                        })}
-                    />
-                </Table.PfProvider>
-                <PaginationRow
-                    viewType={PAGINATION_VIEW.TABLE}
-                    pagination={pagination}
-                    pageInputValue={pageChangeValue}
-                    amountOfPages={sortedPaginatedRows.amountOfPages}
-                    itemCount={sortedPaginatedRows.itemCount}
-                    itemsStart={sortedPaginatedRows.itemsStart}
-                    itemsEnd={sortedPaginatedRows.itemsEnd}
-                    onPerPageSelect={this.onPerPageSelect}
-                    onFirstPage={this.onFirstPage}
-                    onPreviousPage={this.onPreviousPage}
-                    onPageInput={this.onPageInput}
-                    onNextPage={this.onNextPage}
-                    onLastPage={this.onLastPage}
-                    onSubmit={this.onSubmit}
+                <DSTable
+                    getColumns={this.getColumns}
+                    fieldsToSearch={this.state.fieldsToSearch}
+                    rowKey="cn"
+                    rows={this.props.rows}
+                    toolBarSearchField="Plugins"
+                    toolBarDisableLoadingSpinner
                 />
             </div>
         );
diff --git a/src/cockpit/389-console/src/monitor.html b/src/cockpit/389-console/src/monitor.html
index 4ce889b..ba35e5c 100644
--- a/src/cockpit/389-console/src/monitor.html
+++ b/src/cockpit/389-console/src/monitor.html
@@ -536,7 +536,7 @@
       <option>10000</option>
     </select><button id="accesslog-refresh-btn" class="ds-adj-btn">Refresh</button><label
       class="ds-left-margin">Continuously Refresh<input type="checkbox" class="ds-sm-left-margin" id="accesslog-cont-refresh"></label>
-    <textarea id="accesslog-area" class="ds-logarea"></textarea>
+    <textarea id="accesslog-area" class="ds-logarea" readonly></textarea>
     <p></p>
   </div>
 
@@ -557,7 +557,7 @@
       <option>10000</option>
     </select><button id="auditlog-refresh-btn" class="ds-adj-btn">Refresh</button><label
       class="ds-left-margin">Continuously Refresh<input type="checkbox" class="ds-sm-left-margin" id="auditlog-cont-refresh"></label>
-    <textarea id="auditlog-area" class="ds-logarea"></textarea>
+    <textarea id="auditlog-area" class="ds-logarea" readonly></textarea>
     <p></p>
   </div>
 
@@ -578,7 +578,7 @@
       <option>10000</option>
     </select><button id="auditfaillog-refresh-btn" class="ds-adj-btn">Refresh</button><label
       class="ds-left-margin">Continuously Refresh<input type="checkbox" class="ds-sm-left-margin" id="auditfaillog-cont-refresh"></label>
-    <textarea id="auditfaillog-area" class="ds-logarea"></textarea>
+    <textarea id="auditfaillog-area" class="ds-logarea" readonly></textarea>
     <p></p>
   </div>
 
@@ -616,7 +616,7 @@
           <option>Debug</option>
         </select>
       </div>
-    <textarea id="errorslog-area" class="ds-logarea"></textarea>
+    <textarea id="errorslog-area" class="ds-logarea" readonly></textarea>
     <p></p>
   </div>
 
@@ -914,5 +914,3 @@
       </div>
     </div>
   </div>
-
-
diff --git a/src/cockpit/389-console/src/plugins.jsx b/src/cockpit/389-console/src/plugins.jsx
index 2b455ba..d2b6932 100644
--- a/src/cockpit/389-console/src/plugins.jsx
+++ b/src/cockpit/389-console/src/plugins.jsx
@@ -17,7 +17,7 @@ import ReferentialIntegrity from "./lib/plugins/referentialIntegrity.jsx";
 import RetroChangelog from "./lib/plugins/retroChangelog.jsx";
 import RootDNAccessControl from "./lib/plugins/rootDNAccessControl.jsx";
 import USN from "./lib/plugins/usn.jsx";
-import NotificationController from "./lib/notifications.jsx";
+import { NotificationController } from "./lib/notifications.jsx";
 import "./css/ds.css";
 
 var cmd;
diff --git a/src/cockpit/389-console/src/servers.html b/src/cockpit/389-console/src/servers.html
index ef647fe..7d3c745 100644
--- a/src/cockpit/389-console/src/servers.html
+++ b/src/cockpit/389-console/src/servers.html
@@ -169,7 +169,7 @@
     <p></p>
 
     <div class="ds-footer">
-      <button class="btn btn-primary save-button">Save</button>
+      <button class="btn btn-primary save-button">Save Configuration</button>
     </div>
   </div>
 
diff --git a/src/cockpit/389-console/src/servers.js b/src/cockpit/389-console/src/servers.js
index 204a14d..4d1865c 100644
--- a/src/cockpit/389-console/src/servers.js
+++ b/src/cockpit/389-console/src/servers.js
@@ -1313,7 +1313,7 @@ $(document).ready( function() {
 
       // First check if backup name is already used
       var check_cmd = [DSCTL, '-j', server_id, 'backups'];
-      log_cmd('#restore-server-btn (click)', 'Restore server instance', check_cmd);
+      log_cmd('#ds-backup-btn (click)', 'Check backup name', check_cmd);
       cockpit.spawn(check_cmd, { superuser: true, "err": "message", "environ": [ENV]}).done(function(data) {
         var obj = JSON.parse(data);
         var found_backup = false;
diff --git a/src/cockpit/389-console/webpack.config.js b/src/cockpit/389-console/webpack.config.js
index 2387cd9..8c89041 100644
--- a/src/cockpit/389-console/webpack.config.js
+++ b/src/cockpit/389-console/webpack.config.js
@@ -24,8 +24,6 @@ var info = {
         index: ["./index.es6"]
     },
     files: [
-        "backend.html",
-        "backend.js",
         "banner.html",
         "css",
         "ds.js",
diff --git a/src/lib389/lib389/__init__.py b/src/lib389/lib389/__init__.py
index 470d252..36b4c12 100644
--- a/src/lib389/lib389/__init__.py
+++ b/src/lib389/lib389/__init__.py
@@ -484,7 +484,6 @@ class DirSrv(SimpleLDAPObject, object):
         self.serverid = serverid
 
         # Do we have ldapi settings?
-        # Do we really need .strip() on this?
         self.ldapi_enabled = None
         self.ldapi_socket = None
 
@@ -573,7 +572,7 @@ class DirSrv(SimpleLDAPObject, object):
             # The lack of this value basically rules it out in most cases
             self.ds_paths = Paths(instance=self)
         else:
-            self.ds_paths = Paths(args[SER_SERVERID_PROP], instance=self)
+            self.ds_paths = Paths(serverid=args[SER_SERVERID_PROP], instance=self)
             # Settings from args of server attributes
             self.serverid = args.get(SER_SERVERID_PROP, None)
             # Probably local?
@@ -748,6 +747,10 @@ class DirSrv(SimpleLDAPObject, object):
         elif serverid is not None:
             serverid = serverid.replace('slapd-', '')
 
+        if self.serverid is None:
+            # Need to set the Paths in case it does exist
+            self.ds_paths = Paths(serverid)
+
         # list of the found instances
         instances = []
 
@@ -767,9 +770,8 @@ class DirSrv(SimpleLDAPObject, object):
                 # Now just populate that instance dict (soon to be changed ...)
                 instances.append(_parse_configfile(dse_ldif, serverid))
             else:
-                # it's not
-                self.log.debug("list instance not found: %s -> %s\n" % (serverid, dse_ldif))
-
+                # it's not=
+                self.log.debug("list instance not found in {}: {}\n".format(dse_ldif, serverid))
         else:
             # For each dir that starts with slapd-*
             potential_inst = [
@@ -2986,6 +2988,49 @@ class DirSrv(SimpleLDAPObject, object):
         self.log.debug("Deleting backup directory: ", del_dir)
         shutil.rmtree(del_dir)
 
+    def getLDIFSuffix(self, filename):
+        suffix = ""
+        with open(filename, 'r') as ldif_file:
+            for line in ldif_file:
+                if line.startswith("dn: "):
+                    parts = line.split(" ", 1)
+                    suffix = parts[1].rstrip().lower()
+                    break
+        return suffix
+
+    def ldifs(self, use_json=False):
+        # Return a list of backups from the bakdir
+        ldifdir = self.get_ldif_dir()
+        dirlist = [item for item in os.listdir(ldifdir)]
+
+        if use_json:
+            json_result = {'type': 'list', 'items': []}
+        for ldif in dirlist:
+            fullpath = ldifdir + "/" + ldif
+            ldif_date = os.path.getctime(fullpath)
+            ldif_date = datetime.fromtimestamp(ldif_date).strftime('%Y-%m-%d %H:%M:%S')
+            ldif_size = subprocess.check_output(['du', '-sh', fullpath]).split()[0].decode('utf-8')
+            ldif_suffix = self.getLDIFSuffix(fullpath)
+            if ldif_suffix == "":
+                ldif_suffix = "???"
+            if use_json:
+                json_item = [ldif, ldif_date, ldif_size, ldif_suffix]
+                json_result['items'].append(json_item)
+            else:
+                self.log.info('{} ({}), Created ({}), Size ({})'.format(ldif, ldif_suffix, ldif_date, ldif_size))
+
+        if use_json:
+            print(json.dumps(json_result))
+
+        return True
+
+    def del_ldif(self, ldifname):
+        # Delete backup directory
+        ldifdir = self.get_ldif_dir()
+        del_file = ldifdir + "/" + ldifname
+        self.log.debug("Deleting LDIF file: " + del_file)
+        os.remove(del_file)
+
     def dbscan(self, bename=None, index=None, key=None, width=None, isRaw=False):
         """Wrapper around dbscan tool that analyzes and extracts information
         from an import Directory Server database file
diff --git a/src/lib389/lib389/backend.py b/src/lib389/lib389/backend.py
index eb1d60e..7535c06 100644
--- a/src/lib389/lib389/backend.py
+++ b/src/lib389/lib389/backend.py
@@ -624,17 +624,21 @@ class Backend(DSLdapObject):
         if reindex:
             self.reindex(attr_name)
 
-    def reindex(self, attrs=None):
+    def reindex(self, attrs=None, wait=False):
         """Reindex the attributes for this backend
         :param attrs - an optional list of attributes to index
+        :param wait - Set to true to wait for task to complete
         """
+        args = None
+        if wait:
+            args = {TASK_WAIT: True}
         bename = ensure_str(self.get_attr_val_bytes('cn'))
         reindex_task = Tasks(self._instance)
-        reindex_task.reindex(benamebase=bename, attrname=attrs)
+        reindex_task.reindex(benamebase=bename, attrname=attrs, args=args)
 
     def get_encrypted_attrs(self, just_names=False):
         """Get a list of the excrypted attributes
-        :param just_names - If True only he encrypted attribute names are returned (instead of the full attribute entry)
+        :param just_names - If True only the encrypted attribute names are returned (instead of the full attribute entry)
         :returns - a list of attributes
         """
         attrs = EncryptedAttrs(self._instance, basedn=self._dn).list()
@@ -755,8 +759,7 @@ class Backends(DSLdapObjects):
         """Do an import of the suffix"""
 
         if not ldifs:
-            self.log.error("import_ldif: LDIF filename is missing")
-            return False
+            raise ValueError("import_ldif: LDIF filename is missing")
         ldif_paths = []
         for ldif in list(ldifs):
             if not ldif.startswith("/"):
@@ -800,6 +803,11 @@ class Backends(DSLdapObjects):
                 task_properties['nsFilename'] = os.path.join(self._instance.ds_paths.ldif_dir, ldif)
             else:
                 task_properties['nsFilename'] = os.path.join(self._instance.ds_paths.ldif_dir, "%s.ldif" % ldif)
+        elif ldif is not None and ldif.startswith("/"):
+            if ldif.endswith(".ldif"):
+                task_properties['nsFilename'] = ldif
+            else:
+                task_properties['nsFilename'] = "%s.ldif" % ldif
         else:
             tnow = datetime.now().strftime("%Y_%m_%d_%H_%M_%S")
             task_properties['nsFilename'] = os.path.join(self._instance.ds_paths.ldif_dir,
diff --git a/src/lib389/lib389/chaining.py b/src/lib389/lib389/chaining.py
index c528df8..35949d3 100644
--- a/src/lib389/lib389/chaining.py
+++ b/src/lib389/lib389/chaining.py
@@ -11,8 +11,10 @@ from lib389._constants import *
 from lib389.properties import *
 from lib389.utils import ensure_str
 from lib389.monitor import MonitorChaining
+from lib389.mappingTree import MappingTrees
 from lib389._mapped_object import DSLdapObjects, DSLdapObject
 from lib389.backend import Backends
+from lib389.rootdse import RootDSE
 
 
 class ChainingConfig(DSLdapObject):
@@ -36,24 +38,22 @@ class ChainingConfig(DSLdapObject):
         self._protected = True
         self._dn = "cn=config,cn=chaining database,cn=plugins,cn=config"
 
-    # Contorl OIDS from rootdsde - > supportedControl
-    # Set nstransmittedcontrols
-
-    # Chaining comps:  nspossiblechainingcomponents
-    # Set comps:  nsactivechainingcomponents (DN)
-
-    def get_controls(self, use_json=False):
+    def get_controls(self):
         """Get a list of the supported controls from the root DSE entry
         :return list of OIDs
         """
-        rootdse = self._instance.search_s("", ldap.SCOPE_BASE, self._object_filter, ['supportedControl'])[0]
-        return rootdse.get_attr_vals('supportedControl', use_json)
+        rootdse = RootDSE(self._instance)
+        ctrls = rootdse.get_supported_ctrls()
+        ctrls.sort()
+        return ctrls
 
-    def get_comps(self, use_json=False):
+    def get_comps(self):
         """Return a list of the available plugin components
         :return list of plugin components
         """
-        return self.get_attr_vals('nspossiblechainingcomponents', use_json)
+        comps = self.get_attr_vals_utf8_l('nspossiblechainingcomponents')
+        comps.sort()
+        return comps
 
 
 class ChainingDefault(DSLdapObject):
@@ -100,6 +100,7 @@ class ChainingLink(DSLdapObject):
         self._create_objectclasses = ['top', 'extensibleObject', BACKEND_OBJECTCLASS_VALUE]
         self._protected = False
         self._basedn = "cn=chaining database,cn=plugins,cn=config"
+        self._mts = MappingTrees(self._instance)
 
     def get_monitor(self, rdn):
         """Get a MonitorChaining(DSLdapObject) for the chaining link
@@ -120,19 +121,13 @@ class ChainingLink(DSLdapObject):
         Delete chaining entry
         """
 
-        suffix = ensure_str(self.get_attr_val('nsslapd-suffix')).lower()
-        rdn = ensure_str(self.get_attr_val('cn')).lower()
-        be_insts = Backends(self._instance).list()
-        for be in be_insts:
-            be_suffix = ensure_str(be.get_attr_val('nsslapd-suffix')).lower()
-            if suffix == be_suffix:
-                # Remove chaining link backend
-                try:
-                    be.remove('nsslapd-backend', rdn)
-                except ldap.NO_SUCH_ATTRIBUTE:
-                    # It's not set in the backend, that's okay
-                    pass
-                break
+        rdn = self.get_attr_val_utf8_l('cn')
+        try:
+            mt = self._mts.get(selector=rdn)
+            mt.delete()
+        except ldap.NO_SUCH_OBJECT:
+            # Righto, it's already gone! Do nothing ...
+            pass
 
         # Delete the monitoring entry
         monitor = self.get_monitor(rdn)
@@ -141,6 +136,27 @@ class ChainingLink(DSLdapObject):
         # Delete the link
         self.delete()
 
+    def create(self, rdn=None, properties=None, basedn=None):
+        """Create the link entry, and the mapping tree entry(if needed)
+        """
+
+        # Create chaining entry
+        super(ChainingLink, self).create(rdn, properties, basedn)
+
+        # Create mapping tree entry
+        dn_comps = ldap.explode_dn(properties['nsslapd-suffix'][0])
+        parent_suffix = ','.join(dn_comps[1:])
+        mt_properties = {
+            'cn': properties['nsslapd-suffix'][0],
+            'nsslapd-state': 'backend',
+            'nsslapd-backend': properties['cn'][0],
+            'nsslapd-parent-suffix': parent_suffix
+        }
+        try:
+            self._mts.ensure_state(properties=mt_properties)
+        except ldap.ALREADY_EXISTS:
+            pass
+
 
 class ChainingLinks(DSLdapObjects):
     """DSLdapObjects that represents DN_LDBM base DN
diff --git a/src/lib389/lib389/cli_conf/backend.py b/src/lib389/lib389/cli_conf/backend.py
index fdb5dd5..dbc8aa6 100644
--- a/src/lib389/lib389/cli_conf/backend.py
+++ b/src/lib389/lib389/cli_conf/backend.py
@@ -8,6 +8,7 @@
 # --- END COPYRIGHT BLOCK ---
 
 from lib389.backend import Backend, Backends, DatabaseConfig
+from lib389.chaining import (ChainingLinks)
 from lib389.index import Index, VLVIndex, VLVSearches
 from lib389.monitor import MonitorLDBM
 from lib389.utils import ensure_str, is_a_dn, is_dn_parent
@@ -53,6 +54,7 @@ arg_to_attr = {
         'rangelookthroughlimit': 'nsslapd-rangelookthroughlimit',
         'backend_opt_level': 'nsslapd-backend-opt-level',
         'deadlock_policy': 'nsslapd-db-deadlock-policy',
+        'db_home_directory': 'nsslapd-db-home-directory',
         # VLV attributes
         'search_base': 'vlvbase',
         'search_scope': 'vlvscope',
@@ -170,7 +172,7 @@ def backend_create(inst, basedn, log, args):
 
     be = Backend(inst)
     be.create(properties=props)
-    print("The database was successfully created")
+    print("The database was sucessfully created")
 
 
 def _recursively_del_backends(be):
@@ -197,7 +199,7 @@ def backend_delete(inst, basedn, log, args, warn=True):
     _recursively_del_backends(be)
     be.delete()
 
-    print("The database, and any sub-suffixes, were successfully deleted")
+    print("The database, and any sub-suffixes, were sucessfully deleted")
 
 
 def backend_import(inst, basedn, log, args):
@@ -216,7 +218,7 @@ def backend_import(inst, basedn, log, args):
     if task.is_complete() and result == 0:
         print("The import task has finished successfully")
     else:
-        raise ValueError("The import task has failed with the error code: ({})".format(result))
+        raise ValueError("Import task failed\n-------------------------\n{}".format(ensure_str(task.get_task_log())))
 
 
 def backend_export(inst, basedn, log, args):
@@ -244,7 +246,16 @@ def backend_export(inst, basedn, log, args):
     if task.is_complete() and result == 0:
         print("The export task has finished successfully")
     else:
-        raise ValueError("The export task has failed with the error code: ({})".format(result))
+        raise ValueError("Export task failed\n-------------------------\n{}".format(ensure_str(task.get_task_log())))
+
+
+def is_db_link(inst, rdn):
+    links = ChainingLinks(inst).list()
+    for link in links:
+        cn = ensure_str(link.get_attr_val('cn')).lower()
+        if cn == rdn.lower():
+            return True
+    return False
 
 
 def backend_get_subsuffixes(inst, basedn, log, args):
@@ -256,15 +267,27 @@ def backend_get_subsuffixes(inst, basedn, log, args):
             # We have our parent, now find the children
             mts = be._mts.list()
             for mt in mts:
+                db_type = "suffix"
                 sub = mt.get_attr_val_utf8_l('nsslapd-parent-suffix')
+                sub_be = mt.get_attr_val_utf8_l('nsslapd-backend')
                 if sub == be_suffix:
-                    # We have a subsuffix
+                    # We have a subsuffix (maybe a db link?)
+                    if is_db_link(inst, sub_be):
+                        db_type = "link"
+
                     if args.suffix:
-                        val = mt.get_attr_val_utf8_l('cn')
+                        subsuffixes.append(mt.get_attr_val_utf8_l('cn'))
                     else:
-                        val = ("{} ({})".format(mt.get_attr_val_utf8_l('cn'),
-                                                mt.get_attr_val_utf8_l('nsslapd-backend')))
-                    subsuffixes.append(val)
+                        if args.json:
+                            val = {"suffix": mt.get_attr_val_utf8_l('cn'),
+                                   "backend": mt.get_attr_val_utf8_l('nsslapd-backend'),
+                                   "type": db_type}
+                        else:
+                            val = ("{} ({}) Database Type: {}".format(
+                                mt.get_attr_val_utf8_l('cn'),
+                                mt.get_attr_val_utf8_l('nsslapd-backend'),
+                                db_type))
+                        subsuffixes.append(val)
             break
     if len(subsuffixes) > 0:
         subsuffixes.sort()
@@ -280,6 +303,100 @@ def backend_get_subsuffixes(inst, basedn, log, args):
             print("No sub-suffixes under this backend")
 
 
+def build_node(suffix, be_name, subsuf=False, link=False):
+    """Build the UI node for a suffix
+    """
+    icon = "glyphicon glyphicon-tree-conifer"
+    suffix_type = "suffix"
+    if subsuf:
+        icon = "glyphicon glyphicon-leaf"
+        suffix_type = "subsuffix"
+    if link:
+        icon = "glyphicon glyphicon-link"
+        suffix_type = "dblink"
+    return {
+        "text": suffix,
+        "id": suffix,
+        "selectable": True,
+        "icon": icon,
+        "type": suffix_type,
+        "be": be_name,
+        "nodes": []
+    }
+
+
+def backend_build_tree(inst, be_insts, nodes):
+    """Recursively build the tree
+    """
+    if len(nodes) == 0:
+        # Done
+        return
+
+    for node in nodes:
+        node_suffix = node['id']
+        # Get sub suffixes and chaining of node
+        for be in be_insts:
+            be_suffix = be.get_attr_val_utf8_l('nsslapd-suffix')
+            if be_suffix == node_suffix.lower():
+                # We have our parent, now find the children
+                mts = be._mts.list()
+                for mt in mts:
+                    sub = mt.get_attr_val_utf8_l('nsslapd-parent-suffix')
+                    sub_be = mt.get_attr_val_utf8_l('nsslapd-backend')
+                    if sub == be_suffix:
+                        # We have a subsuffix (maybe a db link?)
+                        link = False
+                        if is_db_link(inst, sub_be):
+                            link = True
+                        node['nodes'].append(build_node(mt.get_attr_val_utf8_l('cn'), sub_be, subsuf=True, link=link))
+
+                # Recurse over the new subsuffixes
+                backend_build_tree(inst, be_insts, node['nodes'])
+                break
+
+
+def print_suffix_tree(nodes, level):
+    """Print all the nodes and children recursively
+    """
+    if len(nodes) > 0:
+        for node in nodes:
+            spaces = " " * level
+            print('{}- {}'.format(spaces, node['id']))
+            if len(node['nodes']) > 0:
+                print_suffix_tree(node['nodes'], level + 2)
+
+
+def backend_get_tree(inst, basedn, log, args):
+    """Build a tree model of all the suffixes/sub suffixes nad DB links
+    """
+    nodes = []
+
+    # Get the top suffixes
+    be_insts = MANY(inst).list()
+    for be in be_insts:
+        suffix = be.get_attr_val_utf8_l('nsslapd-suffix')
+        be_name = be.get_attr_val_utf8('cn')
+        mt = be._mts.get(suffix)
+        sub = mt.get_attr_val_utf8_l('nsslapd-parent-suffix')
+        if sub is not None:
+            continue
+        nodes.append(build_node(suffix, be_name))
+
+    # No suffixes, return empty list
+    if len(nodes) == 0:
+        return nodes
+
+    # Build the tree
+    be_insts = Backends(inst).list()
+    backend_build_tree(inst, be_insts, nodes)
+
+    # Done
+    if args.json:
+        print(json.dumps(nodes))
+    else:
+        print_suffix_tree(nodes, 1)
+
+
 def backend_set(inst, basedn, log, args):
     # Validate paried args
     if args.enable and args.disable:
@@ -303,11 +420,15 @@ def backend_set(inst, basedn, log, args):
         be.set('nsslapd-cachememsize', args.cache_memsize)
     if args.dncache_memsize:
         be.set('nsslapd-dncachememsize', args.dncache_memsize)
+    if args.require_index:
+        be.set('nsslapd-require-index', 'on')
+    if args.ignore_index:
+        be.set('nsslapd-require-index', 'off')
     if args.enable:
         be.enable()
     if args.disable:
         be.disable()
-    print("The backend configuration was successfully updated")
+    print("The backend configuration was sucessfully updated")
 
 
 def db_config_get(inst, basedn, log, args):
@@ -411,7 +532,7 @@ def backend_list_index(inst, basedn, log, args):
             if args.just_names:
                 results.append(index.get_attr_val_utf8_l('cn'))
             else:
-                results.append(index.get_all_attrs_json())
+                results.append(json.loads(index.get_all_attrs_json()))
         else:
             if args.just_names:
                 print(index.get_attr_val_utf8_l('cn'))
@@ -431,7 +552,7 @@ def backend_del_index(inst, basedn, log, args):
 
 def backend_reindex(inst, basedn, log, args):
     be = _get_backend(inst, args.be_name)
-    be.reindex(attrs=args.attr)
+    be.reindex(attrs=args.attr, wait=args.wait)
     print("Successfully reindexed database")
 
 
@@ -456,7 +577,14 @@ def backend_attr_encrypt(inst, basedn, log, args):
     if args.list:
         results = be.get_encrypted_attrs(args.just_names)
         if args.json:
-           print(json.dumps({"type": "list", "items": results}))
+            json_results = []
+            if args.just_names:
+                json_results = results
+            else:
+                for result in results:
+                    json_results.append(json.loads(result.get_all_attrs_json()))
+            print(json.dumps({"type": "list", "items": json_results}))
+
         else:
             if len(results) == 0:
                 print("There are no encrypted attributes for this backend")
@@ -479,14 +607,31 @@ def backend_list_vlv(inst, basedn, log, args):
                 results.append(vlv.get_attr_val_utf8_l('cn'))
             else:
                 entry = vlv.get_attrs_vals_json(VLV_SEARCH_ATTRS)
-                results.append(json.loads(entry))
+                indexes = vlv.get_sorts()
+                sorts = []
+                for idx in indexes:
+                    index_entry = idx.get_attrs_vals_json(VLV_INDEX_ATTRS)
+                    sorts.append(json.loads(index_entry))
+                entry = json.loads(entry)  # Return entry to a dict
+                entry["sorts"] = sorts  # Update dict
+                results.append(entry)
         else:
             if args.just_names:
                 print(vlv.get_attr_val_utf8_l('cn'))
             else:
                 raw_entry = vlv.get_attrs_vals(VLV_SEARCH_ATTRS)
+                print('dn: ' + vlv.dn)
                 for k, v in list(raw_entry.items()):
                     print('{}: {}'.format(ensure_str(k), ensure_str(v[0])))
+                indexes = vlv.get_sorts()
+                sorts = []
+                print("Sorts:")
+                for idx in indexes:
+                    entry = idx.get_attrs_vals(VLV_INDEX_ATTRS)
+                    print(' - dn: ' + idx.dn)
+                    for k, v in list(entry.items()):
+                        print(' - {}: {}'.format(ensure_str(k), ensure_str(v[0])))
+                    print()
 
     if args.json:
         print(json.dumps({"type": "list", "items": results}))
@@ -504,7 +649,6 @@ def backend_get_vlv(inst, basedn, log, args):
                 results.append(json.loads(entry))
             else:
                 raw_entry = vlv.get_attrs_vals(VLV_SEARCH_ATTRS)
-                print('VLV Search:')
                 print('dn: ' + vlv._dn)
                 for k, v in list(raw_entry.items()):
                     print('{}: {}'.format(ensure_str(k), ensure_str(v[0])))
@@ -516,10 +660,11 @@ def backend_get_vlv(inst, basedn, log, args):
                     results.append(json.loads(entry))
                 else:
                     raw_entry = idx.get_attrs_vals(VLV_INDEX_ATTRS)
-                    print('\nVLV Index:')
-                    print('dn: ' + idx._dn)
+                    print('Sorts:')
+                    print(' - dn: ' + idx._dn)
                     for k, v in list(raw_entry.items()):
-                        print('{}: {}'.format(ensure_str(k), ensure_str(v[0])))
+                        print(' - {}: {}'.format(ensure_str(k), ensure_str(v[0])))
+                    print()
 
             if args.json:
                 print(json.dumps({"type": "list", "items": results}))
@@ -568,7 +713,7 @@ def backend_create_vlv_index(inst, basedn, log, args):
     be = _get_backend(inst, args.be_name)
     vlv_search = be.get_vlv_searches(vlv_name=args.parent_name)
     vlv_search.add_sort(args.index_name, args.sort)
-    if args.index:
+    if args.index_it:
         vlv_search.reindex(args.be_name, vlv_index=args.index_name)
     print("Successfully created new VLV index entry")
 
@@ -576,7 +721,7 @@ def backend_create_vlv_index(inst, basedn, log, args):
 def backend_delete_vlv_index(inst, basedn, log, args):
     be = _get_backend(inst, args.be_name)
     vlv_search = be.get_vlv_searches(vlv_name=args.parent_name)
-    vlv_search.delete_sort(args.index_name)
+    vlv_search.delete_sort(args.index_name, args.sort)
     print("Successfully deleted VLV index entry")
 
 
@@ -625,6 +770,8 @@ def create_parser(subparsers):
     set_backend_parser.set_defaults(func=backend_set)
     set_backend_parser.add_argument('--enable-readonly', action='store_true', help='Set backend database to be read-only')
     set_backend_parser.add_argument('--disable-readonly', action='store_true', help='Disable read-only mode for backend database')
+    set_backend_parser.add_argument('--require-index', action='store_true', help='Only allow indexed searches')
+    set_backend_parser.add_argument('--ignore-index', action='store_true', help='Allow all searches even if they are unindexed')
     set_backend_parser.add_argument('--add-referral', help='Add a LDAP referral to the backend')
     set_backend_parser.add_argument('--del-referral', help='Remove a LDAP referral to the backend')
     set_backend_parser.add_argument('--enable', action='store_true', help='Enable the backend database')
@@ -643,10 +790,10 @@ def create_parser(subparsers):
     # Create index
     add_index_parser = index_subcommands.add_parser('add', help='Set configuration settings for a single backend')
     add_index_parser.set_defaults(func=backend_add_index)
-    add_index_parser.add_argument('--index-type', action='append', help='An indexing type: eq, sub, pres, or approximate')
+    add_index_parser.add_argument('--index-type', required=True, action='append', help='An indexing type: eq, sub, pres, or approximate')
     add_index_parser.add_argument('--matching-rule', action='append', help='Matching rule for the index')
     add_index_parser.add_argument('--reindex', action='store_true', help='After adding new index, reindex the database')
-    add_index_parser.add_argument('--attr', help='The index attribute\'s name')
+    add_index_parser.add_argument('--attr', required=True, help='The index attribute\'s name')
     add_index_parser.add_argument('be_name', help='The backend name or suffix to delete')
 
     # Edit index
@@ -682,6 +829,7 @@ def create_parser(subparsers):
     reindex_parser = index_subcommands.add_parser('reindex', help='Reindex the database (for a single index or all indexes')
     reindex_parser.set_defaults(func=backend_reindex)
     reindex_parser.add_argument('--attr', action='append', help='The index attribute\'s name to reindex.  Skip this argument to reindex all attributes')
+    reindex_parser.add_argument('--wait', action='store_true', help='Wait for the index task to complete and report the status')
     reindex_parser.add_argument('be_name', help='The backend name or suffix to reindex')
 
     #############################################
@@ -691,7 +839,7 @@ def create_parser(subparsers):
     vlv_subcommands = vlv_parser.add_subparsers(help="action")
 
     # List VLV Searches
-    list_vlv_search_parser = vlv_subcommands.add_parser('list', help='List VLV search definition entries')
+    list_vlv_search_parser = vlv_subcommands.add_parser('list', help='List VLV search and index entries')
     list_vlv_search_parser.set_defaults(func=backend_list_vlv)
     list_vlv_search_parser.add_argument('--just-names', action='store_true', help='List just the names of the VLV search entries')
     list_vlv_search_parser.add_argument('be_name', help='The backend name of the VLV index')
@@ -709,7 +857,7 @@ def create_parser(subparsers):
     add_vlv_search_parser.set_defaults(func=backend_create_vlv)
     add_vlv_search_parser.add_argument('--name', required=True, help='Name of the VLV search entry')
     add_vlv_search_parser.add_argument('--search-base', required=True, help='The VLV search base')
-    add_vlv_search_parser.add_argument('--search-scope', required=True, help='The VLV search scope: 0 (base search), 1 (one-evel search), or 2 (subtree ssearch)')
+    add_vlv_search_parser.add_argument('--search-scope', required=True, help='The VLV search scope: 0 (base search), 1 (one-level search), or 2 (subtree search)')
     add_vlv_search_parser.add_argument('--search-filter', required=True, help='The VLV search filter')
     add_vlv_search_parser.add_argument('be_name', help='The backend name of the VLV index')
 
@@ -718,7 +866,7 @@ def create_parser(subparsers):
     edit_vlv_search_parser.set_defaults(func=backend_edit_vlv)
     edit_vlv_search_parser.add_argument('--name', required=True, help='Name of the VLV index')
     edit_vlv_search_parser.add_argument('--search-base', help='The VLV search base')
-    edit_vlv_search_parser.add_argument('--search-scope', help='The VLV search scope: 0 (base search), 1 (one-evel search), or 2 (subtree ssearch)')
+    edit_vlv_search_parser.add_argument('--search-scope', help='The VLV search scope: 0 (base search), 1 (one-level search), or 2 (subtree search)')
     edit_vlv_search_parser.add_argument('--search-filter', help='The VLV search filter')
     edit_vlv_search_parser.add_argument('--reindex', action='store_true', help='Reindex all the VLV database indexes')
     edit_vlv_search_parser.add_argument('be_name', help='The backend name of the VLV index')
@@ -731,20 +879,21 @@ def create_parser(subparsers):
 
     # Create VLV Index
     add_vlv_index_parser = vlv_subcommands.add_parser('add-index', help='Create a VLV index under a VLV search entry(parent entry).  '
-                                                                           'The VLV index just specifies the attributes to sort')
+                                                                        'The VLV index just specifies the attributes to sort')
     add_vlv_index_parser.set_defaults(func=backend_create_vlv_index)
     add_vlv_index_parser.add_argument('--parent-name', required=True, help='Name, or "cn" attribute value, of the parent VLV search entry')
     add_vlv_index_parser.add_argument('--index-name', required=True, help='Name of the new VLV index')
-    add_vlv_index_parser.add_argument('--sort', help='A space separated list of attributes to sort for this VLV index')
-    add_vlv_index_parser.add_argument('--index', action='store_true', help='Create the actual database index for this VLV index definition')
+    add_vlv_index_parser.add_argument('--sort', required=True, help='A space separated list of attributes to sort for this VLV index')
+    add_vlv_index_parser.add_argument('--index-it', action='store_true', help='Create the database index for this VLV index definition')
     add_vlv_index_parser.add_argument('be_name', help='The backend name of the VLV index')
 
     # Delete VLV Index
-    add_vlv_index_parser = vlv_subcommands.add_parser('del-index', help='Delete a VLV index under a VLV search entry(parent entry).')
-    add_vlv_index_parser.set_defaults(func=backend_delete_vlv_index)
-    add_vlv_index_parser.add_argument('--parent-name', required=True, help='Name, or "cn" attribute value, of the parent VLV search entry')
-    add_vlv_index_parser.add_argument('--index-name', required=True, help='Name of the VLV index to delete')
-    add_vlv_index_parser.add_argument('be_name', help='The backend name of the VLV index')
+    del_vlv_index_parser = vlv_subcommands.add_parser('del-index', help='Delete a VLV index under a VLV search entry(parent entry).')
+    del_vlv_index_parser.set_defaults(func=backend_delete_vlv_index)
+    del_vlv_index_parser.add_argument('--parent-name', required=True, help='Name, or "cn" attribute value, of the parent VLV search entry')
+    del_vlv_index_parser.add_argument('--index-name', help='Name of the VLV index to delete')
+    del_vlv_index_parser.add_argument('--sort', help='Delete a VLV index that has this vlvsort value')
+    del_vlv_index_parser.add_argument('be_name', help='The backend name of the VLV index')
 
     # Reindex VLV
     reindex_vlv_parser = vlv_subcommands.add_parser('reindex', help='Index/reindex the VLV database index')
@@ -784,7 +933,7 @@ def create_parser(subparsers):
     set_db_config_parser.add_argument('--directory', help='Specifies absolute path to database instance')
     set_db_config_parser.add_argument('--dbcachesize', help='Specifies the database index cache size, in bytes.')
     set_db_config_parser.add_argument('--logdirectory', help='Specifies the path to the directory that contains the database transaction logs')
-    set_db_config_parser.add_argument('--durable_txn', help='Sets whether database transaction log entries are immediately written to the disk.')
+    set_db_config_parser.add_argument('--durable-txn', help='Sets whether database transaction log entries are immediately written to the disk.')
     set_db_config_parser.add_argument('--txn-wait', help='Sets whether the server should should wait if there are no db locks available')
     set_db_config_parser.add_argument('--checkpoint-interval', help='Sets the amount of time in seconds after which the Directory Server sends a '
                                                                     'checkpoint entry to the database transaction log')
@@ -796,7 +945,7 @@ def create_parser(subparsers):
                                                               'the batch count (only works when txn-batch-val is set)')
     set_db_config_parser.add_argument('--logbufsize', help='Specifies the transaction log information buffer size')
     set_db_config_parser.add_argument('--locks', help='Sets the maximum number of database locks')
-    set_db_config_parser.add_argument('--import-cache_autosize', help='Set to "on" or "off" to automatically set the size of the import '
+    set_db_config_parser.add_argument('--import-cache-autosize', help='Set to "on" or "off" to automatically set the size of the import '
                                                                        'cache to be used during the the import process of LDIF files')
     set_db_config_parser.add_argument('--cache-autosize', help='Sets the percentage of free memory that is used in total for the database '
                                                                'and entry cache.  Set to "0" to disable this feature.')
@@ -815,6 +964,7 @@ def create_parser(subparsers):
     set_db_config_parser.add_argument('--backend-opt-level', help='WARNING this parameter can trigger experimental code to improve write '
                                                                   'performance.  Valid values are: 0, 1, 2, or 4')
     set_db_config_parser.add_argument('--deadlock-policy', help='Adjusts the backend database deadlock policy (Advanced setting)')
+    set_db_config_parser.add_argument('--db-home-directory', help='Sets the directory for the database mmapped files (Advanced setting)')
 
     #######################################################
     # Database & Suffix Monitor
@@ -900,3 +1050,9 @@ def create_parser(subparsers):
     delete_parser = subcommands.add_parser('delete', help='Delete a backend database')
     delete_parser.set_defaults(func=backend_delete)
     delete_parser.add_argument('be_name', help='The backend name or suffix to delete')
+
+    #######################################################
+    # Get Suffix Tree (for use in web console)
+    #######################################################
+    get_tree_parser = subcommands.add_parser('get-tree', help='Get a representation of the suffix tree')
+    get_tree_parser.set_defaults(func=backend_get_tree)
\ No newline at end of file
diff --git a/src/lib389/lib389/cli_conf/chaining.py b/src/lib389/lib389/cli_conf/chaining.py
index e003fe4..783a9f3 100644
--- a/src/lib389/lib389/cli_conf/chaining.py
+++ b/src/lib389/lib389/cli_conf/chaining.py
@@ -6,15 +6,13 @@
 # See LICENSE for details.
 # --- END COPYRIGHT BLOCK ---
 
+import json
 from lib389.chaining import (
     ChainingLink, ChainingLinks, ChainingConfig, ChainingDefault)
-from lib389.utils import ensure_str
 from lib389.cli_base import (
-    populate_attr_arguments,
     _generic_list,
     _generic_get,
     _get_arg,
-    _get_attributes,
     )
 
 arg_to_attr = {
@@ -29,8 +27,8 @@ arg_to_attr = {
         'return_ref': 'nsreferralonscopedsearch',
         'check_aci': 'nschecklocalaci',
         'bind_attempts': 'nsbindretrylimit',
-        'size_limit': 'nsslapd_sizelimit',
-        'time_limit': 'nsslapd_timelimit',
+        'size_limit': 'nsslapd-sizelimit',
+        'time_limit': 'nsslapd-timelimit',
         'hop_limit': 'nshoplimit',
         'response_delay': 'nsmaxresponsedelay',
         'test_response_delay': 'nsmaxtestresponsedelay',
@@ -56,8 +54,9 @@ def _get_link(inst, rdn):
     found = False
     links = ChainingLinks(inst).list()
     for link in links:
-        cn = ensure_str(link.get_attr_val('cn')).lower()
-        if cn == rdn.lower():
+        cn = link.get_attr_val_utf8_l('cn')
+        suffix = link.get_attr_val_utf8_l('nsslapd-suffix')
+        if cn == rdn.lower() or suffix == rdn.lower():
             found = True
             return link
     if not found:
@@ -66,10 +65,28 @@ def _get_link(inst, rdn):
 
 def config_get(inst, basedn, log, args):
     chain_cfg = ChainingConfig(inst)
-    if args and args.json:
-        print(chain_cfg.get_all_attrs_json())
+    if args.avail_controls or args.avail_comps:
+        if args.avail_controls:
+            ctrls = chain_cfg.get_controls()
+            if args.json:
+                print(json.dumps({"type": "list", "items": ctrls}))
+            else:
+                print("Available Components:")
+                for ctrl in ctrls:
+                    print(ctrl)
+        if args.avail_comps:
+            comps = chain_cfg.get_comps()
+            if args.json:
+                print(json.dumps({"type": "list", "items": comps}))
+            else:
+                print("Available Controls:")
+                for comp in comps:
+                    print(comp)
     else:
-        print(chain_cfg.display())
+        if args.json:
+            print(chain_cfg.get_all_attrs_json())
+        else:
+            print(chain_cfg.display())
 
 
 def config_set(inst, basedn, log, args):
@@ -78,22 +95,26 @@ def config_set(inst, basedn, log, args):
 
     # Add control
     if args.add_control is not None:
-        chain_cfg.add('nstransmittedcontrols', args.add_control)
+        for ctrl in args.add_control:
+            chain_cfg.add('nstransmittedcontrols', ctrl)
         did_something = True
 
     # Delete control
     if args.del_control is not None:
-        chain_cfg.remove('nstransmittedcontrols', args.del_control)
+        for ctrl in args.del_control:
+            chain_cfg.remove('nstransmittedcontrols', ctrl)
         did_something = True
 
     # Add component
     if args.add_comp is not None:
-        chain_cfg.add('nsactivechainingcomponents', args.add_comp)
+        for comp in args.add_comp:
+            chain_cfg.add('nsactivechainingcomponents', comp)
         did_something = True
 
     # Del component
     if args.del_comp is not None:
-        chain_cfg.remove('nsactivechainingcomponents', args.del_comp)
+        for comp in args.del_comp:
+            chain_cfg.remove('nsactivechainingcomponents', comp)
         did_something = True
 
     if did_something:
@@ -117,6 +138,10 @@ def def_config_set(inst, basedn, log, args):
     replace_list = []
 
     for attr, value in list(attrs.items()):
+        if value is False:
+            value = "off"
+        elif value is True:
+            value = "on"
         if value == "":
             # Delete value
             chain_cfg.remove_all(attr)
@@ -134,13 +159,12 @@ def def_config_set(inst, basedn, log, args):
 def create_link(inst, basedn, log, args, warn=True):
     attrs = _args_to_attrs(args)
     attrs['cn'] = args.CHAIN_NAME[0]
-    create_link = ChainingLinks(inst)
-    create_link.add_link(attrs)
+    links = ChainingLinks(inst)
+    links.add_link(attrs)
     print('Successfully created database link')
 
 
 def get_link(inst, basedn, log, args, warn=True):
-
     rdn = _get_arg(args.CHAIN_NAME[0], msg="Enter 'cn' to retrieve")
     _generic_get(inst, basedn, log.getChild('get_link'), ChainingLinks, rdn, args)
 
@@ -191,15 +215,15 @@ def create_parser(subparsers):
 
     config_get_parser = subcommands.add_parser('config-get', help='Get the chaining controls and server component lists')
     config_get_parser.set_defaults(func=config_get)
-    config_get_parser.add_argument('--avail-controls', help="List available controls for chaining")
-    config_get_parser.add_argument('--avail-comps', help="List available plugin components for chaining")
+    config_get_parser.add_argument('--avail-controls', action='store_true', help="List available controls for chaining")
+    config_get_parser.add_argument('--avail-comps', action='store_true', help="List available plugin components for chaining")
 
     config_set_parser = subcommands.add_parser('config-set', help='Set the chaining controls and server component lists')
     config_set_parser.set_defaults(func=config_set)
-    config_set_parser.add_argument('--add-control', help="Add a transmitted control OID")
-    config_set_parser.add_argument('--del-control', help="Delete a transmitted control OID")
-    config_set_parser.add_argument('--add-comp', help="Add a chaining component")
-    config_set_parser.add_argument('--del-comp', help="Delete a chaining component")
+    config_set_parser.add_argument('--add-control', action='append', help="Add a transmitted control OID")
+    config_set_parser.add_argument('--del-control', action='append', help="Delete a transmitted control OID")
+    config_set_parser.add_argument('--add-comp', action='append', help="Add a chaining component")
+    config_set_parser.add_argument('--del-comp', action='append', help="Delete a chaining component")
 
     def_config_get_parser = subcommands.add_parser('config-get-def', help='Get the default creation parameters for new database links')
     def_config_get_parser.set_defaults(func=def_config_get)
@@ -225,7 +249,7 @@ def create_parser(subparsers):
     def_config_set_parser.add_argument('--response-delay',
         help="The maximum amount of time it can take a remote server to respond to an LDAP operation request made by a database link before an error is suspected.")
     def_config_set_parser.add_argument('--test-response-delay', help="Sets the duration of the test issued by the database link to check whether the remote server is responding.")
-    def_config_set_parser.add_argument('--use-starttls', help="Specificies that the database links should StartTLS for its secure connections.")
+    def_config_set_parser.add_argument('--use-starttls', help="Set to \"on\" specifies that the database links should use StartTLS for its secure connections.")
 
     create_link_parser = subcommands.add_parser('link-create', add_help=False, conflict_handler='resolve', parents=[def_config_set_parser],
         help='Create a database link to a remote server')
@@ -240,7 +264,7 @@ def create_parser(subparsers):
 
     get_link_parser = subcommands.add_parser('link-get', help='get chaining database link')
     get_link_parser.set_defaults(func=get_link)
-    get_link_parser.add_argument('CHAIN_NAME', nargs=1, help='The chaining link name to search for')
+    get_link_parser.add_argument('CHAIN_NAME', nargs=1, help='The chaining link name, or suffix, to retrieve')
 
     edit_link_parser = subcommands.add_parser('link-set', add_help=False, conflict_handler='resolve',
         parents=[def_config_set_parser], help='Edit a database link to a remote server')
@@ -262,5 +286,3 @@ def create_parser(subparsers):
 
     list_link_parser = subcommands.add_parser('link-list', help='List database links')
     list_link_parser.set_defaults(func=list_links)
-
-
diff --git a/src/lib389/lib389/cli_ctl/dbtasks.py b/src/lib389/lib389/cli_ctl/dbtasks.py
index 0b6e948..9477b3c 100644
--- a/src/lib389/lib389/cli_ctl/dbtasks.py
+++ b/src/lib389/lib389/cli_ctl/dbtasks.py
@@ -55,7 +55,7 @@ def dbtasks_ldif2db(inst, log, args):
 def dbtasks_backups(inst, log, args):
     if args.delete:
         # Delete backup
-        inst.del_backup(args.delete)
+        inst.del_backup(args.delete[0])
     else:
         # list backups
         if not inst.backups(args.json):
@@ -66,6 +66,20 @@ def dbtasks_backups(inst, log, args):
                 log.info("backups successful")
 
 
+def dbtasks_ldifs(inst, log, args):
+    if args.delete:
+        # Delete LDIF file
+        inst.del_ldif(args.delete[0])
+    else:
+        # list LDIF files
+        if not inst.ldifs(args.json):
+            log.fatal("Failed to get list of LDIF files")
+            return False
+        else:
+            if args.json is None:
+                log.info("backups successful")
+
+
 def dbtasks_verify(inst, log, args):
     if not inst.dbverify(bename=args.backend):
         log.fatal("dbverify failed")
@@ -97,7 +111,6 @@ def create_parser(subcommands):
     dbverify_parser.add_argument('backend', help="The backend to verify. IE userRoot")
     dbverify_parser.set_defaults(func=dbtasks_verify)
 
-
     bak2db_parser = subcommands.add_parser('bak2db', help="Restore a BDB backup of the database. The server must be stopped for this to proceed.")
     bak2db_parser.add_argument('archive', help="The archive to restore. This will erase all current server databases.")
     bak2db_parser.set_defaults(func=dbtasks_bak2db)
@@ -109,5 +122,10 @@ def create_parser(subcommands):
     ldif2db_parser.set_defaults(func=dbtasks_ldif2db)
 
     backups_parser = subcommands.add_parser('backups', help="List backup's found in the server's default backup directory")
-    backups_parser.add_argument('--delete', help="Delete backup directory")
+    backups_parser.add_argument('--delete', nargs=1, help="Delete backup directory")
     backups_parser.set_defaults(func=dbtasks_backups)
+
+    ldifs_parser = subcommands.add_parser('ldifs', help="List all the DLIF files located in the server's LDIF directory")
+    ldifs_parser.add_argument('--delete', nargs=1, help="Delete LDIF file")
+    ldifs_parser.set_defaults(func=dbtasks_ldifs)
+
diff --git a/src/lib389/lib389/index.py b/src/lib389/lib389/index.py
index 4c472a6..f5707c0 100644
--- a/src/lib389/lib389/index.py
+++ b/src/lib389/lib389/index.py
@@ -95,11 +95,15 @@ class VLVSearch(DSLdapObject):
         new_index = VLVIndex(self._instance, dn=dn)
         new_index.create(properties=props)
 
-    def delete_sort(self, name):
+    def delete_sort(self, name, sort_attrs=None):
         vlvsorts = VLVIndexes(self._instance, basedn=self._dn).list()
         for vlvsort in vlvsorts:
             sort_name = vlvsort.get_attr_val_utf8_l('cn').lower()
-            if sort_name == name.lower():
+            sort = vlvsort.get_attr_val_utf8_l('vlvsort')
+            if sort_attrs is not None and sort_attrs == sort:
+                vlvsort.delete()
+                return
+            elif name is not None and sort_name == name.lower():
                 vlvsort.delete()
                 return
         raise ValueError("Can not delete vlv sort index because it does not exist")
@@ -121,9 +125,10 @@ class VLVSearch(DSLdapObject):
         else:
             attrs = []
             vlvsorts = VLVIndexes(self._instance, basedn=self._dn).list()
-            for vlvsort in vlvsorts:
-                attrs.append(ensure_str(vlvsort.get_attr_val_bytes('cn')))
-            reindex_task.reindex(suffix=be_name, attrname=attrs, vlv=True)
+            if len(vlvsorts) > 0:
+                for vlvsort in vlvsorts:
+                    attrs.append(ensure_str(vlvsort.get_attr_val_bytes('cn')))
+                reindex_task.reindex(suffix=be_name, attrname=attrs, vlv=True)
 
 
 class VLVSearches(DSLdapObjects):
diff --git a/src/lib389/lib389/instance/remove.py b/src/lib389/lib389/instance/remove.py
index c5d6622..5fbd511 100644
--- a/src/lib389/lib389/instance/remove.py
+++ b/src/lib389/lib389/instance/remove.py
@@ -36,6 +36,7 @@ def remove_ds_instance(dirsrv, force=False):
     """
     _log = dirsrv.log.getChild('remove_ds')
     _log.debug("Removing instance %s" % dirsrv.serverid)
+
     # Copy all the paths we are about to tamper with
     remove_paths = {}
     remove_paths['backup_dir'] = dirsrv.ds_paths.backup_dir
@@ -74,6 +75,13 @@ def remove_ds_instance(dirsrv, force=False):
     _log.debug("Stopping instance %s" % dirsrv.serverid)
     dirsrv.stop()
 
+    _log.debug("Found instance marker at %s! Proceeding to remove ..." % dse_ldif_path)
+
+    # Stop the instance (if running) and now we know it really does exist
+    # and hopefully have permission to access it ...
+    _log.debug("Stopping instance %s" % dirsrv.serverid)
+    dirsrv.stop()
+
     ### ANY NEW REMOVAL ACTION MUST BE BELOW THIS LINE!!!
 
     # Remove these paths:
diff --git a/src/lib389/lib389/rootdse.py b/src/lib389/lib389/rootdse.py
index aa17561..131a319 100644
--- a/src/lib389/lib389/rootdse.py
+++ b/src/lib389/lib389/rootdse.py
@@ -45,3 +45,6 @@ class RootDSE(DSLdapObject):
     def supports_exop_ldapssotoken_revoke(self):
         return self.present("supportedExtension", "2.16.840.1.113730.3.5.16")
 
+    def get_supported_ctrls(self):
+        return self.get_attr_vals_utf8('supportedControl')
+
diff --git a/src/lib389/lib389/tasks.py b/src/lib389/lib389/tasks.py
index 8878e51..47df609 100644
--- a/src/lib389/lib389/tasks.py
+++ b/src/lib389/lib389/tasks.py
@@ -37,6 +37,7 @@ class Task(DSLdapObject):
         self._create_objectclasses = ['top', 'extensibleObject']
         self._protected = False
         self._exit_code = None
+        self._task_log = ""
 
     def status(self):
         """Return the decoded status of the task
@@ -47,6 +48,7 @@ class Task(DSLdapObject):
         """Return True if task is complete, else False."""
 
         self._exit_code = self.get_attr_val_utf8("nsTaskExitCode")
+        self._task_log = self.get_attr_val_utf8("nsTaskLog")
         if not self.exists():
             self._log.debug("complete: task has self cleaned ...")
             # The task cleaned it self up.
@@ -66,6 +68,15 @@ class Task(DSLdapObject):
                 return None
         return None
 
+    def get_task_log(self):
+        """Return task's exit code if task is complete, else None."""
+        if self.is_complete():
+            try:
+                return (self._task_log)
+            except TypeError:
+                return None
+        return None
+
     def wait(self, timeout=120):
         """Wait until task is complete."""
 
@@ -621,7 +632,7 @@ class Tasks(object):
                       task
                 wait: True/[False] - If True, 'index' waits for the completion
                                      of the task before to return
-        :param vlv - this task is to reindex a VVL index
+        :param vlv - this task is to reindex a VLV index
 
         :return None
 

