Monday, March 2, 2020

[389-commits] [389-ds-base] branch 389-ds-base-1.4.1 updated: Issue 50904 - Connect All React Components And Refactor the Main Navigation Tab Code

This is an automated email from the git hooks/post-receive script.

mreynolds pushed a commit to branch 389-ds-base-1.4.1
in repository 389-ds-base.

The following commit(s) were added to refs/heads/389-ds-base-1.4.1 by this push:
new 22a3b16 Issue 50904 - Connect All React Components And Refactor the Main Navigation Tab Code
22a3b16 is described below

commit 22a3b1668f4665f8d6d5e90188d93ae6ada1041c
Author: Simon Pichugin <spichugi@redhat.com>
AuthorDate: Tue Feb 18 16:20:33 2020 +0100

Issue 50904 - Connect All React Components And Refactor the Main Navigation Tab Code

Description: Port the rest of ds.js and index.html code to React.
It includes instance navigation, creation, removal, and other dsctl tasks.
Fix https://pagure.io/389-ds-base/issue/49902

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

Reviewed by: mreynolds (Thanks!)
---
src/cockpit/389-console/src/css/ds.css | 33 +-
src/cockpit/389-console/src/database.jsx | 110 +-
src/cockpit/389-console/src/ds.js | 1074 -----------
src/cockpit/389-console/src/ds.jsx | 1917 ++++++++++++++++++++
src/cockpit/389-console/src/index.es6 | 85 +-
src/cockpit/389-console/src/index.html | 473 +----
.../389-console/src/lib/database/backups.jsx | 4 +-
.../389-console/src/lib/database/chaining.jsx | 2 +-
.../src/lib/plugins/attributeUniqueness.jsx | 28 +-
.../389-console/src/lib/plugins/autoMembership.jsx | 14 +-
src/cockpit/389-console/src/lib/plugins/dna.jsx | 10 +-
.../src/lib/plugins/linkedAttributes.jsx | 18 +-
.../389-console/src/lib/plugins/memberOf.jsx | 52 +-
.../src/lib/plugins/passthroughAuthentication.jsx | 24 +-
.../src/lib/plugins/referentialIntegrity.jsx | 22 +-
.../389-console/src/lib/plugins/retroChangelog.jsx | 14 +-
src/cockpit/389-console/src/lib/plugins/usn.jsx | 15 +-
.../389-console/src/lib/server/accessLog.jsx | 40 +-
.../389-console/src/lib/server/auditLog.jsx | 40 +-
.../389-console/src/lib/server/auditfailLog.jsx | 40 +-
.../389-console/src/lib/server/errorLog.jsx | 40 +-
src/cockpit/389-console/src/lib/server/ldapi.jsx | 38 +-
src/cockpit/389-console/src/lib/server/sasl.jsx | 54 +-
.../389-console/src/lib/server/settings.jsx | 58 +-
src/cockpit/389-console/src/lib/server/tuning.jsx | 38 +-
src/cockpit/389-console/src/monitor.jsx | 56 +-
src/cockpit/389-console/src/plugins.jsx | 113 +-
src/cockpit/389-console/src/replication.jsx | 83 +-
src/cockpit/389-console/src/schema.jsx | 78 +-
src/cockpit/389-console/src/security.jsx | 75 +-
src/cockpit/389-console/src/server.jsx | 179 +-
src/cockpit/389-console/webpack.config.js | 1 -
src/lib389/cli/dsctl | 8 +-
src/lib389/lib389/cli_ctl/instance.py | 2 +-
34 files changed, 2391 insertions(+), 2447 deletions(-)

diff --git a/src/cockpit/389-console/src/css/ds.css b/src/cockpit/389-console/src/css/ds.css
index 82b1ab3..76bf2a9 100644
--- a/src/cockpit/389-console/src/css/ds.css
+++ b/src/cockpit/389-console/src/css/ds.css
@@ -59,12 +59,6 @@
margin-top: 2px;
}

-.ds-refresh:hover {
- color: DarkGray;
- background-color: white;
- background-image: none;
-}
-
.dataTables_wrapper {
padding: 0px !important;
margin-bottom: 10px !important;
@@ -282,6 +276,16 @@ td {
padding: 5px;
}

+.ds-operate-spinner {
+ margin-left: 10px;
+ top: 10px;
+}
+
+.ds-tab-main {
+ margin-left: 2%;
+ font-size: 18px;
+}
+
.ds-config-label {
margin-top: 10px;
width: 225px !important;
@@ -513,7 +517,6 @@ option {
text-align: left;
}

-.ds-accordion:hover,
.ds-accordion:focus {
background-color: transparent !important;
outline: none !important;
@@ -523,10 +526,6 @@ option {
box-shadow: 0 !important;
}

-.ds-accordion:active {
- background-color: transparent !important;
-}
-
.ds-margin-top {
margin-top: 10px !important;
}
@@ -610,10 +609,6 @@ option {
width: 100%;
}

-.ds-inst-indent {
- margin-left: 240px;
-}
-
.ds-left-margin {
margin-left: 10px !important;
}
@@ -679,7 +674,7 @@ option {
.ds-loading {
position: fixed;
top: 25%;
- left: 35%;
+ left: 50%;
transform: translate(-25%, -35%);
}

@@ -855,12 +850,6 @@ option {
display: block;
}

-.treeview-hover .treeitem-row:hover {
- background-color: #def3ff;
- border-color: #bee1f4;
- display: block;
-}
-
input {
padding-left: 5px !important;
}
diff --git a/src/cockpit/389-console/src/database.jsx b/src/cockpit/389-console/src/database.jsx
index 3ac1e7a..efa3ce6 100644
--- a/src/cockpit/389-console/src/database.jsx
+++ b/src/cockpit/389-console/src/database.jsx
@@ -1,6 +1,5 @@
import cockpit from "cockpit";
import React from "react";
-import { NotificationController } from "./lib/notifications.jsx";
import { log_cmd } from "./lib/tools.jsx";
import {
ChainingConfig,
@@ -40,7 +39,7 @@ export class Database extends React.Component {
constructor(props) {
super(props);
this.state = {
- notifications: [],
+ firstLoad: true,
errObj: {},
nodes: [],
node_name: "",
@@ -76,8 +75,6 @@ export class Database extends React.Component {

// 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.handleRadioChange = this.handleRadioChange.bind(this);
this.loadGlobalConfig = this.loadGlobalConfig.bind(this);
@@ -109,23 +106,22 @@ export class Database extends React.Component {
this.enableTree = this.enableTree.bind(this);
}

- componentWillMount () {
- if (!this.state.loaded) {
- 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);
+ if (this.props.wasActiveList.includes(2)) {
+ if (this.state.firstLoad) {
+ if (!this.state.loaded) {
+ this.loadGlobalConfig();
+ this.loadChainingConfig();
+ this.loadLDIFs();
+ this.loadBackups();
+ this.loadSuffixList();
+ }
+ this.loadSuffixTree(false);
+ } else {
+ if (this.props.serverId !== prevProps.serverId) {
+ this.loadSuffixTree(false);
+ }
+ }
}
}

@@ -146,6 +142,9 @@ export class Database extends React.Component {
}

loadGlobalConfig () {
+ if (this.state.firstLoad) {
+ this.setState({ firstLoad: false });
+ }
const cmd = [
"dsconf", "-j", "ldapi://%2fvar%2frun%2fslapd-" + this.props.serverId + ".socket",
"backend", "config", "get"
@@ -198,7 +197,7 @@ export class Database extends React.Component {
})
.fail(err => {
let errMsg = JSON.parse(err);
- this.addNotification(
+ this.props.addNotification(
"error",
`Error loading database configuration - ${errMsg.desc}`
);
@@ -285,7 +284,7 @@ export class Database extends React.Component {
})
.fail(err => {
let errMsg = JSON.parse(err);
- this.addNotification(
+ this.props.addNotification(
"error",
`Error loading default chaining configuration - ${errMsg.desc}`
);
@@ -469,7 +468,7 @@ export class Database extends React.Component {
})
.fail(err => {
let errMsg = JSON.parse(err);
- this.addNotification(
+ this.props.addNotification(
"error",
`Error getting chaining link configuration - ${errMsg.desc}`
);
@@ -551,29 +550,6 @@ export class Database extends React.Component {
});
}

- 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
@@ -644,7 +620,7 @@ export class Database extends React.Component {
};

if (this.state.createSuffix == "") {
- this.addNotification(
+ this.props.addNotification(
"warning",
`Missing the suffix DN`
);
@@ -652,7 +628,7 @@ export class Database extends React.Component {
errors = true;
}
if (this.state.createBeName == "") {
- this.addNotification(
+ this.props.addNotification(
"warning",
`Missing the suffix backend name`
);
@@ -683,7 +659,7 @@ export class Database extends React.Component {
.spawn(cmd, { superuser: true, err: "message" })
.done(content => {
this.closeSuffixModal();
- this.addNotification(
+ this.props.addNotification(
"success",
`Successfully create new suffix`
);
@@ -693,7 +669,7 @@ export class Database extends React.Component {
})
.fail(err => {
let errMsg = JSON.parse(err);
- this.addNotification(
+ this.props.addNotification(
"error",
`Error creating suffix - ${errMsg.desc}`
);
@@ -853,7 +829,7 @@ export class Database extends React.Component {
})
.fail(err => {
let errMsg = JSON.parse(err);
- this.addNotification(
+ this.props.addNotification(
"error",
`Error loading indexes for ${suffix} - ${errMsg.desc}`
);
@@ -1008,7 +984,7 @@ export class Database extends React.Component {
})
.fail(err => {
let errMsg = JSON.parse(err);
- this.addNotification(
+ this.props.addNotification(
"error",
`Error loading indexes for ${suffix} - ${errMsg.desc}`
);
@@ -1019,7 +995,7 @@ export class Database extends React.Component {
})
.fail(err => {
let errMsg = JSON.parse(err);
- this.addNotification(
+ this.props.addNotification(
"error",
`Error attribute encryption for ${suffix} - ${errMsg.desc}`
);
@@ -1030,7 +1006,7 @@ export class Database extends React.Component {
})
.fail(err => {
let errMsg = JSON.parse(err);
- this.addNotification(
+ this.props.addNotification(
"error",
`Error loading VLV indexes for ${suffix} - ${errMsg.desc}`
);
@@ -1041,7 +1017,7 @@ export class Database extends React.Component {
})
.fail(err => {
let errMsg = JSON.parse(err);
- this.addNotification(
+ this.props.addNotification(
"error",
`Error loading config for ${suffix} - ${errMsg.desc}`
);
@@ -1074,7 +1050,7 @@ export class Database extends React.Component {
const cmd = [
"dsctl", "-j", this.props.serverId, "backups"
];
- log_cmd("loadBackups", "Load Backups", cmd);
+ log_cmd("loadBackupsDatabase", "Load Backups", cmd);
cockpit
.spawn(cmd, { superuser: true, err: "message" })
.done(content => {
@@ -1111,7 +1087,7 @@ export class Database extends React.Component {
})
.fail(err => {
let errMsg = JSON.parse(err);
- this.addNotification(
+ this.props.addNotification(
"error",
`Failed to get attributes - ${errMsg.desc}`
);
@@ -1138,7 +1114,7 @@ export class Database extends React.Component {
db_element =
<GlobalDatabaseConfig
serverId={this.props.serverId}
- addNotification={this.addNotification}
+ addNotification={this.props.addNotification}
reload={this.loadGlobalConfig}
data={this.state.globalDBConfig}
enableTree={this.enableTree}
@@ -1148,7 +1124,7 @@ export class Database extends React.Component {
db_element =
<ChainingDatabaseConfig
serverId={this.props.serverId}
- addNotification={this.addNotification}
+ addNotification={this.props.addNotification}
reload={this.loadChainingConfig}
data={this.state.chainingConfig}
enableTree={this.enableTree}
@@ -1158,7 +1134,7 @@ export class Database extends React.Component {
db_element =
<GlobalPwPolicy
serverId={this.props.serverId}
- addNotification={this.addNotification}
+ addNotification={this.props.addNotification}
attrs={this.state.attributes}
enableTree={this.enableTree}
/>;
@@ -1166,7 +1142,7 @@ export class Database extends React.Component {
db_element =
<LocalPwPolicy
serverId={this.props.serverId}
- addNotification={this.addNotification}
+ addNotification={this.props.addNotification}
attrs={this.state.attributes}
enableTree={this.enableTree}
/>;
@@ -1174,7 +1150,7 @@ export class Database extends React.Component {
db_element =
<Backups
serverId={this.props.serverId}
- addNotification={this.addNotification}
+ addNotification={this.props.addNotification}
backups={this.state.BackupRows}
suffixes={this.state.suffixList}
ldifs={this.state.LDIFRows}
@@ -1202,7 +1178,7 @@ export class Database extends React.Component {
reloadIndexes={this.loadIndexes}
reloadVLV={this.loadVLV}
reloadAttrEnc={this.loadAttrEncrypt}
- addNotification={this.addNotification}
+ addNotification={this.props.addNotification}
reloadLDIFs={this.loadLDIFs}
LDIFRows={this.state.LDIFRows}
dbtype={this.state.dbtype}
@@ -1227,7 +1203,7 @@ export class Database extends React.Component {
suffix={this.state.node_text}
bename={this.state.bename}
loadSuffixTree={this.loadSuffixTree}
- addNotification={this.addNotification}
+ addNotification={this.props.addNotification}
data={this.state[this.state.node_text]}
enableTree={this.enableTree}
reload={this.loadChainingLink}
@@ -1268,10 +1244,6 @@ export class Database extends React.Component {

return (
<div className="container-fluid">
- <NotificationController
- notifications={this.state.notifications}
- removeNotificationAction={this.removeNotification}
- />
{body}
<CreateSuffixModal
showModal={this.state.showSuffixModal}
@@ -1381,10 +1353,12 @@ class CreateSuffixModal extends React.Component {
// Property types and defaults

Database.propTypes = {
+ addNotification: PropTypes.func,
serverId: PropTypes.string
};

Database.defaultProps = {
+ addNotification: noop,
serverId: ""
};

diff --git a/src/cockpit/389-console/src/ds.js b/src/cockpit/389-console/src/ds.js
deleted file mode 100644
index 5c7e302..0000000
--- a/src/cockpit/389-console/src/ds.js
+++ /dev/null
@@ -1,1074 +0,0 @@
-var DS_HOME = "/etc/dirsrv/";
-var server_id = "None";
-var server_inst = "";
-var dn_regex = new RegExp( "^([A-Za-z]+=.*)" );
-
-/*
- * We can't load the config until all the html pages are load, so we'll use vars
- * to track the loading, and once all the pages are loaded, then we can load the config
- */
-var server_page_loaded = 1;
-var security_page_loaded = 1;
-var db_page_loaded = 1;
-var repl_page_loaded = 1;
-var plugin_page_loaded = 1;
-var schema_page_loaded = 1;
-var monitor_page_loaded = 1;
-var config_loaded = 0;
-
-// objects to store original values (used for comparing what changed when saving
-var config_values = {};
-var localpwp_values = {};
-var repl_config_values = {};
-var repl_cl_values = {};
-
-//TODO - need "config_values" for all the other pages: backend, replication, suffix, etc.
-
-var DSCONF = "dsconf";
-var DSCTL = "dsctl";
-var DSCREATE = "dscreate";
-var ENV = "";
-
-
-/*
- * Console logging function for CLI commands
- *
- * @param {text} js_func The javascript/jquery function that is making this call.
- * @param {text} desc The description of the CLI command.
- * @param {array} cmd_array An array of all the CLI arguments.
- */
-function log_cmd(js_func, desc, cmd_array) {
- if (window.console) {
- var pw_args = ['--passwd', '--bind-pw', '--bind-passwd', '--nsslapd-rootpw'];
- var cmd_list = [];
- var converted_pw = false;
-
- for (var idx in cmd_array) {
- var cmd = cmd_array[idx].toString();
- converted_pw = false;
- for (var arg_idx in pw_args) {
- if ( cmd.startsWith(pw_args[arg_idx]) ) {
- // We are setting a password, if it has a value we need to hide it
- var arg_len = cmd.indexOf('=');
- var arg = cmd.substring(0, arg_len);
- if (cmd.length != arg_len + 1) {
- // We are setting a password value...
- cmd_list.push(arg + "=**********");
- converted_pw = true;
- }
- break;
- }
- }
- if (!converted_pw) {
- cmd_list.push(cmd);
- }
- }
- window.console.log("CMD: " + js_func + ": " + desc + " ==> " + cmd_list.join(' '));
- }
-}
-
-// TODO validation functions
-
-function valid_dn (dn){
- // Validate value is a valid DN (sanity validation)
- var result = dn_regex.test(dn);
- return result;
-}
-
-function valid_num (val){
- // Validate value is a number
- let result = !isNaN(val);
- return result;
-}
-
-function valid_port (val){
- // Validate value is a number and between 1 and 65535
- let result = !isNaN(val);
- if (result) {
- if (val < 1 || val > 65535) {
- result = false;
- }
- }
- return result;
-}
-
-function tableize (val) {
- // Truncate a long value to fit inside table
- if (val.length > 25){
- val = val.substring(0,25) + "...";
- }
- return val;
-}
-
-/*
- * Set the ports numbers on the instance creation form. If the default ports
- * are taken just unset the values.
- */
-function set_ports() {
- var cmd = ['ss', '-ntpl'];
- cockpit.spawn(cmd, { superuser: true, "err": "message"}).done(function(data) {
- var lines = data.split('\n');
- $("#create-inst-port").val("389");
- $("#create-inst-secureport").val("636");
- for (var i = 0; i < lines.length; i++){
- if (lines[i].indexOf("LISTEN") != -1 && lines[i].indexOf(":389 ") != -1) {
- $("#create-inst-port").val("");
- }
- if (lines[i].indexOf("LISTEN") != -1 && lines[i].indexOf(":636 ") != -1) {
- $("#create-inst-secureport").val("");
- }
- }
- });
-}
-
-function sort_list (sel) {
- var opts_list = sel.find('option');
- opts_list.sort(function(a, b) { return $(a).text() > $(b).text() ? 1 : -1; });
- sel.html('').append(opts_list);
-}
-
-
-function get_date_string (timestamp) {
- // Convert DS timestamp to a friendly string: 20180921142257Z -> 10/21/2018, 2:22:57 PM
- let year = timestamp.substr(0,4);
- let month = timestamp.substr(4,2);
- let day = timestamp.substr(6,2);
- let hour = timestamp.substr(8,2);
- let minute = timestamp.substr(10,2);
- let sec = timestamp.substr(12,2);
- let date = new Date(parseInt(year), parseInt(month), parseInt(day),
- parseInt(hour), parseInt(minute), parseInt(sec));
-
- return date.toLocaleString();
-}
-
-function get_date_diff(start, end) {
- // Get the start up date
- let year = start.substr(0,4);
- let month = start.substr(4,2);
- let day = start.substr(6,2);
- let hour = start.substr(8,2);
- let minute = start.substr(10,2);
- let sec = start.substr(12,2);
- let startDate = new Date(parseInt(year), parseInt(month), parseInt(day),
- parseInt(hour), parseInt(minute), parseInt(sec));
-
- // Get the servers current date
- year = end.substr(0,4);
- month = end.substr(4,2);
- day = end.substr(6,2);
- hour = end.substr(8,2);
- minute = end.substr(10,2);
- sec = end.substr(12,2);
- let currDate = new Date(parseInt(year), parseInt(month), parseInt(day),
- parseInt(hour), parseInt(minute), parseInt(sec));
-
- // Generate pretty elapsed time string
- let seconds = Math.floor((startDate - (currDate))/1000);
- let minutes = Math.floor(seconds/60);
- let hours = Math.floor(minutes/60);
- let days = Math.floor(hours/24);
- hours = hours-(days*24);
- minutes = minutes-(days*24*60)-(hours*60);
- seconds = seconds-(days*24*60*60)-(hours*60*60)-(minutes*60);
-
- return("${days} days, ${hours} hours, ${minutes} minutes, and ${seconds} seconds");
-}
-
-function set_no_insts () {
- $("#select-server").empty();
- $("#select-server").append('<option value="No instances">No instances</option>');
- $("#select-server select").val('No instances');
-
- server_id = "";
- server_inst = "";
-
- $("#server-list-menu").attr('disabled', true);
- $("#ds-navigation").hide();
- $(".all-pages").hide();
- $("#no-instances").show();
-}
-
-function check_for_389 () {
- var cmd = ["rpm", "-q", "389-ds-base"];
-
- cockpit.spawn(cmd, { superuser: true }).fail(function(data) {
- $("#server-list-menu").attr('disabled', true);
- $("#ds-navigation").hide();
- $(".all-pages").hide();
- $("#no-package").show();
- });
-}
-
-function check_inst_alive (connect_err) {
- // Check if this instance is started, if not hide configuration pages
- if (connect_err === undefined) {
- connect_err = 0;
- }
- cmd = [DSCTL, '-j', server_inst, 'status'];
- cockpit.spawn(cmd, { superuser: true}).
- done(function(status_data) {
- var status_json = JSON.parse(status_data);
- if (status_json.running == true) {
- if (connect_err) {
- $("#ds-navigation").hide();
- $(".all-pages").hide();
- $("#no-connect").show();
- } else {
- // if nav page was hidden reset everything
- if ($("#ds-navigation").is(":hidden") ){
- $(".all-pages").hide();
- $("#ds-navigation").show();
- $("#server-content").show();
- }
- $("#not-running").hide();
- $("#no-connect").hide();
- }
- } else {
- $("#loading-page").hide();
- $("#ds-navigation").hide();
- $(".all-pages").hide();
- $("#not-running").show();
- }
- }).fail(function(data) {
- $("#loading-page").hide();
- $("#ds-navigation").hide();
- $(".all-pages").hide();
- $("#not-running").show();
- });
-}
-
-function get_insts() {
- // Load initial forms
- $("#server-list-menu").attr('disabled', false);
- $("#ds-navigation").show();
- $(".all-pages").hide();
- $("#no-instances").hide();
-
- var insts = [];
- var cmd = ["/bin/sh", "-c", "/usr/bin/ls -d " + DS_HOME + "slapd-*"];
- cockpit.spawn(cmd, { superuser: true }).done(function(data) {
- // Parse the output, and skip removed instances and empty lines
- var lines = data.split('\n');
- var i = 0;
- for (i = 0; i < lines.length; i++) {
- if (lines[i].endsWith(".removed") == false && lines[i] != "") {
- var serverid = lines[i].replace(DS_HOME, "");
- insts.push(serverid);
- }
- }
-
- if (server_id != "None") {
- $("#ds-banner").html("Managing Instance <select class=\"btn btn-default dropdown\" id=\"select-server\"></select>");
- }
-
- // Populate the server instance drop down
- $("#select-server").empty();
- for (i = 0; i < insts.length; i++) {
- $("#select-server").append('<option value="' + insts[i] + '">' + insts[i] +'</option>');
- $("#select-server select").val(insts[i]);
- }
-
- // Handle changing instance here
- document.getElementById("select-server").addEventListener("change", function() {
- server_id = $(this).val();
- server_inst = server_id.replace("slapd-", "");
- load_config();
- });
-
- if (insts[0] === undefined) {
- set_no_insts();
- $("#loading-page").hide();
- $("#everything").show();
- } else {
- // We have at least one instance, make sure we "open" the UI
- server_id = insts[0];
- server_inst = insts[0].replace("slapd-", "");
- check_inst_alive();
- // We have to dispatch an event for the React components rerender
- // It should also trigger the listener defined before
- server_select_elem = document.getElementById('select-server');
- server_select_elem.dispatchEvent(new Event('change'));
- }
- }).fail(function(error){
- set_no_insts();
- $("#loading-page").hide();
- $("#everything").show();
- });
-}
-
-function report_err( input, msg) {
- $(".ds-modal-error").html('Error: ' + msg);
- input.css("border-color", "red");
- $(".ds-modal-error").show();
-}
-
-
-function popup_err(title, msg) {
- // Display errors from the cli (we have to use pre tags)
- bootpopup({
- title: title,
- content: [
- '<pre>' + msg + '</pre>'
- ]
- });
- check_inst_alive(0);
-}
-
-function popup_msg(title, msg) {
- bootpopup({
- title: title,
- content: [
- '<p>' + msg + '</p>'
- ]
- });
-}
-
-function popup_confirm(msg, title, callback) {
- if(typeof callback !== "function") {
- callback = function() {};
- }
- var answer = false;
- return bootpopup({
- title: title,
- content: [
- msg
- ],
- showclose: false,
- buttons: ["no", "yes"],
- yes: function() { answer = true; },
- dismiss: function() { callback(answer); },
- });
-}
-
-function popup_success(msg) {
- $('#success-msg').html(msg);
- $('#success-form').modal('show');
- setTimeout(function() {$('#success-form').modal('hide');}, 2000);
-}
-
-// This is called when any Save button is clicked on the main page. We call
-// all the save functions for all the pages here. This is not used for modal forms
-function save_all () {
- save_config(); // Server Config Page
-}
-
-var progress = 10;
-
-function update_progress () {
- progress += 10;
- if (progress > 100) {
- progress = 100;
- }
- $("#ds-progress-label").text(progress + "%");
- $("#ds-progress-bar").attr("aria-valuenow", progress);
- $("#ds-progress-bar").css("width", progress + "%");
-}
-
-var loading_cfg = 0;
-
-function load_config (refresh){
- // If we are currently loading config don't do it twice
- if (loading_cfg == 1){
- return;
- }
- loading_cfg = 1;
- progress = 10;
- update_progress();
-
- // Show the spinner, and reset the pages
- $("#loading-msg").html("Loading Directory Server configuration for <i><b>" + server_id + "</b></i>...");
- $("#everything").hide();
- $(".all-pages").hide();
- $("#loading-page").show();
- config_loaded = 0;
-
- /*
- * Start with the dropdowns, if this fails we stop here, otherwise we assume
- * we are up and running and we can load the other config/
- */
- var cmd = [DSCONF, '-j', 'ldapi://%2fvar%2frun%2f' + server_id + '.socket','backend', 'suffix', 'list', '--suffix'];
- log_cmd('load_config', 'get backend list', cmd);
- cockpit.spawn(cmd, { superuser: true, "err": "message", "environ": [ENV]}).done(function(data) {
- update_progress();
- config_loaded = 1;
-
- // Initialize the tabs
- $(".ds-tab-list").css( 'color', '#777');
- $("#server-tab").css( 'color', '#228bc0');
-
- // Set an interval event to wait for all the pages to load, then show the content
- var loading_config = setInterval(function() {
- if (config_loaded == 1) {
- $("#loading-page").hide();
- $("#everything").show();
- $("#server-content").show();
- clearInterval(loading_config);
- loading_cfg = 0;
-
- if (refresh) {
- // Reload reactJS pages by clicking dummy element
- let reload_el = document.getElementById('reload-page');
- reload_el.click();
- }
-
- console.log("Completed configuration initialization.");
- }
- }, 300);
-
- }).fail(function(data) {
- popup_err("Failed To Contact Server",data.message);
- $("#everything").show();
- check_inst_alive(1);
- loading_cfg = 0;
- });
-}
-
-
-
-// Create Instance
-$("#create-inst-save").on("click", function() {
- $(".ds-modal-error").hide();
- $(".ds-inst-input").css("border-color", "initial");
-
- /*
- * Validate settings and update the INF settings
- */
- let setup_inf = create_inf_template;
-
- // Server ID
- let new_server_id = $("#create-inst-serverid").val();
- if (new_server_id == ""){
- report_err($("#create-inst-serverid"), 'You must provide an Instance name');
- $("#create-inst-serverid").css("border-color", "red");
- return;
- } else {
- new_server_id = new_server_id.replace(/^slapd-/i, ""); // strip "slapd-"
- if (new_server_id.length > 128) {
- report_err($("#create-inst-serverid"), 'Instance name is too long, it must not exceed 128 characters');
- $("#create-inst-serverid").css("border-color", "red");
- return;
- }
- if (new_server_id.match(/^[#%:A-Za-z0-9_\-]+$/g)) {
- setup_inf = setup_inf.replace('INST_NAME', new_server_id);
- } else {
- report_err($("#create-inst-serverid"), 'Instance name can only contain letters, numbers, and: # % : - _');
- $("#create-inst-serverid").css("border-color", "red");
- return;
- }
- }
-
- // Port
- let server_port = $("#create-inst-port").val();
- if (server_port == ""){
- report_err($("#create-inst-port"), 'You must provide a port number');
- $("#create-inst-port").css("border-color", "red");
- return;
- } else if (!valid_port(server_port)) {
- report_err($("#create-inst-port"), 'Port must be a number between 1 and 65534!');
- $("#create-inst-port").css("border-color", "red");
- return;
- } else {
- setup_inf = setup_inf.replace('PORT', server_port);
- }
-
- // Secure Port
- let secure_port = $("#create-inst-secureport").val();
- if (secure_port == ""){
- report_err($("#create-inst-secureport"), 'You must provide a secure port number');
- $("#create-inst-secureport").css("border-color", "red");
- return;
- } else if (!valid_port(secure_port)) {
- report_err($("#create-inst-secureport"), 'Secure port must be a number!');
- $("#create-inst-secureport").css("border-color", "red");
- return;
- } else {
- setup_inf = setup_inf.replace('SECURE_PORT', secure_port);
- }
-
- // Root DN
- let server_rootdn = $("#create-inst-rootdn").val();
- if (server_rootdn == ""){
- report_err($("#create-inst-rootdn"), 'You must provide a Directory Manager DN');
- $("#create-inst-rootdn").css("border-color", "red");
- return;
- } else {
- setup_inf = setup_inf.replace('ROOTDN', server_rootdn);
- }
-
- // Setup Self-Signed Certs
- if ( $("#create-inst-tls").is(":checked") ){
- setup_inf = setup_inf.replace('SELF_SIGN', 'True');
- } else {
- setup_inf = setup_inf.replace('SELF_SIGN', 'False');
- }
-
- // Root DN password
- let root_pw = $("#rootdn-pw").val();
- let root_pw_confirm = $("#rootdn-pw-confirm").val();
- if (root_pw != root_pw_confirm) {
- report_err($("#rootdn-pw"), 'Directory Manager passwords do not match!');
- $("#rootdn-pw-confirm").css("border-color", "red");
- return;
- } else if (root_pw == ""){
- report_err($("#rootdn-pw"), 'Directory Manager password can not be empty!');
- $("#rootdn-pw-confirm").css("border-color", "red");
- return;
- } else if (root_pw.length < 8) {
- report_err($("#rootdn-pw"), 'Directory Manager password must have at least 8 characters');
- $("#rootdn-pw-confirm").css("border-color", "red");
- return;
- } else {
- setup_inf = setup_inf.replace('ROOTPW', root_pw);
- }
-
- // Backend/Suffix
- let backend_name = $("#backend-name").val();
- let backend_suffix = $("#backend-suffix").val();
- if ( (backend_name != "" && backend_suffix == "") || (backend_name == "" && backend_suffix != "") ) {
- if (backend_name == ""){
- report_err($("#backend-name"), 'If you specify a backend suffix, you must also specify a backend name');
- $("#backend-name").css("border-color", "red");
- return;
- } else {
- report_err($("#backend-suffix"), 'If you specify a backend name, you must also specify a backend suffix');
- $("#backend-suffix").css("border-color", "red");
- return;
- }
- }
- if (backend_name != ""){
- // We definitely have a backend name and suffix, next validate the suffix is a DN
- if (valid_dn(backend_suffix)) {
- // It's valid, add it
- setup_inf += "\n[backend-" + backend_name + "]\nsuffix = " + backend_suffix + "\n";
- } else {
- // Not a valid DN
- report_err($("#backend-suffix"), 'Invalid DN for Backend Suffix');
- return;
- }
- if ( $("#create-sample-entries").is(":checked") ) {
- setup_inf += '\nsample_entries = yes\n';
- } else if ( $("#create-suffix-entry").is(":checked") ) {
- setup_inf += '\ncreate_suffix_entry = yes\n';
- }
- }
-
- /*
- * Here are steps we take to create the instance
- *
- * [1] Get FQDN Name for nsslapd-localhost setting in setup file
- * [2] Create a file for the inf setup parameters
- * [3] Set strict permissions on that file
- * [4] Populate the new setup file with settings (including cleartext password)
- * [5] Create the instance
- * [6] Remove setup file
- */
- cockpit.spawn(["hostname", "--fqdn"], { superuser: true, "err": "message" }).fail(function(ex, data) {
- // Failed to get FQDN
- popup_err("Failed to get hostname!", data);
- }).done(function (data) {
- /*
- * We have FQDN, so set the hostname in inf file, and create the setup file
- */
- setup_inf = setup_inf.replace('FQDN', data);
- let setup_file = "/tmp/389-setup-" + (new Date).getTime() + ".inf";
- let rm_cmd = ['rm', setup_file];
- let create_file_cmd = ['touch', setup_file];
- cockpit.spawn(create_file_cmd, { superuser: true, "err": "message" }).fail(function(ex, data) {
- // Failed to create setup file
- popup_err("Failed to create installation file!", data);
- }).done(function (){
- /*
- * We have our new setup file, now set permissions on that setup file before we add sensitive data
- */
- let chmod_cmd = ['chmod', '600', setup_file];
- cockpit.spawn(chmod_cmd, { superuser: true, "err": "message" }).fail(function(ex, data) {
- // Failed to set permissions on setup file
- cockpit.spawn(rm_cmd, { superuser: true }); // Remove Inf file with clear text password
- $("#create-inst-spinner").hide();
- popup_err("Failed to set permission on setup file " + setup_file + ": ", data);
- }).done(function () {
- /*
- * Success we have our setup file and it has the correct permissions.
- * Now populate the setup file...
- */
- let cmd = ["/bin/sh", "-c", '/usr/bin/echo -e "' + setup_inf + '" >> ' + setup_file];
- cockpit.spawn(cmd, { superuser: true, "err": "message" }).fail(function(ex, data) {
- // Failed to populate setup file
- popup_err("Failed to populate installation file!", data);
- }).done(function (){
- /*
- * Next, create the instance...
- */
- let cmd = [DSCREATE, 'from-file', setup_file];
- cockpit.spawn(cmd, { superuser: true, "err": "message", "environ": [ENV] }).fail(function(ex, data) {
- // Failed to create the new instance!
- cockpit.spawn(rm_cmd, { superuser: true }); // Remove Inf file with clear text password
- $("#create-inst-spinner").hide();
- popup_err("Failed to create instance!", data);
- }).done(function (){
- // Success!!! Now cleanup everything up...
- cockpit.spawn(rm_cmd, { superuser: true }); // Remove Inf file with clear text password
- $("#create-inst-spinner").hide();
- $("#server-list-menu").attr('disabled', false);
- $("#no-instances").hide();
- get_insts(); // Refresh server list
- popup_success("Successfully created instance: <b>slapd-" + new_server_id + "</b>");
- $("#create-inst-form").modal('toggle');
- });
- });
- $("#create-inst-spinner").show();
- });
- });
- }).fail(function(data) {
- console.log("failed: " + data.message);
- });
-});
-
-var create_full_template =
- "[general]\n" +
- "config_version = 2\n" +
- "defaults = 999999999\n" +
- "full_machine_name = FQDN\n" +
- "selinux = True\n" +
- "strict_host_checking = True\n" +
- "systemd = True\n" +
- "[slapd]\n" +
- "backup_dir = /var/lib/dirsrv/slapd-{instance_name}/bak\n" +
- "bin_dir = /usr/bin\n" +
- "cert_dir = /etc/dirsrv/slapd-{instance_name}\n" +
- "config_dir = /etc/dirsrv/slapd-{instance_name}\n" +
- "data_dir = /usr/share\n" +
- "db_dir = /var/lib/dirsrv/slapd-{instance_name}/db\n" +
- "user = dirsrv\n" +
- "group = dirsrv\n" +
- "initconfig_dir = /etc/sysconfig\n" +
- "inst_dir = /usr/lib64/dirsrv/slapd-{instance_name}\n" +
- "instance_name = localhost\n" +
- "ldif_dir = /var/lib/dirsrv/slapd-{instance_name}/ldif\n" +
- "lib_dir = /usr/lib64\n" +
- "local_state_dir = /var\n" +
- "lock_dir = /var/lock/dirsrv/slapd-{instance_name}\n" +
- "log_dir = /var/log/dirsrv/slapd-{instance_name}\n" +
- "port = PORT\n" +
- "prefix = /usr\n" +
- "root_dn = ROOTDN\n" +
- "root_password = ROOTPW\n" +
- "run_dir = /var/run/dirsrv\n" +
- "sbin_dir = /usr/sbin\n" +
- "schema_dir = /etc/dirsrv/slapd-{instance_name}/schema\n" +
- "secure_port = SECURE_PORT\n" +
- "self_sign_cert = True\n" +
- "sysconf_dir = /etc\n" +
- "tmp_dir = /tmp\n";
-
-var create_inf_template =
- "[general]\n" +
- "config_version = 2\n" +
- "full_machine_name = FQDN\n\n" +
- "[slapd]\n" +
- "user = dirsrv\n" +
- "group = dirsrv\n" +
- "instance_name = INST_NAME\n" +
- "port = PORT\n" +
- "root_dn = ROOTDN\n" +
- "root_password = ROOTPW\n" +
- "secure_port = SECURE_PORT\n" +
- "self_sign_cert = SELF_SIGN\n";
-
-
-function clear_inst_form() {
- $(".ds-modal-error").hide();
- $("#create-inst-serverid").val("");
- $("#create-inst-port").val("389");
- $("#create-inst-secureport").val("636");
- $("#create-inst-rootdn").val("cn=Directory Manager");
- $("#rootdn-pw").val("");
- $("#rootdn-pw-confirm").val("");
- $("#backend-suffix").val("dc=example,dc=com");
- $("#backend-name").val("userRoot");
- $("#create-sample-entries").prop('checked', false);
- $("#create-inst-tls").prop('checked', true);
- $(".ds-inst-input").css("border-color", "initial");
-}
-
-function do_backup(server_inst, backup_name) {
- var cmd = [DSCTL, '-j', server_inst, 'status'];
- $("#backup-spinner").show();
- cockpit.spawn(cmd, { superuser: true}).
- done(function(status_data) {
- var status_json = JSON.parse(status_data);
- if (status_json.running == true) {
- var cmd = [DSCONF, "-j", server_inst, 'backup', 'create', backup_name];
- log_cmd('#ds-backup-btn (click)', 'Backup server instance', cmd);
- cockpit.spawn(cmd, { superuser: true, "err": "message", "environ": [ENV]}).
- done(function(data) {
- $("#backup-spinner").hide();
- popup_success("Backup has been created");
- $("#backup-form").modal('toggle');
- }).
- fail(function(data) {
- $("#backup-spinner").hide();
- popup_err("Failed to backup the server", data.message);
- })
- } else {
- var cmd = [DSCTL, server_inst, 'db2bak', backup_name];
- log_cmd('#ds-backup-btn (click)', 'Backup server instance (offline)', cmd);
- cockpit.spawn(cmd, { superuser: true, "err": "message", "environ": [ENV]}).
- done(function(data) {
- $("#backup-spinner").hide();
- popup_success("Backup has been created");
- $("#backup-form").modal('toggle');
- }).
- fail(function(data) {
- $("#backup-spinner").hide();
- popup_err("Failed to backup the server", data.message);
- });
- }
- }).
- fail(function() {
- popup_err("Failed to check the server status", data.message);
- });
-}
-
-$(window.document).ready(function() {
- if(navigator.userAgent.toLowerCase().indexOf('firefoxf') > -1) {
- $("select@@@").focus( function() {
- this.style.setProperty( 'outline', 'none', 'important' );
- this.style.setProperty( 'color', 'rgba(0,0,0,0)', 'important' );
- this.style.setProperty( 'text-shadow', '0 0 0 #000', 'important' );
- });
- }
-
- // Set an interval event to wait for all the pages to load, then load the config
- var init_config = setInterval(function() {
- /*
- * Stop, Start, and Restart server
- */
-
- let banner = document.getElementById("start-server-btn");
- if (banner == null) {
- // Not ready yet, return and try again
- return;
- }
-
- get_insts();
-
- /* Restore. load restore table with current backups */
- document.getElementById("restore-server-btn").addEventListener("click", function() {
- var cmd = [DSCTL, '-j', server_inst, 'backups'];
- log_cmd('#restore-server-btn (click)', 'Restore server instance', cmd);
- cockpit.spawn(cmd, { superuser: true, "err": "message", "environ": [ENV]}).done(function(data) {
- let backup_btn = "<button class=\"btn btn-default restore-btn\" type=\"button\">Restore</button>";
- let del_btn = "<button title=\"Delete backup directory\" class=\"btn btn-default ds-del-backup-btn\" type=\"button\"><span class='glyphicon glyphicon-trash'></span></button>";
- let obj = JSON.parse(data);
- backup_table.clear().draw( false );
- for (var i = 0; i < obj.items.length; i++) {
- let backup_name = obj.items[i][0];
- let backup_date = obj.items[i][1];
- let backup_size = obj.items[i][2];
- backup_table.row.add([backup_name, backup_date, backup_size, backup_btn, del_btn]).draw( false );
- }
- }).fail(function(data) {
- popup_err("Failed to get list of backups", data.message);
- });
- });
-
- document.getElementById("backup-server-btn").addEventListener("click", function() {
- $("#backup-name").val("");
- });
-
- document.getElementById("start-server-btn").addEventListener("click", function() {
- $("#ds-start-inst").html("<span class=\"spinner spinner-xs spinner-inline\"></span> Starting instance <b>" + server_id + "</b>...");
- $("#start-instance-form").modal('toggle');
- var cmd = [DSCTL, server_inst, 'start'];
- log_cmd('#start-server-btn (click)', 'Start server instance', cmd);
- cockpit.spawn(cmd, { superuser: true, "err": "message", "environ": [ENV]}).done(function(data) {
- $("#start-instance-form").modal('toggle');
- load_config(true);
- popup_success("Started instance \"" + server_id + "\"");
- }).fail(function(data) {
- $("#start-instance-form").modal('toggle');
- popup_err("Failed to start instance \"" + server_id, data.message);
- });
- });
-
- document.getElementById("stop-server-btn").addEventListener("click", function() {
- $("#ds-stop-inst").html("<span class=\"spinner spinner-xs spinner-inline\"></span> Stopping instance <b>" + server_id + "</b>...");
- $("#stop-instance-form").modal('toggle');
- var cmd = [DSCTL, server_inst, 'stop'];
- log_cmd('#stop-server-btn (click)', 'Stop server instance', cmd);
- cockpit.spawn(cmd, { superuser: true, "err": "message", "environ": [ENV]}).done(function(data) {
- $("#stop-instance-form").modal('toggle');
- popup_success("Stopped instance \"" + server_id + "\"");
- check_inst_alive();
- }).fail(function(data) {
- $("#stop-instance-form").modal('toggle');
- popup_err("Error", "Failed to stop instance \"" + server_id+ "\"", data.message);
- check_inst_alive();
- });
- });
-
-
- document.getElementById("restart-server-btn").addEventListener("click", function() {
- $("#ds-restart-inst").html("<span class=\"spinner spinner-xs spinner-inline\"></span> Restarting instance <b>" + server_id + "</b>...");
- $("#restart-instance-form").modal('toggle');
- var cmd = [DSCTL, server_inst, 'restart'];
- log_cmd('#restart-server-btn (click)', 'Restart server instance', cmd);
- cockpit.spawn(cmd, { superuser: true, "err": "message", "environ": [ENV]}).done(function(data) {
- $("#restart-instance-form").modal('toggle');
- load_config(true);
- popup_success("Restarted instance \"" + server_id + "\"");
- }).fail(function(data) {
- $("#restart-instance-form").modal('toggle');
- popup_err("Failed to restart instance \"" + server_id + "\"", data.message);
- });
- });
-
- document.getElementById("remove-server-btn").addEventListener("click", function() {
- popup_confirm("Are you sure you want to this remove instance: <b>" + server_id + "</b>", "Confirmation", function (yes) {
- if (yes) {
- var cmd = [DSCTL, server_inst, "remove", "--do-it"];
- $("#ds-remove-inst").html("<span class=\"spinner spinner-xs spinner-inline\"></span> Removing instance <b>" + server_id + "</b>...");
- $("#remove-instance-form").modal('toggle');
- log_cmd('#remove-server-btn (click)', 'Remove instance', cmd);
- cockpit.spawn(cmd, { superuser: true, "err": "message", "environ": [ENV]}).done(function(data) {
- $("#remove-instance-form").modal('toggle');
- popup_success("Instance has been deleted");
- get_insts();
- }).fail(function(data) {
- $("#remove-instance-form").modal('toggle');
- popup_err("Failed to remove instance", data.message);
- });
- }
- });
- });
- clearInterval(init_config);
- }, 250);
-
- $("#main-banner").load("banner.html");
- check_for_389();
-
- $("#server-tab").css( 'color', '#228bc0'); // Set first tab as highlighted
-
- // Events
- $(".ds-nav-choice").on('click', function (){
- // This highlights each nav tab when clicked
- $(".ds-tab-list").css( 'color', '#777');
- var tab = $(this).attr("parent-id");
- $("#" + tab).css( 'color', '#228bc0');
- });
-
- $("#server-tasks-btn").on("click", function() {
- $(".all-pages").hide();
- $("#server-tasks").show();
- });
- $("#server-tab").on("click", function() {
- $(".all-pages").hide();
- $("#server-content").show();
- });
- $("#plugin-tab").on("click", function() {
- $(".all-pages").hide();
- $("#plugin-content").show();
- });
- $("#database-tab").on("click", function() {
- $(".all-pages").hide();
- $("#database-content").show();
- });
- $("#monitor-tab").on("click", function() {
- $(".all-pages").hide();
- $("#monitor-content").show();
- });
- $("#schema-tab").on("click", function() {
- $(".all-pages").hide();
- $("#schema-content").show();
- });
- $("#replication-tab").on("click", function() {
- $(".all-pages").hide();
- $("#replication-content").show();
- });
-
- // Create instance form
- $("#create-server-btn").on("click", function() {
- clear_inst_form();
- set_ports();
- });
- $("#no-inst-create-btn").on("click", function () {
- clear_inst_form();
- });
-
- // backup/restore table
- var backup_table = $('#backup-table').DataTable( {
- "paging": true,
- "bAutoWidth": false,
- "dom": '<"pull-left"f><"pull-right"l>tip',
- "lengthMenu": [ 10, 25, 50, 100],
- "language": {
- "emptyTable": "No backups available for restore",
- "search": "Search Backups"
- },
- "columnDefs": [ {
- "targets": [3, 4],
- "orderable": false
- } ],
- "columns": [
- { "width": "120px" },
- { "width": "80px" },
- { "width": "30px" },
- { "width": "40px" },
- { "width": "30px" }
- ],
- });
-
- $(".all-pages").hide();
- $("#server-content").show();
-
- // To remove text border on firefox on dropdowns)
- if(navigator.userAgent.toLowerCase().indexOf('firefox') > -1) {
- $("select").focus( function() {
- this.style.setProperty( 'outline', 'none', 'important' );
- this.style.setProperty( 'color', 'rgba(0,0,0,0)', 'important' );
- this.style.setProperty( 'text-shadow', '0 0 0 #000', 'important' );
- });
- }
-
- $(".ds-tab-standalone").on('click', function (){
- $(".ds-tab-list").css( 'color', '#777');
- $(this).css( 'color', '#228bc0');
- });
-
- /* Backup server */
- $("#ds-backup-btn").on('click', function () {
- var backup_name = $("#backup-name").val();
- if (backup_name == ""){
- popup_msg("Error", "Backup must have a name");
- return;
- }
- if (backup_name.indexOf(' ') >= 0) {
- popup_msg("Error", "Backup name can not contain any spaces");
- return;
- }
- if (backup_name.indexOf('/') >= 0) {
- popup_msg("Error", "Backup name can not contain a forward slash. " +
- "Backups are written to the server's backup directory (nsslapd-bakdir)");
- return;
- }
-
- // First check if backup name is already used
- var check_cmd = [DSCTL, '-j', server_inst, 'backups'];
- log_cmd('#ds-backup-btn (click)', 'Restore server instance', check_cmd);
- cockpit.spawn(check_cmd, { superuser: true, "err": "message", "environ": [ENV]}).done(function(data) {
- var obj = JSON.parse(data);
- var found_backup = false;
- for (var i = 0; i < obj.items.length; i++) {
- if (obj.items[i][0] == backup_name) {
- found_backup = true;
- break;
- }
- }
- if (found_backup) {
- popup_confirm("A backup already exists with this name, replace it?", "Confirmation", function (yes) {
- if (yes) {
- do_backup(server_inst, backup_name);
- } else {
- return;
- }
- });
- } else {
- do_backup(server_inst, backup_name);
- }
- });
- });
-
- /* Restore server */
- $(document).on('click', '.restore-btn', function(e) {
- e.preventDefault();
- var data = backup_table.row( $(this).parents('tr') ).data();
- var restore_name = data[0];
- popup_confirm("Are you sure you want to restore this backup: <b>" + restore_name + "<b>", "Confirmation", function (yes) {
- if (yes) {
- var cmd = [DSCTL, '-j', server_inst, 'status'];
- $("#restore-spinner").show();
- cockpit.spawn(cmd, { superuser: true}).
- done(function(status_data) {
- var status_json = JSON.parse(status_data);
- if (status_json.running == true) {
- var cmd = [DSCONF, server_inst, 'backup', 'restore', restore_name];
- log_cmd('.restore-btn (click)', 'Restore server instance(online)', cmd);
- cockpit.spawn(cmd, { superuser: true, "err": "message", "environ": [ENV]}).
- done(function(data) {
- $("#restore-spinner").hide();
- popup_success("The backup has been restored");
- $("#restore-form").modal('toggle');
- }).
- fail(function(data) {
- $("#restore-spinner").hide();
- popup_err("Failed to restore from the backup", data.message);
- });
- } else {
- var cmd = [DSCTL, server_inst, 'bak2db', restore_name];
- log_cmd('.restore-btn (click)', 'Restore server instance(offline)', cmd);
- cockpit.spawn(cmd, { superuser: true, "err": "message", "environ": [ENV]}).
- done(function(data) {
- $("#restore-spinner").hide();
- popup_success("The backup has been restored");
- $("#restore-form").modal('toggle');
- }).
- fail(function(data) {
- $("#restore-spinner").hide();
- popup_err("Failed to restore from the backup", data.message);
- });
- }
- }).
- fail(function() {
- popup_err("Failed to check the server status", data.message);
- });
- }
- });
- });
-
- /* Delete backup directory */
- $(document).on('click', '.ds-del-backup-btn', function(e) {
- e.preventDefault();
- var data = backup_table.row( $(this).parents('tr') ).data();
- var restore_name = data[0];
- var backup_row = $(this);
- popup_confirm("Are you sure you want to delete this backup: <b>" + restore_name + "</b>", "Confirmation", function (yes) {
- if (yes) {
- var cmd = [DSCTL, server_inst, 'backups', '--delete', restore_name];
- $("#restore-spinner").show();
- log_cmd('.ds-del-backup-btn (click)', 'Delete backup', cmd);
- cockpit.spawn(cmd, { superuser: true, "err": "message", "environ": [ENV]}).done(function(data) {
- $("#restore-spinner").hide();
- backup_table.row( backup_row.parents('tr') ).remove().draw( false );
- popup_success("The backup has been deleted");
- }).fail(function(data) {
- $("#restore-spinner").hide();
- popup_err("Failed to delete the backup", data.message);
- });
- }
- });
- });
-
- /* reload schema */
- $("#schema-reload-btn").on("click", function () {
- var schema_dir = $("#reload-dir").val();
- if (schema_dir != ""){
- var cmd = [DSCONF, server_inst, 'schema', 'reload', '--schemadir', schema_dir, '--wait'];
- } else {
- var cmd = [DSCONF, server_inst, 'schema', 'reload', '--wait'];
- }
- $("#reload-spinner").show();
- log_cmd('#schema-reload-btn (click)', 'Reload schema files', cmd);
- cockpit.spawn(cmd, { superuser: true, "err": "message", "environ": [ENV]}).done(function(data) {
- popup_success("Successfully reloaded schema"); // TODO use timed interval success msg (waiting for another PR top be merged before we can add it)
- $("#schema-reload-form").modal('toggle');
- $("#reload-spinner").hide();
- }).fail(function(data) {
- popup_err("Failed to reload schema files", data.message);
- $("#reload-spinner").hide();
- });
- });
-
-
-});
diff --git a/src/cockpit/389-console/src/ds.jsx b/src/cockpit/389-console/src/ds.jsx
new file mode 100644
index 0000000..439a850
--- /dev/null
+++ b/src/cockpit/389-console/src/ds.jsx
@@ -0,0 +1,1917 @@
+import cockpit from "cockpit";
+import React from "react";
+import PropTypes from "prop-types";
+import { Plugins } from "./plugins.jsx";
+import { Database } from "./database.jsx";
+import { Monitor } from "./monitor.jsx";
+import { Schema } from "./schema.jsx";
+import { Replication } from "./replication.jsx";
+import { Server } from "./server.jsx";
+import { ConfirmPopup, DoubleConfirmModal, NotificationController } from "./lib/notifications.jsx";
+import { BackupTable } from "./lib/database/databaseTables.jsx";
+import { BackupModal, RestoreModal, DeleteBackupModal } from "./lib/database/backups.jsx";
+import { log_cmd, bad_file_name } from "./lib/tools.jsx";
+import {
+ Nav,
+ NavItem,
+ DropdownButton,
+ MenuItem,
+ TabContainer,
+ TabContent,
+ TabPane,
+ ProgressBar,
+ FormControl,
+ FormGroup,
+ ControlLabel,
+ Radio,
+ Form,
+ noop,
+ Checkbox,
+ Spinner,
+ Row,
+ Modal,
+ Icon,
+ Col,
+ Button
+} from "patternfly-react";
+import "./css/ds.css";
+
+const staticStates = {
+ noPackage: (
+ <h3>
+ There is no <b>389-ds-base</b> package installed on this system. Sorry there is nothing
+ to manage...
+ </h3>
+ ),
+ noInsts: <h3>There are no Directory Server instances to manage</h3>,
+ notRunning: (
+ <h3>
+ This server instance is not running, either start it from the <b>Actions</b> dropdown
+ menu, or choose a different instance
+ </h3>
+ ),
+ notConnecting: (
+ <h3>
+ This server instance is running, but we can not connect to it. Check LDAPI is properly
+ configured on this instance.
+ </h3>
+ )
+};
+
+export class DSInstance extends React.Component {
+ componentWillMount() {
+ this.checkPackageAndLoad();
+ }
+
+ constructor(props) {
+ super(props);
+ this.state = {
+ pageLoadingState: { state: "loading", jsx: "" },
+ serverId: "",
+ instList: [],
+ backupRows: [],
+ notifications: [],
+ activeKey: 1,
+ wasActiveList: [1],
+ progressValue: 0,
+ loadingOperate: false,
+
+ showDeleteConfirm: false,
+ modalSpinning: false,
+ modalChecked: false,
+
+ showSchemaReloadModal: false,
+ showManageBackupsModal: false,
+ showCreateInstanceModal: false
+ };
+
+ this.handleServerIdChange = this.handleServerIdChange.bind(this);
+ this.handleFieldChange = this.handleFieldChange.bind(this);
+ this.addNotification = this.addNotification.bind(this);
+ this.removeNotification = this.removeNotification.bind(this);
+ this.handleNavSelect = this.handleNavSelect.bind(this);
+ this.loadInstanceList = this.loadInstanceList.bind(this);
+ this.loadBackups = this.loadBackups.bind(this);
+ this.setServerId = this.setServerId.bind(this);
+ this.checkPackageAndLoad = this.checkPackageAndLoad.bind(this);
+ this.updateProgress = this.updateProgress.bind(this);
+ this.openCreateInstanceModal = this.openCreateInstanceModal.bind(this);
+ this.closeCreateInstanceModal = this.closeCreateInstanceModal.bind(this);
+ this.operateInstance = this.operateInstance.bind(this);
+ this.openManageBackupsModal = this.openManageBackupsModal.bind(this);
+ this.closeManageBackupsModal = this.closeManageBackupsModal.bind(this);
+ this.openSchemaReloadModal = this.openSchemaReloadModal.bind(this);
+ this.closeSchemaReloadModal = this.closeSchemaReloadModal.bind(this);
+ this.removeInstance = this.removeInstance.bind(this);
+ this.showDeleteConfirm = this.showDeleteConfirm.bind(this);
+ this.closeDeleteConfirm = this.closeDeleteConfirm.bind(this);
+ }
+
+ updateProgress(value) {
+ this.setState(
+ prevState => ({
+ progressValue: prevState.progressValue + value
+ }),
+ () => {
+ if (this.state.progressValue >= 100) {
+ this.setState(prevState => ({
+ pageLoadingState: {
+ ...prevState.pageLoadingState,
+ state: "success"
+ }
+ }));
+ } else {
+ this.setState(prevState => ({
+ pageLoadingState: {
+ ...prevState.pageLoadingState,
+ state: "loading"
+ }
+ }));
+ }
+ }
+ );
+ }
+
+ setServerId(serverId, action) {
+ // First we need to check if the instance is alive and well
+ let cmd = ["dsctl", "-j", serverId, "status"];
+ log_cmd("setServerId", "Test if instance is running ", cmd);
+ cockpit
+ .spawn(cmd, { superuser: true, err: "message" })
+ .done(status_data => {
+ let status_json = JSON.parse(status_data);
+ if (status_json.running) {
+ let cmd = [
+ "dsconf",
+ "-j",
+ "ldapi://%2fvar%2frun%2fslapd-" + serverId + ".socket",
+ "backend",
+ "suffix",
+ "list",
+ "--suffix"
+ ];
+ log_cmd("setServerId", "Test if instance is alive ", cmd);
+ cockpit
+ .spawn(cmd, { superuser: true, err: "message" })
+ .done(_ => {
+ this.setState(
+ {
+ serverId: serverId
+ },
+ () => {
+ this.setState(prevState => ({
+ pageLoadingState: {
+ ...prevState.pageLoadingState,
+ state: "success"
+ }
+ }));
+ this.loadBackups();
+ }
+ );
+ if (action === "restart") {
+ this.setState(
+ {
+ serverId: ""
+ },
+ () => {
+ this.setState({
+ serverId: serverId
+ });
+ }
+ );
+ }
+ this.updateProgress(25);
+ })
+ .fail(err => {
+ let errMsg = JSON.parse(err);
+ console.log("setServerId failed: ", errMsg.desc);
+ this.setState(
+ {
+ pageLoadingState: {
+ state: "notConnecting",
+ jsx: staticStates["notConnecting"]
+ }
+ },
+ () => {
+ this.setState({
+ serverId: serverId
+ });
+ }
+ );
+ });
+ this.updateProgress(25);
+ } else {
+ this.setState(
+ {
+ pageLoadingState: {
+ state: "notRunning",
+ jsx: staticStates["notRunning"]
+ }
+ },
+ () => {
+ this.setState({
+ serverId: serverId
+ });
+ }
+ );
+ }
+ })
+ .fail(err => {
+ let errMsg = JSON.parse(err);
+ console.log("setServerId failed: ", errMsg.desc);
+ this.setState(
+ {
+ pageLoadingState: {
+ state: "notConnecting",
+ jsx: staticStates["notConnecting"]
+ }
+ },
+ () => {
+ this.setState({
+ serverId: serverId
+ });
+ }
+ );
+ });
+ }
+
+ checkPackageAndLoad() {
+ let cmd = ["rpm", "-q", "389-ds-base"];
+ log_cmd("checkPackageAndLoad", "Check if 389-ds-base package is installed", cmd);
+ cockpit
+ .spawn(cmd, { superuser: true })
+ .done(_ => {
+ this.updateProgress(25);
+ this.loadInstanceList();
+ })
+ .fail(_ => {
+ this.setState({
+ pageLoadingState: {
+ state: "noPackage",
+ jsx: staticStates["noPackage"]
+ }
+ });
+ });
+ }
+
+ loadInstanceList(serverId, action) {
+ if (serverId === undefined) {
+ this.setState(prevState => ({
+ pageLoadingState: {
+ ...prevState.pageLoadingState,
+ state: "loading"
+ }
+ }));
+ }
+ let cmd = ["dsctl", "-l", "-j"];
+ log_cmd("loadInstanceList", "Load the instance list select", cmd);
+ cockpit
+ .spawn(cmd, { superuser: true })
+ .done(data => {
+ let myObject = JSON.parse(data);
+ this.setState({
+ instList: myObject.insts,
+ loadingOperate: false
+ });
+ // Set default value for the inst select
+ if (serverId !== undefined && serverId !== "") {
+ this.setState({
+ wasActiveList: [this.state.activeKey]
+ });
+ this.setServerId(serverId, action);
+ } else {
+ if (myObject.insts.length > 0) {
+ this.setState({
+ wasActiveList: [this.state.activeKey]
+ });
+ this.setServerId(myObject.insts[0].replace("slapd-", ""), action);
+ } else {
+ this.setState({
+ serverId: "",
+ pageLoadingState: {
+ state: "noInsts",
+ jsx: staticStates["noInsts"]
+ }
+ });
+ }
+ }
+ this.updateProgress(25);
+ })
+ .fail(_ => {
+ this.setState({
+ instList: [],
+ serverId: "",
+ loadingOperate: false,
+ pageLoadingState: {
+ state: "noInsts",
+ jsx: staticStates["noInsts"]
+ }
+ });
+ });
+ }
+
+ loadBackups() {
+ this.setState({
+ loadingOperate: true
+ });
+ const cmd = ["dsctl", "-j", this.state.serverId, "backups"];
+ log_cmd("loadBackupsDSInstance", "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,
+ loadingOperate: false
+ });
+ });
+ }
+
+ 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
+ )
+ });
+ }
+
+ handleNavSelect(key) {
+ this.setState({
+ activeKey: key
+ });
+ const { wasActiveList } = this.state;
+ if (!wasActiveList.includes(key)) {
+ let newList = wasActiveList.concat(key);
+ this.setState({
+ wasActiveList: newList
+ });
+ }
+ }
+
+ handleServerIdChange(e) {
+ this.loadInstanceList(e.target.value);
+ }
+
+ handleFieldChange(e) {
+ let value = e.target.type === "checkbox" ? e.target.checked : e.target.value;
+ if (e.target.type === "number") {
+ if (e.target.value) {
+ value = parseInt(e.target.value);
+ } else {
+ value = 1;
+ }
+ }
+ this.setState({
+ [e.target.id]: value
+ });
+ }
+
+ removeInstance() {
+ this.operateInstance();
+ this.closeDeleteConfirm();
+ }
+
+ operateInstance(e) {
+ this.setState({
+ loadingOperate: true
+ });
+
+ let action = "remove";
+ if (e !== undefined) {
+ action = e.target.id.split("-")[0];
+ }
+
+ let cmd = ["dsctl", "-j", this.state.serverId, action];
+ if (action === "remove") {
+ cmd = [...cmd, "--do-it"];
+ }
+ log_cmd("operateInstance", `Do ${action} the instance`, cmd);
+ cockpit
+ .spawn(cmd, { superuser: true, err: "message" })
+ .done(_ => {
+ if (action === "remove") {
+ this.loadInstanceList();
+ } else {
+ this.loadInstanceList(this.state.serverId, action);
+ }
+ if (action === "remove") {
+ this.addNotification("success", "Instance was successfully removed");
+ } else {
+ this.addNotification("success", `Instance was successfully ${action}ed`);
+ }
+ })
+ .fail(err => {
+ let errMsg = JSON.parse(err);
+ this.addNotification(
+ "error",
+ `Error during instance ${action} operation - ${errMsg.desc}`
+ );
+ this.loadInstanceList(this.state.serverId, action);
+ });
+ }
+
+ openCreateInstanceModal() {
+ this.setState({
+ showCreateInstanceModal: true
+ });
+ }
+
+ closeCreateInstanceModal() {
+ this.setState({
+ showCreateInstanceModal: false
+ });
+ }
+
+ openManageBackupsModal() {
+ this.setState({
+ showManageBackupsModal: true
+ });
+ }
+
+ closeManageBackupsModal() {
+ this.setState({
+ showManageBackupsModal: false
+ });
+ }
+
+ openSchemaReloadModal() {
+ this.setState({
+ showSchemaReloadModal: true
+ });
+ }
+
+ closeSchemaReloadModal() {
+ this.setState({
+ showSchemaReloadModal: false
+ });
+ }
+
+ showDeleteConfirm() {
+ this.setState({
+ showDeleteConfirm: true,
+ modalSpinning: false,
+ modalChecked: false
+ });
+ }
+
+ closeDeleteConfirm() {
+ this.setState({
+ showDeleteConfirm: false,
+ modalSpinning: false,
+ modalChecked: false
+ });
+ }
+
+ render() {
+ const {
+ instList,
+ serverId,
+ progressValue,
+ notifications,
+ pageLoadingState,
+ loadingOperate
+ } = this.state;
+
+ let mainContent = "";
+
+ if (pageLoadingState.state === "loading") {
+ mainContent = (
+ <div id="loading-instances" className="all-pages ds-center">
+ <div id="loading-page" className="ds-center ds-loading">
+ <h4 id="loading-msg">Loading Directory Server Configuration...</h4>
+ <p className="ds-margin-top-lg">
+ <span className="spinner spinner-lg spinner-inline" />
+ </p>
+ <div className="progress ds-margin-top-lg">
+ <ProgressBar active now={progressValue} label={`${progressValue}%`} />
+ </div>
+ </div>
+ </div>
+ );
+ } else if (pageLoadingState.state === "noInsts") {
+ mainContent = (
+ <div id="noInsts" className="all-pages ds-center">
+ {pageLoadingState.jsx}
+ <p>
+ <Button
+ id="no-inst-create-btn"
+ bsStyle="primary"
+ onClick={this.openCreateInstanceModal}
+ >
+ Create New Instance
+ </Button>
+ </p>
+ </div>
+ );
+ } else {
+ mainContent = (
+ <div id={pageLoadingState.state} className="all-pages ds-center">
+ {pageLoadingState.jsx}
+ </div>
+ );
+ }
+
+ let operateSpinner = "";
+ if (loadingOperate) {
+ operateSpinner = <Spinner className="ds-operate-spinner" loading inline size="md" />;
+ }
+
+ return (
+ <div>
+ <NotificationController
+ notifications={notifications}
+ removeNotificationAction={this.removeNotification}
+ />
+ {pageLoadingState.state !== "loading" &&
+ pageLoadingState.state !== "noInsts" &&
+ pageLoadingState.state !== "noPackage" ? (
+ <div className="ds-logo" hidden={pageLoadingState.state === "loading"}>
+ <h2 className="ds-logo-style" id="main-banner">
+ 389 Directory Server Management
+ <div className="dropdown ds-server-action">
+ <select
+ className="btn btn-default dropdown"
+ title="Directory Server Instance List"
+ id="serverId"
+ value={serverId}
+ onChange={this.handleServerIdChange}
+ >
+ {Object.entries(instList).map(([_, inst]) => (
+ <option key={inst} value={inst.replace("slapd-", "")}>
+ {inst}
+ </option>
+ ))}
+ </select>
+ </div>
+ {operateSpinner}
+ <div className="dropdown ds-float-right">
+ <DropdownButton
+ pullRight
+ id="ds-action"
+ className="ds-action-button"
+ bsStyle="primary"
+ title="Actions"
+ >
+ <MenuItem
+ id="start-ds"
+ eventKey="1"
+ onClick={this.operateInstance}
+ >
+ Start Instance
+ </MenuItem>
+ <MenuItem
+ id="stop-ds"
+ eventKey="2"
+ onClick={this.operateInstance}
+ >
+ Stop Instance
+ </MenuItem>
+ <MenuItem
+ id="restart-ds"
+ eventKey="3"
+ onClick={this.operateInstance}
+ >
+ Restart Instance
+ </MenuItem>
+ <MenuItem
+ id="manage-backup-ds"
+ eventKey="4"
+ onClick={this.openManageBackupsModal}
+ >
+ Manage Backups
+ </MenuItem>
+ <MenuItem
+ id="reload-schema-ds"
+ eventKey="5"
+ onClick={this.openSchemaReloadModal}
+ >
+ Reload Schema Files
+ </MenuItem>
+ <MenuItem
+ id="remove-ds"
+ eventKey="6"
+ onClick={this.showDeleteConfirm}
+ >
+ Remove Instance
+ </MenuItem>
+ <MenuItem
+ id="create-ds"
+ eventKey="7"
+ onClick={this.openCreateInstanceModal}
+ >
+ Create Instance
+ </MenuItem>
+ </DropdownButton>
+ </div>
+ </h2>
+ </div>
+ ) : (
+ <div />
+ )}
+ {serverId !== "" &&
+ (pageLoadingState.state === "success" || pageLoadingState.state === "loading") ? (
+ <div>
+ <div hidden={pageLoadingState.state === "loading"}>
+ <TabContainer
+ id="basic-tabs-pf"
+ onSelect={this.handleNavSelect}
+ activeKey={this.state.activeKey}
+ >
+ <div>
+ <Nav className="nav nav-tabs nav-tabs-pf collapse navbar-collapse navbar-collapse-5 ds-nav navbar navbar-default">
+ <NavItem className="ds-tab-main" eventKey={1}>
+ Server Settings
+ </NavItem>
+ <NavItem className="ds-tab-main" eventKey={2}>
+ Database
+ </NavItem>
+ <NavItem className="ds-tab-main" eventKey={3}>
+ Replication
+ </NavItem>
+ <NavItem className="ds-tab-main" eventKey={4}>
+ Schema
+ </NavItem>
+ <NavItem className="ds-tab-main" eventKey={5}>
+ Plugins
+ </NavItem>
+ <NavItem className="ds-tab-main" eventKey={6}>
+ Monitoring
+ </NavItem>
+ </Nav>
+ <TabContent>
+ <TabPane eventKey={1}>
+ <Server
+ addNotification={this.addNotification}
+ serverId={this.state.serverId}
+ wasActiveList={this.state.wasActiveList}
+ />
+ </TabPane>
+ <TabPane eventKey={2}>
+ <Database
+ addNotification={this.addNotification}
+ serverId={this.state.serverId}
+ wasActiveList={this.state.wasActiveList}
+ />
+ </TabPane>
+ <TabPane eventKey={3}>
+ <Replication
+ addNotification={this.addNotification}
+ serverId={this.state.serverId}
+ wasActiveList={this.state.wasActiveList}
+ />
+ </TabPane>
+ <TabPane eventKey={4}>
+ <Schema
+ addNotification={this.addNotification}
+ serverId={this.state.serverId}
+ wasActiveList={this.state.wasActiveList}
+ />
+ </TabPane>
+ <TabPane eventKey={5}>
+ <Plugins
+ addNotification={this.addNotification}
+ serverId={this.state.serverId}
+ wasActiveList={this.state.wasActiveList}
+ />
+ </TabPane>
+ <TabPane eventKey={6}>
+ <Monitor
+ addNotification={this.addNotification}
+ serverId={this.state.serverId}
+ wasActiveList={this.state.wasActiveList}
+ />
+ </TabPane>
+ </TabContent>
+ </div>
+ </TabContainer>
+ </div>
+ <div hidden={pageLoadingState.state !== "loading"}>{mainContent}</div>
+ </div>
+ ) : (
+ <div>{mainContent}</div>
+ )}
+ <CreateInstanceModal
+ showModal={this.state.showCreateInstanceModal}
+ closeHandler={this.closeCreateInstanceModal}
+ addNotification={this.addNotification}
+ serverId={this.state.serverId}
+ loadInstanceList={this.loadInstanceList}
+ />
+ <SchemaReloadModal
+ showModal={this.state.showSchemaReloadModal}
+ closeHandler={this.closeSchemaReloadModal}
+ addNotification={this.addNotification}
+ serverId={this.state.serverId}
+ />
+ <ManageBackupsModal
+ addNotification={this.addNotification}
+ serverId={this.state.serverId}
+ showModal={this.state.showManageBackupsModal}
+ closeHandler={this.closeManageBackupsModal}
+ handleChange={this.handleFieldChange}
+ backups={this.state.backupRows}
+ reload={this.loadBackups}
+ />
+ <DoubleConfirmModal
+ showModal={this.state.showDeleteConfirm}
+ closeHandler={this.closeDeleteConfirm}
+ handleChange={this.handleFieldChange}
+ actionHandler={this.removeInstance}
+ spinning={this.state.modalSpinning}
+ item={this.state.serverId}
+ checked={this.state.modalChecked}
+ mTitle="Remove Instance"
+ mMsg="Are you really sure you want to delete this instance?"
+ mSpinningMsg="Removing Instance..."
+ mBtnName="Remove Instance"
+ />
+ </div>
+ );
+ }
+}
+
+class CreateInstanceModal extends React.Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ createServerId: "",
+ createPort: 389,
+ createSecurePort: 636,
+ createDM: "cn=Directory Manager",
+ createDMPassword: "",
+ createDMPasswordConfirm: "",
+ createDBSuffix: "",
+ createDBName: "",
+ createTLSCert: true,
+ createInitDB: "",
+ loadingCreate: false
+ };
+
+ this.handleFieldChange = this.handleFieldChange.bind(this);
+ this.createInstance = this.createInstance.bind(this);
+ }
+
+ handleFieldChange(e) {
+ let value = e.target.type === "checkbox" ? e.target.checked : e.target.value;
+ if (e.target.type === "number") {
+ if (e.target.value) {
+ value = parseInt(e.target.value);
+ } else {
+ value = 1;
+ }
+ }
+ this.setState({
+ [e.target.id]: value
+ });
+ }
+
+ createInstance() {
+ const {
+ createServerId,
+ createPort,
+ createSecurePort,
+ createDM,
+ createDMPassword,
+ createDMPasswordConfirm,
+ createDBSuffix,
+ createDBName,
+ createTLSCert,
+ createInitDB
+ } = this.state;
+ const { closeHandler, addNotification, loadInstanceList } = this.props;
+
+ let setup_inf =
+ "[general]\n" +
+ "config_version = 2\n" +
+ "full_machine_name = FQDN\n\n" +
+ "[slapd]\n" +
+ "user = dirsrv\n" +
+ "group = dirsrv\n" +
+ "instance_name = INST_NAME\n" +
+ "port = PORT\n" +
+ "root_dn = ROOTDN\n" +
+ "root_password = ROOTPW\n" +
+ "secure_port = SECURE_PORT\n" +
+ "self_sign_cert = SELF_SIGN\n";
+
+ // Server ID
+ let newServerId = createServerId;
+ if (newServerId === "") {
+ addNotification("warning", "Instance Name is required.");
+ return;
+ }
+ newServerId = newServerId.replace(/^slapd-/i, ""); // strip "slapd-"
+ if (newServerId.length > 128) {
+ addNotification(
+ "warning",
+ "Instance name is too long, it must not exceed 128 characters"
+ );
+ return;
+ }
+ if (newServerId.match(/^[#%:A-Za-z0-9_-]+$/g)) {
+ setup_inf = setup_inf.replace("INST_NAME", newServerId);
+ } else {
+ addNotification(
+ "warning",
+ "Instance name can only contain letters, numbers, and: # % : - _"
+ );
+ return;
+ }
+
+ // Port
+ if (createPort < 1 || createPort > 65535) {
+ addNotification("warning", "Port must be a number between 1 and 65534!");
+ return;
+ } else {
+ setup_inf = setup_inf.replace("PORT", createPort);
+ }
+
+ // Secure Port
+ if (createSecurePort < 1 || createSecurePort > 65535) {
+ addNotification("warning", "Secure Port must be a number between 1 and 65534!");
+ return;
+ } else {
+ setup_inf = setup_inf.replace("SECURE_PORT", createSecurePort);
+ }
+
+ // Root DN
+ if (createDM === "") {
+ addNotification("warning", "You must provide a Directory Manager DN");
+ return;
+ } else {
+ setup_inf = setup_inf.replace("ROOTDN", createDM);
+ }
+
+ // Setup Self-Signed Certs
+ if (createTLSCert) {
+ setup_inf = setup_inf.replace("SELF_SIGN", "True");
+ } else {
+ setup_inf = setup_inf.replace("SELF_SIGN", "False");
+ }
+
+ // Root DN password
+ if (createDMPassword != createDMPasswordConfirm) {
+ addNotification("warning", "Directory Manager passwords do not match!");
+ return;
+ } else if (createDMPassword == "") {
+ addNotification("warning", "Directory Manager password can not be empty!");
+ return;
+ } else if (createDMPassword.length < 8) {
+ addNotification(
+ "warning",
+ "Directory Manager password must have at least 8 characters"
+ );
+ return;
+ } else {
+ setup_inf = setup_inf.replace("ROOTPW", createDMPassword);
+ }
+
+ // Backend/Suffix
+ if (
+ (createDBName != "" && createDBSuffix == "") ||
+ (createDBName == "" && createDBSuffix != "")
+ ) {
+ if (createDBName == "") {
+ addNotification(
+ "warning",
+ "If you specify a backend suffix, you must also specify a backend name"
+ );
+ return;
+ } else {
+ addNotification(
+ "warning",
+ "If you specify a backend name, you must also specify a backend suffix"
+ );
+ return;
+ }
+ }
+ if (createDBName != "") {
+ // We definitely have a backend name and suffix, next validate the suffix is a DN
+ let dn_regex = new RegExp("^([A-Za-z]+=.*)");
+ if (dn_regex.test(createDBSuffix)) {
+ // It's valid, add it
+ setup_inf += "\n[backend-" + createDBName + "]\nsuffix = " + createDBSuffix + "\n";
+ } else {
+ // Not a valid DN
+ addNotification("warning", "Invalid DN for Backend Suffix");
+ return;
+ }
+
+ if (createInitDB === "createSample") {
+ setup_inf += "\nsample_entries = yes\n";
+ }
+ if (createInitDB === "createSuffix") {
+ setup_inf += "\ncreate_suffix_entry = yes\n";
+ }
+ }
+
+ /*
+ * Here are steps we take to create the instance
+ *
+ * [1] Get FQDN Name for nsslapd-localhost setting in setup file
+ * [2] Create a file for the inf setup parameters
+ * [3] Set strict permissions on that file
+ * [4] Populate the new setup file with settings (including cleartext password)
+ * [5] Create the instance
+ * [6] Remove setup file
+ */
+ this.setState({
+ loadingCreate: true
+ });
+ cockpit
+
+ .spawn(["hostnamectl", "status", "--static"], { superuser: true, err: "message" })
+ .fail(err => {
+ let errMsg = JSON.parse(err);
+ this.setState({
+ loadingCreate: false
+ });
+ addNotification("error", `Failed to get hostname!", ${errMsg.desc}`);
+ })
+ .done(data => {
+ /*
+ * We have FQDN, so set the hostname in inf file, and create the setup file
+ */
+ setup_inf = setup_inf.replace("FQDN", data);
+ let setup_file = "/tmp/389-setup-" + new Date().getTime() + ".inf";
+ let rm_cmd = ["rm", setup_file];
+ let create_file_cmd = ["touch", setup_file];
+ cockpit
+ .spawn(create_file_cmd, { superuser: true, err: "message" })
+ .fail(err => {
+ let errMsg = JSON.parse(err);
+ this.setState({
+ loadingCreate: false
+ });
+ addNotification(
+ "error",
+ `Failed to create installation file!" ${errMsg.desc}`
+ );
+ })
+ .done(_ => {
+ /*
+ * We have our new setup file, now set permissions on that setup file before we add sensitive data
+ */
+ let chmod_cmd = ["chmod", "600", setup_file];
+ cockpit
+ .spawn(chmod_cmd, { superuser: true, err: "message" })
+ .fail(err => {
+ let errMsg = JSON.parse(err);
+ cockpit.spawn(rm_cmd, { superuser: true }); // Remove Inf file with clear text password
+ this.setState({
+ loadingCreate: false
+ });
+ addNotification(
+ "error",
+ `Failed to set permission on setup file ${setup_file}: ${
+ errMsg.desc
+ }`
+ );
+ })
+ .done(_ => {
+ /*
+ * Success we have our setup file and it has the correct permissions.
+ * Now populate the setup file...
+ */
+ let cmd = [
+ "/bin/sh",
+ "-c",
+ '/usr/bin/echo -e "' + setup_inf + '" >> ' + setup_file
+ ];
+ cockpit
+ .spawn(cmd, { superuser: true, err: "message" })
+ .fail(err => {
+ let errMsg = JSON.parse(err);
+ this.setState({
+ loadingCreate: false
+ });
+ addNotification(
+ "error",
+ `Failed to populate installation file! ${errMsg.desc}`
+ );
+ })
+ .done(_ => {
+ /*
+ * Next, create the instance...
+ */
+ let cmd = ["dscreate", "from-file", setup_file];
+ cockpit
+ .spawn(cmd, {
+ superuser: true,
+ err: "message"
+ })
+ .fail(_ => {
+ cockpit.spawn(rm_cmd, { superuser: true }); // Remove Inf file with clear text password
+ this.setState({
+ loadingCreate: false
+ });
+ addNotification(
+ "error",
+ "Failed to create instance!"
+ );
+ })
+ .done(_ => {
+ // Success!!! Now cleanup everything up...
+ cockpit.spawn(rm_cmd, { superuser: true }); // Remove Inf file with clear text password
+ this.setState({
+ loadingCreate: false
+ });
+
+ loadInstanceList(createServerId);
+ addNotification(
+ "success",
+ `Successfully created instance: slapd-${createServerId}`
+ );
+ closeHandler();
+ });
+ });
+ });
+ });
+ });
+ }
+
+ render() {
+ const { showModal, closeHandler } = this.props;
+
+ const {
+ loadingCreate,
+ createServerId,
+ createPort,
+ createSecurePort,
+ createDM,
+ createDMPassword,
+ createDMPasswordConfirm,
+ createDBSuffix,
+ createDBName,
+ createTLSCert,
+ createInitDB
+ } = this.state;
+
+ let createSpinner = "";
+ if (loadingCreate) {
+ createSpinner = (
+ <Row>
+ <div className="ds-margin-top-lg ds-modal-spinner">
+ <Spinner loading inline size="lg" />
+ Creating instance...
+ </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>Create New Server Instance</Modal.Title>
+ </Modal.Header>
+ <Modal.Body>
+ <Form horizontal>
+ <FormGroup controlId="createServerId">
+ <Col
+ componentClass={ControlLabel}
+ sm={4}
+ title="The instance name, this is what gets appended to 'slapi-'. The instance name can only contain letters, numbers, and: # % : - _"
+ >
+ Instance Name
+ </Col>
+ <Col sm={8}>
+ <FormControl
+ id="createServerId"
+ type="text"
+ placeholder="Your_Instance_Name"
+ value={createServerId}
+ onChange={this.handleFieldChange}
+ />
+ </Col>
+ </FormGroup>
+ <FormGroup controlId="createPort">
+ <Col
+ componentClass={ControlLabel}
+ sm={4}
+ title="The server port number"
+ >
+ Port
+ </Col>
+ <Col sm={8}>
+ <FormControl
+ type="number"
+ min="0"
+ max="65535"
+ value={createPort}
+ onChange={this.handleFieldChange}
+ />
+ </Col>
+ </FormGroup>
+ <FormGroup controlId="createSecurePort">
+ <Col
+ componentClass={ControlLabel}
+ sm={4}
+ title="The secure port number for TLS connections"
+ >
+ Secure Port
+ </Col>
+ <Col sm={8}>
+ <FormControl
+ type="number"
+ min="0"
+ max="65535"
+ value={createSecurePort}
+ onChange={this.handleFieldChange}
+ />
+ </Col>
+ </FormGroup>
+ <FormGroup controlId="createTLSCert">
+ <Col
+ componentClass={ControlLabel}
+ sm={4}
+ title="Create a self-signed certificate database"
+ >
+ Create Self-Signed TLS Certificate DB
+ </Col>
+ <Col sm={8}>
+ <Checkbox
+ id="createTLSCert"
+ checked={createTLSCert}
+ onChange={this.handleFieldChange}
+ />
+ </Col>
+ </FormGroup>
+ <FormGroup controlId="createDM">
+ <Col
+ componentClass={ControlLabel}
+ sm={4}
+ title="The DN for the unrestricted user"
+ >
+ Directory Manager DN
+ </Col>
+ <Col sm={8}>
+ <FormControl
+ type="text"
+ id="createDM"
+ onChange={this.handleFieldChange}
+ value={createDM}
+ />
+ </Col>
+ </FormGroup>
+ <FormGroup controlId="createDMPassword">
+ <Col
+ componentClass={ControlLabel}
+ sm={4}
+ title="Directory Manager password."
+ >
+ Directory Manager Password
+ </Col>
+ <Col sm={8}>
+ <FormControl
+ id="createDMPassword"
+ type="password"
+ placeholder="Enter password"
+ onChange={this.handleFieldChange}
+ value={createDMPassword}
+ />
+ </Col>
+ </FormGroup>
+ <FormGroup controlId="createDMPasswordConfirm">
+ <Col componentClass={ControlLabel} sm={4} title="Confirm password.">
+ Confirm Password
+ </Col>
+ <Col sm={8}>
+ <FormControl
+ id="createDMPasswordConfirm"
+ type="password"
+ placeholder="Confirm password"
+ onChange={this.handleFieldChange}
+ value={createDMPasswordConfirm}
+ />
+ </Col>
+ </FormGroup>
+ <hr />
+ <h5 className="ds-center">Optional Database Settings</h5>
+ <FormGroup controlId="createDBSuffix">
+ <Col
+ componentClass={ControlLabel}
+ sm={4}
+ title="Database suffix, like 'dc=example,dc=com'. The suffix must be a valid LDAP Distiguished Name (DN)"
+ >
+ Database Suffix
+ </Col>
+ <Col sm={8}>
+ <FormControl
+ type="text"
+ id="createDBSuffix"
+ placeholder="e.g. dc=example,dc=com"
+ onChange={this.handleFieldChange}
+ value={createDBSuffix}
+ />
+ </Col>
+ </FormGroup>
+ <FormGroup controlId="createDBName">
+ <Col
+ componentClass={ControlLabel}
+ sm={4}
+ title="The name for the backend database, like 'userroot'. The name can be a combination of alphanumeric characters, dashes (-), and underscores (_). No other characters are allowed, and the name must be unique across all backends."
+ >
+ Database Name
+ </Col>
+ <Col sm={8}>
+ <FormControl
+ type="text"
+ id="createDBName"
+ placeholder="e.g. userRoot"
+ onChange={this.handleFieldChange}
+ value={createDBName}
+ />
+ </Col>
+ </FormGroup>
+ <FormGroup
+ key="createInitDBn"
+ controlId="createInitDBn"
+ disabled={false}
+ >
+ <Col smOffset={4} sm={8}>
+ <Radio
+ id="createInitDB"
+ value="noInit"
+ name="noInit"
+ inline
+ checked={createInitDB === "noInit"}
+ onChange={this.handleFieldChange}
+ >
+ Do Not Initialize Database
+ </Radio>
+ </Col>
+ </FormGroup>
+ <FormGroup
+ key="createInitDBs"
+ controlId="createInitDBs"
+ disabled={false}
+ >
+ <Col smOffset={4} sm={8}>
+ <Radio
+ id="createInitDB"
+ value="createSuffix"
+ name="createSuffix"
+ inline
+ checked={createInitDB === "createSuffix"}
+ onChange={this.handleFieldChange}
+ >
+ Create Suffix Entry
+ </Radio>
+ </Col>
+ </FormGroup>
+ <FormGroup
+ key="createInitDBp"
+ controlId="createInitDBp"
+ disabled={false}
+ >
+ <Col smOffset={4} sm={8}>
+ <Radio
+ id="createInitDB"
+ value="createSample"
+ name="createSample"
+ inline
+ checked={createInitDB === "createSample"}
+ onChange={this.handleFieldChange}
+ >
+ Create Suffix Entry And Add Sample Entries
+ </Radio>
+ </Col>
+ </FormGroup>
+ </Form>
+ {createSpinner}
+ </Modal.Body>
+ <Modal.Footer>
+ <Button bsStyle="default" className="btn-cancel" onClick={closeHandler}>
+ Cancel
+ </Button>
+ <Button bsStyle="primary" onClick={this.createInstance}>
+ Create Instance
+ </Button>
+ </Modal.Footer>
+ </div>
+ </Modal>
+ );
+ }
+}
+
+CreateInstanceModal.propTypes = {
+ showModal: PropTypes.bool,
+ closeHandler: PropTypes.func,
+ addNotification: PropTypes.func,
+ loadInstanceList: PropTypes.func
+};
+
+CreateInstanceModal.defaultProps = {
+ showModal: false,
+ closeHandler: noop,
+ addNotification: noop,
+ loadInstanceList: noop
+};
+
+export class SchemaReloadModal extends React.Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ reloadSchemaDir: "",
+ loadingSchemaTask: false
+ };
+
+ this.reloadSchema = this.reloadSchema.bind(this);
+ this.handleFieldChange = this.handleFieldChange.bind(this);
+ }
+
+ handleFieldChange(e) {
+ this.setState({
+ [e.target.id]: e.target.value
+ });
+ }
+
+ reloadSchema(e) {
+ const { addNotification, serverId, closeHandler } = this.props;
+ const { reloadSchemaDir } = this.state;
+
+ this.setState({
+ loadingSchemaTask: true
+ });
+
+ let cmd = ["dsconf", "-j", serverId, "schema", "reload", "--wait"];
+ if (reloadSchemaDir !== "") {
+ cmd = [...cmd, "--schemadir", reloadSchemaDir];
+ }
+ log_cmd("reloadSchemaDir", "Reload schema files", cmd);
+ cockpit
+ .spawn(cmd, { superuser: true, err: "message" })
+ .done(data => {
+ addNotification("success", "Successfully reloaded schema");
+ this.setState({
+ loadingSchemaTask: false
+ });
+ closeHandler();
+ })
+ .fail(err => {
+ let errMsg = JSON.parse(err);
+ addNotification("error", `Failed to reload schema files - ${errMsg.desc}`);
+ closeHandler();
+ });
+ }
+
+ render() {
+ const { loadingSchemaTask, reloadSchemaDir } = this.state;
+ const { showModal, closeHandler } = this.props;
+
+ let spinner = "";
+ if (loadingSchemaTask) {
+ spinner = (
+ <Row>
+ <div className="ds-margin-top ds-modal-spinner">
+ <Spinner loading inline size="md" />
+ Reloading schema files...
+ </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>Reload Schema Files</Modal.Title>
+ </Modal.Header>
+ <Modal.Body>
+ <Form horizontal autoComplete="off">
+ <Row title="The name of the database link.">
+ <Col sm={3}>
+ <ControlLabel>Schema File Directory:</ControlLabel>
+ </Col>
+ <Col sm={9}>
+ <FormControl
+ type="text"
+ id="reloadSchemaDir"
+ value={reloadSchemaDir}
+ onChange={this.handleFieldChange}
+ />
+ </Col>
+ </Row>
+ {spinner}
+ </Form>
+ </Modal.Body>
+ <Modal.Footer>
+ <Button bsStyle="default" className="btn-cancel" onClick={closeHandler}>
+ Cancel
+ </Button>
+ <Button bsStyle="primary" onClick={this.reloadSchema}>
+ Reload Schema
+ </Button>
+ </Modal.Footer>
+ </div>
+ </Modal>
+ );
+ }
+}
+
+SchemaReloadModal.propTypes = {
+ showModal: PropTypes.bool,
+ closeHandler: PropTypes.func,
+ addNotification: PropTypes.func,
+ serverId: PropTypes.string
+};
+
+SchemaReloadModal.defaultProps = {
+ showModal: false,
+ closeHandler: noop,
+ addNotification: noop,
+ serverId: ""
+};
+
+class ManageBackupsModal extends React.Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ activeKey: 1,
+ showConfirmBackupDelete: false,
+ showConfirmBackup: false,
+ showConfirmRestore: false,
+ showConfirmRestoreReplace: false,
+ showConfirmLDIFReplace: false,
+ showRestoreSpinningModal: false,
+ showDelBackupSpinningModal: false,
+ showBackupModal: false,
+ backupSpinning: false,
+ backupName: "",
+ deleteBackup: "",
+ 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);
+ this.validateBackup = this.validateBackup.bind(this);
+ this.closeConfirmRestoreReplace = this.closeConfirmRestoreReplace.bind(this);
+ }
+
+ closeExportModal() {
+ this.setState({
+ showExportModal: 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,
+ backupName: ""
+ });
+ }
+
+ closeBackupModal() {
+ this.setState({
+ showBackupModal: 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
+ });
+ }
+
+ closeConfirmRestoreReplace() {
+ this.setState({
+ showConfirmRestoreReplace: false
+ });
+ }
+
+ validateBackup() {
+ for (let i = 0; i < this.props.backups.length; i++) {
+ if (this.state.backupName == this.props.backups[i]["name"]) {
+ this.setState({
+ showConfirmRestoreReplace: true
+ });
+ return;
+ }
+ }
+ this.doBackup();
+ }
+
+ doBackup() {
+ this.setState({
+ backupSpinning: true
+ });
+
+ let cmd = ["dsctl", "-j", this.props.serverId, "status"];
+ cockpit
+ .spawn(cmd, { superuser: true })
+ .done(status_data => {
+ let status_json = JSON.parse(status_data);
+ if (status_json.running == true) {
+ let cmd = [
+ "dsconf",
+ "-j",
+ "ldapi://%2fvar%2frun%2fslapd-" + this.props.serverId + ".socket",
+ "backup",
+ "create"
+ ];
+ if (this.state.backupName != "") {
+ if (bad_file_name(this.state.backupName)) {
+ this.props.addNotification(
+ "warning",
+ `Backup name should not be a path. All backups are stored in the server's backup directory`
+ );
+ return;
+ }
+ cmd.push(this.state.backupName);
+ }
+
+ log_cmd("doBackup", "Add backup task online", 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 => {
+ let errMsg = JSON.parse(err);
+ this.props.reload();
+ this.closeBackupModal();
+ this.props.addNotification(
+ "error",
+ `Failure backing up server - ${errMsg.desc}`
+ );
+ });
+ } else {
+ const cmd = ["dsctl", "-j", this.props.serverId, "db2bak"];
+ if (this.state.backupName != "") {
+ if (bad_file_name(this.state.backupName)) {
+ this.props.addNotification(
+ "warning",
+ `Backup name should not be a path. All backups are stored in the server's backup directory`
+ );
+ return;
+ }
+ cmd.push(this.state.backupName);
+ }
+ log_cmd("doBackup", "Doing backup of the server offline", cmd);
+ cockpit
+ .spawn(cmd, { superuser: true })
+ .done(content => {
+ this.props.reload();
+ this.closeBackupModal();
+ this.props.addNotification("success", `Server has been backed up`);
+ })
+ .fail(err => {
+ let errMsg = JSON.parse(err);
+ this.props.reload();
+ this.closeBackupModal();
+ this.props.addNotification(
+ "error",
+ `Failure backing up server - ${errMsg.desc}`
+ );
+ });
+ }
+ })
+ .fail(err => {
+ let errMsg = JSON.parse(err);
+ console.log("Failed to check the server status", errMsg.desc);
+ });
+ }
+
+ restoreBackup() {
+ this.showRestoreSpinningModal();
+ let cmd = ["dsctl", "-j", this.props.serverId, "status"];
+ cockpit
+ .spawn(cmd, { superuser: true })
+ .done(status_data => {
+ let status_json = JSON.parse(status_data);
+ if (status_json.running == true) {
+ const cmd = [
+ "dsconf",
+ "-j",
+ "ldapi://%2fvar%2frun%2fslapd-" + this.props.serverId + ".socket",
+ "backup",
+ "restore",
+ this.state.backupName
+ ];
+ log_cmd("restoreBackup", "Restoring server online", cmd);
+ cockpit
+ .spawn(cmd, { superuser: true, err: "message" })
+ .done(content => {
+ this.closeRestoreSpinningModal();
+ this.props.addNotification("success", `Server has been restored`);
+ })
+ .fail(err => {
+ let errMsg = JSON.parse(err);
+ this.closeRestoreSpinningModal();
+ this.props.addNotification(
+ "error",
+ `Failure restoring up server - ${errMsg.desc}`
+ );
+ });
+ } else {
+ const cmd = [
+ "dsctl",
+ "-j",
+ this.props.serverId,
+ "bak2db",
+ this.state.backupName
+ ];
+ log_cmd("restoreBackup", "Restoring server offline", cmd);
+ cockpit
+ .spawn(cmd, { superuser: true, err: "message" })
+ .done(content => {
+ this.closeRestoreSpinningModal();
+ this.props.addNotification("success", `Server has been restored`);
+ })
+ .fail(err => {
+ let errMsg = JSON.parse(err);
+ this.closeRestoreSpinningModal();
+ this.props.addNotification(
+ "error",
+ `Failure restoring up server - ${errMsg.desc}`
+ );
+ });
+ }
+ })
+ .fail(err => {
+ let errMsg = JSON.parse(err);
+ console.log("Failed to check the server status", errMsg.desc);
+ });
+ }
+
+ deleteBackup(e) {
+ // Show confirmation
+ this.showDelBackupSpinningModal();
+
+ const cmd = [
+ "dsctl",
+ "-j",
+ 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 => {
+ let errMsg = JSON.parse(err);
+ this.props.reload();
+ this.closeDelBackupSpinningModal();
+ this.props.addNotification("error", `Failure deleting backup - ${errMsg.desc}`);
+ });
+ }
+
+ 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
+ });
+ }
+
+ render() {
+ const { showModal, closeHandler, backups, reload, loadingBackup } = this.props;
+
+ let backupSpinner = "";
+ if (loadingBackup) {
+ backupSpinner = (
+ <Row>
+ <div className="ds-margin-top-lg ds-modal-spinner">
+ <Spinner loading inline size="lg" />
+ Creating instance...
+ </div>
+ </Row>
+ );
+ }
+
+ return (
+ <div>
+ <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>Manage Backups</Modal.Title>
+ </Modal.Header>
+ <Modal.Body>
+ <div className="ds-margin-top-xlg">
+ <BackupTable
+ rows={backups}
+ confirmRestore={this.showConfirmRestore}
+ confirmDelete={this.showConfirmBackupDelete}
+ />
+ </div>
+ {backupSpinner}
+ </Modal.Body>
+ <Modal.Footer>
+ <Button
+ bsStyle="primary"
+ onClick={this.showBackupModal}
+ className="ds-margin-top"
+ >
+ Create Backup
+ </Button>
+ <Button
+ bsStyle="default"
+ onClick={reload}
+ className="ds-left-margin ds-margin-top"
+ >
+ Refresh Backups
+ </Button>
+ </Modal.Footer>
+ </div>
+ </Modal>
+ <BackupModal
+ showModal={this.state.showBackupModal}
+ closeHandler={this.closeBackupModal}
+ handleChange={this.handleChange}
+ saveHandler={this.validateBackup}
+ 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}
+ />
+ <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}
+ />
+ <ConfirmPopup
+ showModal={this.state.showConfirmRestoreReplace}
+ closeHandler={this.closeConfirmRestoreReplace}
+ actionFunc={this.doBackup}
+ msg="Replace Existing Backup"
+ msgContent="A backup already eixsts with the same name, do you want to replace it?"
+ />
+ </div>
+ );
+ }
+}
+
+ManageBackupsModal.propTypes = {
+ showModal: PropTypes.bool,
+ closeHandler: PropTypes.func,
+ addNotification: PropTypes.func,
+ serverId: PropTypes.string
+};
+
+ManageBackupsModal.defaultProps = {
+ showModal: false,
+ closeHandler: noop,
+ addNotification: noop,
+ serverId: ""
+};
+
+export default DSInstance;
diff --git a/src/cockpit/389-console/src/index.es6 b/src/cockpit/389-console/src/index.es6
index 9344ffa..91abfcf 100644
--- a/src/cockpit/389-console/src/index.es6
+++ b/src/cockpit/389-console/src/index.es6
@@ -1,86 +1,7 @@
import React from "react";
import ReactDOM from "react-dom";
-import { Plugins } from "./plugins.jsx";
-import { Database } from "./database.jsx";
-import { Monitor } from "./monitor.jsx";
-import { Schema } from "./schema.jsx";
-import { Replication } from "./replication.jsx";
-import { Server } from "./server.jsx";
+import { DSInstance } from "./ds.jsx";

-var serverIdElem;
-
-function renderReactDOM(clear) {
- // We should clear the React properties on the instance removal
- if (clear) {
- serverIdElem = "";
- } else {
- serverIdElem = document
- .getElementById("select-server")
- .value.replace("slapd-", "");
- }
- let d = new Date();
- let tabKey = d.getTime();
-
- // Server Tab
- ReactDOM.render(
- <Server serverId={serverIdElem} key={tabKey} />,
- document.getElementById("server")
- );
- // Plugins Tab
- ReactDOM.render(
- <Plugins serverId={serverIdElem} key={tabKey} />,
- document.getElementById("plugins")
- );
-
- // Database tab
- ReactDOM.render(
- <Database serverId={serverIdElem} key={tabKey} />,
- document.getElementById("database")
- );
-
- // Replication tab
- ReactDOM.render(
- <Replication serverId={serverIdElem} key={tabKey} />,
- document.getElementById("replication")
- );
-
- // Monitor tab
- ReactDOM.render(
- <Monitor serverId={serverIdElem} key={tabKey} />,
- document.getElementById("monitor")
- );
-
- // Schema tab
- ReactDOM.render(
- <Schema serverId={serverIdElem} key={tabKey} />,
- document.getElementById("schema")
- );
-}
-
-// We have to create the wrappers because this is no simple way
-// to pass arguments to the listener's callback function
-function renderReactWrapper() {
- renderReactDOM(false);
-}
-function renderClearWrapper() {
- renderReactDOM(true);
-}
-
-document.addEventListener("DOMContentLoaded", function() {
- var init_config = setInterval(function() {
- serverIdElem = document.getElementById("select-server");
- if (serverIdElem != null && serverIdElem.value.startsWith("slapd-")) {
- document
- .getElementById("select-server")
- .addEventListener("change", renderReactWrapper);
- document
- .getElementById("reload-page")
- .addEventListener("click", renderReactWrapper);
- document
- .getElementById("remove-server-btn")
- .addEventListener("click", renderClearWrapper);
- renderReactDOM();
- clearInterval(init_config);
- }
- }, 250);
+document.addEventListener("DOMContentLoaded", function () {
+ ReactDOM.render(React.createElement(DSInstance, {}), document.getElementById('dsinstance'));
});
diff --git a/src/cockpit/389-console/src/index.html b/src/cockpit/389-console/src/index.html
index 1df2d19..4994f23 100644
--- a/src/cockpit/389-console/src/index.html
+++ b/src/cockpit/389-console/src/index.html
@@ -6,481 +6,16 @@
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script type="text/javascript" src="../base1/cockpit.js"></script>
- <script src="static/jquery-3.3.1.min.js"></script>
- <script src="static/jquery.dataTables.min.js"></script>
- <script src="static/jquery.dataTables.select.min.js"></script>
- <script src="static/moment.min.js"></script>
- <script src="static/dataTables.datetime-moment.js"></script>
- <script src="static/jquery.timepicker.min.js"></script>
- <script src="static/bootstrap.min.js"></script>
- <script src="static/bootpopup.min.js"></script>
- <script src="static/patternfly.min.js"></script>
- <script src="static/c3.min.js"></script>
- <script src="static/d3.min.js"></script>
- <script src="ds.js"></script>
- <link href="static/bootstrap.min.css" rel="stylesheet">
- <link href="static/jquery.dataTables.min.css" type="text/css" rel="stylesheet">
- <link href="static/jquery.timepicker.min.css" type="text/css" rel="stylesheet">
- <link href="static/style.min.css" rel="stylesheet">
<link href="static/patternfly-additions.css" rel="stylesheet" type="text/css">
<link href="static/Typeahead.css" rel="stylesheet" type="text/css">
<link rel="stylesheet" href="../base1/patternfly.css">
<link href="css/ds.css" type="text/css" rel="stylesheet">
</head>

-<body>
- <div id="reload-page" hidden></div>
- <div id="loading-page" class="ds-center ds-loading" hidden>
- <h4 id="loading-msg">Loading Directory Server Configuration...</h4>
- <p class="ds-margin-top-lg"><span class="spinner spinner-lg spinner-inline"></span></p>
-
- <div class="progress ds-margin-top-lg">
- <div class="progress-bar" role="progressbar" id="ds-progress-bar"
- aria-valuenow="20" aria-valuemin="0"
- aria-valuemax="100" style="width: 20%;"
- >
- <span id="ds-progress-label">20%</span>
- </div>
- </div>
-
- </div>
- <div id="everything" hidden>
- <div class="ds-nav-bar">
- <div class="ds-logo">
- <h2 class="ds-logo-style" id="main-banner"></h2>
- </div>
-
- <nav class="navbar navbar-default" id="ds-navigation" role="navigation">
- <div class="collapse navbar-collapse navbar-collapse-5 ds-nav">
- <ul class="nav navbar-nav navbar-primary">
-
- <!-- Server Config navtab -->
- <li class="ds-nav-tab">
- <a href="#0" class="ds-tab-list ds-tab-standalone" id="server-tab">
- Server Settings
- </a>
- </li>
-
- <!-- Database navtab -->
- <li class="ds-nav-tab">
- <a href="#0" class="ds-tab-list ds-tab-standalone" id="database-tab">
- Database
- </a>
- </li>
-
- <!-- Replication navtab -->
- <li class="ds-nav-tab">
- <a href="#0" class="ds-tab-list ds-tab-standalone" id="replication-tab">
- Replication
- </a>
- </li>
-
- <!-- Schema navtab -->
- <li class="dropdown ds-nav-tab">
- <a href="#0" class="ds-tab-list ds-tab-standalone" id="schema-tab">
- Schema
- </a>
- </li>
-
- <!-- Plugins navtab -->
- <li class="ds-nav-tab">
- <a href="#0" class="ds-tab-list ds-tab-standalone" id="plugin-tab">
- Plugins
- </a>
- </li>
-
- <!-- Monitoring navtab -->
- <li class="ds-nav-tab">
- <a href="#0" class="ds-tab-list ds-tab-standalone"id="monitor-tab">
- Monitoring
- </a>
- </li>
- </ul>
- </div>
- </nav>
- </div>
-
-
- <!-- -------------------------------------
- popup modals from any action dropdown, or right-click option need to be defined here
- ---------------------------------------- -->
-
- <div class="modal fade" id="success-form" tabindex="-1" role="dialog" aria-labelledby="success-label" aria-hidden="true">
- <div class="modal-dialog">
- <div class="modal-content ds-popup">
- <div class="modal-header">
- <h4 class="modal-title" id="success-label">Success!</h4>
- </div>
- <div class="modal-body">
- <p id="success-msg"><p>
- </div>
- </div>
- </div>
- </div>
-
- <div class="modal fade" id="restart-instance-form" data-backdrop="static" tabindex="-1" role="dialog" aria-labelledby="restart-inst-label" aria-hidden="true">
- <div class="modal-dialog">
- <div class="modal-content ds-modal">
- <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="restart-inst-label">Restart Instance</h4>
- </div>
- <div class="modal-body">
- <div id="reload-spinner" class="ds-center">
- <p></p>
- <p id="ds-restart-inst"><span class="spinner spinner-xs spinner-inline"></span> Restarting instance...</p>
- </div>
- </div>
- </div>
- </div>
- </div>
-
- <div class="modal fade" id="stop-instance-form" data-backdrop="static" tabindex="-1" role="dialog" aria-labelledby="stop-inst-label" aria-hidden="true">
- <div class="modal-dialog">
- <div class="modal-content ds-modal">
- <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="stop-inst-label">Stop Instance</h4>
- </div>
- <div class="modal-body">
- <div id="reload-spinner" class="ds-center">
- <p></p>
- <p id="ds-stop-inst"><span class="spinner spinner-xs spinner-inline"></span> Stopping instance...</p>
- </div>
- </div>
- </div>
- </div>
- </div>
-
- <div class="modal fade" id="start-instance-form" data-backdrop="static" tabindex="-1" role="dialog" aria-labelledby="start-inst-label" aria-hidden="true">
- <div class="modal-dialog">
- <div class="modal-content ds-modal">
- <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="start-inst-label">Start Instance</h4>
- </div>
- <div class="modal-body">
- <div id="reload-spinner" class="ds-center">
- <p></p>
- <p id="ds-start-inst"><span class="spinner spinner-xs spinner-inline"></span> Starting instance...</p>
- </div>
- </div>
- </div>
- </div>
- </div>
-
- <div class="modal fade" id="remove-instance-form" data-backdrop="static" tabindex="-1" role="dialog" aria-labelledby="remove-inst-label" aria-hidden="true">
- <div class="modal-dialog">
- <div class="modal-content ds-modal">
- <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="remove-inst-label">Remove Instance</h4>
- </div>
- <div class="modal-body">
- <div id="reload-spinner" class="ds-center">
- <p></p>
- <p id="ds-remove-inst"><span class="spinner spinner-xs spinner-inline"></span> Removing instance...</p>
- </div>
- </div>
- </div>
- </div>
- </div>

- <div class="modal fade" id="schema-reload-form" data-backdrop="static" tabindex="-1" role="dialog" aria-labelledby="reload-label" aria-hidden="true">
- <div class="modal-dialog">
- <div class="modal-content ds-modal">
- <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="reload-label">Reload Schema Files</h4>
- </div>
- <div class="modal-body">
- <form class="form-horizontal">
- <label for="reload-dir" class="ds-config-label" title="The name of the database link.">Schema File Directory:</label><input
- class="ds-input-auto" size="40" type="text" placeholder="Leave empty to use default schema location" id="reload-dir">
- </form>
- <div id="reload-spinner" class="ds-center" hidden>
- <p></p>
- <p><span class="spinner spinner-xs spinner-inline"></span> Reloading schema files...</p>
- </div>
- </div>
- <div class="modal-footer">
- <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
- <button type="button" class="btn btn-primary" id ="schema-reload-btn">Reload Schema</button>
- </div>
- </div>
- </div>
- </div>
-
- <!-- Manage Backups/restore -->
- <div class="modal fade" id="restore-form" data-backdrop="static" tabindex="-1" role="dialog" aria-labelledby="restore-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="restore-label">Restore Directory Server</h4>
- </div>
- <div class="modal-body">
- <form class="form-horizontal">
- <table id="backup-table" class="display ds-repl-table" cellspacing="0" width="100%">
- <thead>
- <tr class="ds-table-header">
- <th>Backup Name</th>
- <th>Date</th>
- <th>Size</th>
- <th>Restore</th>
- <th>Delete</th>
- </tr>
- </thead>
- <tbody id="restore-tbody">
- </tbody>
- </table>
- </form>
- <div id="restore-spinner" class="ds-center" hidden>
- <p></p>
- <p><span class="spinner spinner-xs spinner-inline"></span> Restoring the server...</p>
- </div>
- </div>
- <div class="modal-footer">
- <button type="button" class="btn btn-primary" data-dismiss="modal">Close</button>
- </div>
- </div>
- </div>
- </div>
-
- <!-- Create database link -->
- <div class="modal fade" id="create-db-link-form" data-backdrop="static" tabindex="-1" role="dialog" aria-labelledby="dblink-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="dblink-label">Create Database Link</h4>
- </div>
- <div class="modal-body">
- <form class="form-horizontal">
- <div class="ds-container">
- <div class="ds-inline">
- <div>
- <label for="chaining-name" class="ds-config-label" title="The name of the database link.">Database Link Name</label><input
- class="ds-dblink-form-input" type="text" placeholder="Bind DN" id="chaining-name" name="name">
- </div>
- <div>
- <label for="create-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-dblink-form-input" type="text" id="create-nsfarmserverurl"/>
- </div>
- <div>
- <label for="create-nsmultiplexorbinddn" class="ds-config-label" title="Bind DN used to authenticate against the remote server (nsmultiplexorbinddn).">Remote Server Bind DN</label><input
- class="ds-dblink-form-input" type="text" autocomplete="username" placeholder="Bind DN" id="create-nsmultiplexorbinddn" name="name">
- </div>
- <div>
- <label for="create-nsmultiplexorcredentials" class="ds-config-label" title="Replication Bind DN (nsDS5ReplicaCredentials).">Bind DN Credentials</label><input
- class="ds-dblink-form-input" type="password" autocomplete="new-password" placeholder="Enter password" id="create-nsmultiplexorcredentials" name="name">
- </div>
- <div>
- <label for="create-nsmultiplexorcredentials-confirm" class="ds-config-label" title="Confirm password">Confirm Password</label><input
- class="ds-dblink-form-input" type="password" autocomplete="new-password" placeholder="Confirm password" id="create-nsmultiplexorcredentials-confirm" name="name">
- </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>
- </div>
- </div>
- </form>
- </div>
- <div class="modal-footer">
- <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
- <button type="button" class="btn btn-primary" id="chaining-save">Create Link</button>
- </div>
- </div>
- </div>
- </div>
-
- <!--
- Create New Instance
- -->
- <div class="modal fade" id="create-inst-form" data-backdrop="static" tabindex="-1" role="dialog" aria-labelledby="create-inst-header" aria-hidden="true">
- <div class="modal-dialog ds-modal">
- <div class="modal-content animate">
- <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 ds-center" id="create-inst-header">Create New Server Instance</h4>
- </div>
- <div class="modal-body">
- <form class="form-horizontal">
- <p class="ds-modal-error"></p>
- <div class="ds-inline">
- <div>
- <label for="create-inst-serverid" class="ds-config-label ds-input-right" title="The instance name, this is what gets appended to 'slapi-'. The instance name can only contain letters, numbers, and: # % : - _">
- Instance Name</label><input class="ds-input ds-inst-input ds-left-margin" size="40" type="text" id="create-inst-serverid" placeholder="Your_Instance_Name" required />
- </div>
- <div>
- <label for="create-inst-port" class="ds-config-label ds-input-right" title="The server port number">
- Port</label><input class="ds-input ds-inst-input ds-left-margin" size="40" type="text" value="389" id="create-inst-port" required />
- </div>
- <div>
- <label for="create-inst-secureport" class="ds-config-label ds-input-right" title="The secure port number for TLS connections">
- Secure Port</label><input class="ds-input ds-inst-input ds-left-margin" size="40" type="text" value="636" id="create-inst-secureport" required />
- </div>
- <div class="ds-inst-indent">
- <input type="checkbox" class="ds-config-checkbox" id="create-inst-tls" checked><label
- for="create-inst-tls" class="ds-label" title="Create a self-signed certificate database">Create Self-Signed TLS Certificate DB</label>
- </div>
- <div>
- <label for="create-inst-rootdn" class="ds-config-label ds-input-right" title="The DN for the unrestricted user">
- Directory Manager DN</label><input class="ds-input ds-inst-input ds-left-margin" size="40" autocomplete="username" value="cn=Directory Manager" type="text" id="create-inst-rootdn" required />
- </div>
- <div>
- <label for="rootdn-pw" class="ds-config-label ds-input-right" title="Directory Manager password.">Directory Manager Password</label><input
- class="ds-input ds-inst-input ds-left-margin" size="40" type="password" autocomplete="new-password" placeholder="Enter password" id="rootdn-pw" name="name" required>
- </div>
- <div>
- <label for="rootdn-pw-confirm" class="ds-config-label ds-input-right" title="Confirm password">Confirm Password</label><input
- class="ds-input ds-inst-input ds-left-margin" size="40" type="password" autocomplete="new-password" placeholder="Confirm password" id="rootdn-pw-confirm" name="name" required>
- </div>
- <hr>
- <h5 class="ds-center">Optional Database Settings</h5>
- <div>
- <label for="backend-suffix" class="ds-config-label ds-input-right" title="Database suffix, like 'dc=example,dc=com'. The suffix must be a valid LDAP Distiguished Name (DN)">Database Suffix</label><input
- class="ds-input ds-inst-input ds-left-margin" size="40" placeholder="e.g. dc=example,dc=com" type="text" id="backend-suffix">
- </div>
- <div>
- <label for="backend-name" class="ds-config-label ds-input-right" title="The name for the backend database, like 'userroot'. The name can be a combination of alphanumeric characters, dashes (-), and underscores (_). No other characters are allowed, and the name must be unique across all backends.">Database Name</label><input
- class="ds-input ds-inst-input ds-left-margin" placeholder="e.g. userRoot" size="40" type="text" id="backend-name">
- </div>
- <div class="ds-inst-indent ds-margin-top">
- <div>
- <input type="radio" name="ds-radio-group" id="no-init" checked /><label class="ds-left-margin" for="no-init"
- title="Do not initialize the backend database"> Do Not Initialize Database</label>
- </div>
- <div>
- <input type="radio" name="ds-radio-group" id="create-suffix-entry" /><label class="ds-left-margin" for="create-suffix-entry"
- title="Create the suffix entry with a basic READ ACI"> Create Suffix Entry</label>
- </div>
- <div>
- <input type="radio" name="ds-radio-group" id="create-sample-entries" /><label class="ds-left-margin" for="create-sample-entries"
- title="Create sample entries under the suffix"> Create Suffix Entry And Add Sample Entries</label>
- </div>
- </div>
- <div id="create-inst-spinner" class="ds-center" hidden>
- <hr>
- <p><span class="spinner spinner-xs spinner-inline"></span> Creating instance...</p>
- </div>
- </div>
- </form>
- </div>
- <div class="modal-footer">
- <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
- <button type="button" class="btn btn-primary" id="create-inst-save">Create Instance</button>
- </div>
- </div>
- </div>
- </div>
-
- <!--
- Do Backup
- -->
- <div class="modal fade" id="backup-form" data-backdrop="static" tabindex="-1" role="dialog" aria-labelledby="backup-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="backup-label">Backup Directory Server</h4>
- </div>
- <div class="modal-body">
- <form class="form-horizontal">
- <label for="backup-name" title="Enter a name for the backup subdirectory located under the server's backup directory (nsslapd-bakdir)">
- Name For The Backup</label><input class="ds-input-auto" type="text" id="backup-name"/>
- </form>
- <div id="backup-spinner" class="ds-center" hidden>
- <p></p>
- <p><span class="spinner spinner-xs spinner-inline"></span> Backing up the server...</p>
- </div>
- </div>
- <div class="modal-footer">
- <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
- <button type="button" class="btn btn-primary" id="ds-backup-btn">Do Backup</button>
- </div>
- </div>
- </div>
- </div>
-
- <!-- The Nav Tabs -->
-
- <div class="ds-content">
- <div id="no-package" class="all-pages ds-center" hidden>
- <h3>There is no <b>389-ds-base</b> package installed on this system. Sorry there is nothing to manage...</h3>
- </div>
- <div id="no-instances" class="all-pages ds-center" hidden>
- <h3>There are no Directory Server instances to manage</h3>
- <p>
- <button type="button" class="btn btn-primary" id="no-inst-create-btn" data-toggle="modal" data-target="#create-inst-form">Create New Instance</button>
- </p>
- </div>
- <div id="not-running" class="all-pages ds-center" hidden>
- <h3>This server instance is not running, either start it from the <b>Actions</b> dropdown menu, or choose a different instance</h3>
- </div>
- <div id="no-connect" class="all-pages ds-center" hidden>
- <h3>This server instance is running, but we can not connect to it. Check LDAPI is properly configured on this instance.</h3>
- </div>
-
- <div id="server-content" class="all-pages">
- <div id="server"></div>
- </div>
-
- <div id="database-content" class="all-pages" hidden>
- <div id="database"></div>
- </div>
-
- <div id="replication-content" class="all-pages" hidden>
- <div id="replication"></div>
- </div>
-
- <div id="schema-content" class="all-pages" hidden>
- <div id="schema"></div>
- </div>
-
- <div id="plugin-content" class="all-pages" hidden>
- <div id="plugins"></div>
- </div>
-
- <div id="monitor-content" class="all-pages" hidden>
- <div id="monitor"></div>
- </div>
-
- </div>
-
- </div>
- <script src="index.js"></script>
+<body>
+ <div id="dsinstance"></div>
+ <script src="index.js"></script>
</body>
</html>
+
diff --git a/src/cockpit/389-console/src/lib/database/backups.jsx b/src/cockpit/389-console/src/lib/database/backups.jsx
index 6204673..60a50f5 100644
--- a/src/cockpit/389-console/src/lib/database/backups.jsx
+++ b/src/cockpit/389-console/src/lib/database/backups.jsx
@@ -865,7 +865,7 @@ export class BackupModal extends React.Component {
}
}

-class RestoreModal extends React.Component {
+export class RestoreModal extends React.Component {
render() {
const {
showModal,
@@ -912,7 +912,7 @@ class RestoreModal extends React.Component {
}
}

-class DeleteBackupModal extends React.Component {
+export class DeleteBackupModal extends React.Component {
render() {
const {
showModal,
diff --git a/src/cockpit/389-console/src/lib/database/chaining.jsx b/src/cockpit/389-console/src/lib/database/chaining.jsx
index 63cf899..b67c562 100644
--- a/src/cockpit/389-console/src/lib/database/chaining.jsx
+++ b/src/cockpit/389-console/src/lib/database/chaining.jsx
@@ -1265,7 +1265,7 @@ export class ChainingConfig extends React.Component {
checked={this.state.modalChecked}
mTitle="Delete Database Link"
mMsg="Are you really sure you want to delete this database link?"
- mSpinningMsg="Deleting Database Linkt ..."
+ mSpinningMsg="Deleting Database Link..."
mBtnName="Delete Database Link"
/>
</div>
diff --git a/src/cockpit/389-console/src/lib/plugins/attributeUniqueness.jsx b/src/cockpit/389-console/src/lib/plugins/attributeUniqueness.jsx
index 0c9af6a..66453f9 100644
--- a/src/cockpit/389-console/src/lib/plugins/attributeUniqueness.jsx
+++ b/src/cockpit/389-console/src/lib/plugins/attributeUniqueness.jsx
@@ -23,12 +23,17 @@ import "../../css/ds.css";

class AttributeUniqueness extends React.Component {
componentWillMount() {
- this.loadConfigs();
+ if (this.props.wasActiveList.includes(5)) {
+ if (this.state.firstLoad) {
+ this.loadConfigs();
+ }
+ }
}

constructor(props) {
super(props);
this.state = {
+ firstLoad: true,
configRows: [],
attributes: [],
objectClasses: [],
@@ -81,6 +86,9 @@ class AttributeUniqueness extends React.Component {
}

loadConfigs() {
+ this.setState({
+ firstLoad: false
+ });
// Get all the attributes and matching rules now
const cmd = [
"dsconf",
@@ -169,25 +177,18 @@ class AttributeUniqueness extends React.Component {
topEntryOc:
configEntry["uniqueness-top-entry-oc"] === undefined
? []
- : [
- configEntry["uniqueness-top-entry-oc"][0]
- ],
+ : [configEntry["uniqueness-top-entry-oc"][0]],
subtreeEnriesOc:
configEntry["uniqueness-subtree-entries-oc"] === undefined
? []
- : [
- configEntry["uniqueness-subtree-entries-oc"][0]
- ]
+ : [configEntry["uniqueness-subtree-entries-oc"][0]]
});

if (configEntry["uniqueness-attribute-name"] === undefined) {
this.setState({ attrNames: [] });
} else {
for (let value of configEntry["uniqueness-attribute-name"]) {
- configAttrNamesList = [
- ...configAttrNamesList,
- value
- ];
+ configAttrNamesList = [...configAttrNamesList, value];
}
this.setState({ attrNames: configAttrNamesList });
}
@@ -195,10 +196,7 @@ class AttributeUniqueness extends React.Component {
this.setState({ subtrees: [] });
} else {
for (let value of configEntry["uniqueness-subtrees"]) {
- configSubtreesList = [
- ...configSubtreesList,
- value
- ];
+ configSubtreesList = [...configSubtreesList, value];
}
this.setState({ subtrees: configSubtreesList });
}
diff --git a/src/cockpit/389-console/src/lib/plugins/autoMembership.jsx b/src/cockpit/389-console/src/lib/plugins/autoMembership.jsx
index 015b74d..6de8d3a 100644
--- a/src/cockpit/389-console/src/lib/plugins/autoMembership.jsx
+++ b/src/cockpit/389-console/src/lib/plugins/autoMembership.jsx
@@ -21,12 +21,17 @@ import "../../css/ds.css";

class AutoMembership extends React.Component {
componentWillMount() {
- this.loadDefinitions();
+ if (this.props.wasActiveList.includes(5)) {
+ if (this.state.firstLoad) {
+ this.loadDefinitions();
+ }
+ }
}

constructor(props) {
super(props);
this.state = {
+ firstLoad: true,
definitionRows: [],
regexRows: [],
regexesToDelete: [],
@@ -82,6 +87,9 @@ class AutoMembership extends React.Component {
}

loadDefinitions() {
+ this.setState({
+ firstLoad: false
+ });
const cmd = [
"dsconf",
"-j",
@@ -213,9 +221,7 @@ class AutoMembership extends React.Component {
} else {
let groupingAttr = definitionEntry["automembergroupingattr"][0];
this.setState({
- groupingAttrMember: [
- groupingAttr.split(":")[0]
- ],
+ groupingAttrMember: [groupingAttr.split(":")[0]],
groupingAttrEntry: groupingAttr.split(":")[1]
});
}
diff --git a/src/cockpit/389-console/src/lib/plugins/dna.jsx b/src/cockpit/389-console/src/lib/plugins/dna.jsx
index df5c9f8..4539255 100644
--- a/src/cockpit/389-console/src/lib/plugins/dna.jsx
+++ b/src/cockpit/389-console/src/lib/plugins/dna.jsx
@@ -22,12 +22,17 @@ import "../../css/ds.css";

class DNA extends React.Component {
componentWillMount() {
- this.loadConfigs();
+ if (this.props.wasActiveList.includes(5)) {
+ if (this.state.firstLoad) {
+ this.loadConfigs();
+ }
+ }
}

constructor(props) {
super(props);
this.state = {
+ firstLoad: true,
configRows: [],
sharedConfigRows: [],
attributes: [],
@@ -121,6 +126,9 @@ class DNA extends React.Component {
}

loadConfigs() {
+ this.setState({
+ firstLoad: false
+ });
const cmd = [
"dsconf",
"-j",
diff --git a/src/cockpit/389-console/src/lib/plugins/linkedAttributes.jsx b/src/cockpit/389-console/src/lib/plugins/linkedAttributes.jsx
index b9bd253..30900f7 100644
--- a/src/cockpit/389-console/src/lib/plugins/linkedAttributes.jsx
+++ b/src/cockpit/389-console/src/lib/plugins/linkedAttributes.jsx
@@ -21,12 +21,17 @@ import "../../css/ds.css";

class LinkedAttributes extends React.Component {
componentWillMount() {
- this.loadConfigs();
+ if (this.props.wasActiveList.includes(5)) {
+ if (this.state.firstLoad) {
+ this.loadConfigs();
+ }
+ }
}

constructor(props) {
super(props);
this.state = {
+ firstLoad: true,
configRows: [],
attributes: [],

@@ -60,6 +65,9 @@ class LinkedAttributes extends React.Component {
}

loadConfigs() {
+ this.setState({
+ firstLoad: false
+ });
// Get all the attributes and matching rules now
const cmd = [
"dsconf",
@@ -136,15 +144,11 @@ class LinkedAttributes extends React.Component {
linkType:
configEntry["linktype"] === undefined
? []
- : [
- configEntry["linktype"][0]
- ],
+ : [configEntry["linktype"][0]],
managedType:
configEntry["managedtype"] === undefined
? []
- : [
- configEntry["managedtype"][0]
- ],
+ : [configEntry["managedtype"][0]],
linkScope:
configEntry["linkscope"] === undefined
? ""
diff --git a/src/cockpit/389-console/src/lib/plugins/memberOf.jsx b/src/cockpit/389-console/src/lib/plugins/memberOf.jsx
index 391dd3d..9cbceff 100644
--- a/src/cockpit/389-console/src/lib/plugins/memberOf.jsx
+++ b/src/cockpit/389-console/src/lib/plugins/memberOf.jsx
@@ -21,9 +21,13 @@ import "../../css/ds.css";

class MemberOf extends React.Component {
componentWillMount(prevProps) {
- this.getObjectClasses();
- this.getAttributes();
- this.updateFields();
+ if (this.props.wasActiveList.includes(5)) {
+ if (this.state.firstLoad) {
+ this.getObjectClasses();
+ this.getAttributes();
+ this.updateFields();
+ }
+ }
}

componentDidUpdate(prevProps) {
@@ -50,6 +54,7 @@ class MemberOf extends React.Component {
this.toggleFixupModal = this.toggleFixupModal.bind(this);

this.state = {
+ firstLoad: true,
objectClasses: [],
attributeTypes: [],

@@ -182,9 +187,7 @@ class MemberOf extends React.Component {
configAutoAddOC:
configEntry["memberofautoaddoc"] === undefined
? []
- : [
- configEntry["memberofautoaddoc"][0],
- ],
+ : [configEntry["memberofautoaddoc"][0]],
configAllBackends: !(
configEntry["memberofallbackends"] === undefined ||
configEntry["memberofallbackends"][0] == "off"
@@ -210,10 +213,7 @@ class MemberOf extends React.Component {
this.setState({ configAttr: [] });
} else {
for (let value of configEntry["memberofattr"]) {
- configAttrObjectList = [
- ...configAttrObjectList,
- value
- ];
+ configAttrObjectList = [...configAttrObjectList, value];
}
this.setState({ configAttr: configAttrObjectList });
}
@@ -221,10 +221,7 @@ class MemberOf extends React.Component {
this.setState({ configGroupAttr: [] });
} else {
for (let value of configEntry["memberofgroupattr"]) {
- configGroupAttrObjectList = [
- ...configGroupAttrObjectList,
- value
- ];
+ configGroupAttrObjectList = [...configGroupAttrObjectList, value];
}
this.setState({
configGroupAttr: configGroupAttrObjectList
@@ -418,9 +415,7 @@ class MemberOf extends React.Component {
memberOfAutoAddOC:
pluginRow["memberofautoaddoc"] === undefined
? []
- : [
- pluginRow["memberofautoaddoc"][0],
- ],
+ : [pluginRow["memberofautoaddoc"][0]],
memberOfAllBackends: !(
pluginRow["memberofallbackends"] === undefined ||
pluginRow["memberofallbackends"][0] == "off"
@@ -446,10 +441,7 @@ class MemberOf extends React.Component {
this.setState({ memberOfAttr: [] });
} else {
for (let value of pluginRow["memberofattr"]) {
- memberOfAttrObjectList = [
- ...memberOfAttrObjectList,
- value
- ];
+ memberOfAttrObjectList = [...memberOfAttrObjectList, value];
}
this.setState({ memberOfAttr: memberOfAttrObjectList });
}
@@ -457,10 +449,7 @@ class MemberOf extends React.Component {
this.setState({ memberOfGroupAttr: [] });
} else {
for (let value of pluginRow["memberofgroupattr"]) {
- memberOfGroupAttrObjectList = [
- ...memberOfGroupAttrObjectList,
- value
- ];
+ memberOfGroupAttrObjectList = [...memberOfGroupAttrObjectList, value];
}
this.setState({
memberOfGroupAttr: memberOfGroupAttrObjectList
@@ -470,6 +459,9 @@ class MemberOf extends React.Component {
}

getObjectClasses() {
+ this.setState({
+ firstLoad: false
+ });
const oc_cmd = [
"dsconf",
"-j",
@@ -1037,10 +1029,7 @@ class MemberOf extends React.Component {
/>
</Col>
<Col sm={3}>
- <Button
- bsStyle="primary"
- onClick={this.openModal}
- >
+ <Button bsStyle="primary" onClick={this.openModal}>
Manage
</Button>
</Col>
@@ -1078,10 +1067,7 @@ class MemberOf extends React.Component {
</Row>
<Row>
<Col sm={12}>
- <Button
- bsStyle="primary"
- onClick={this.toggleFixupModal}
- >
+ <Button bsStyle="primary" onClick={this.toggleFixupModal}>
Run Fixup Task
</Button>
</Col>
diff --git a/src/cockpit/389-console/src/lib/plugins/passthroughAuthentication.jsx b/src/cockpit/389-console/src/lib/plugins/passthroughAuthentication.jsx
index b3ede3f..d0c4787 100644
--- a/src/cockpit/389-console/src/lib/plugins/passthroughAuthentication.jsx
+++ b/src/cockpit/389-console/src/lib/plugins/passthroughAuthentication.jsx
@@ -22,14 +22,19 @@ import { log_cmd } from "../tools.jsx";
import "../../css/ds.css";

class PassthroughAuthentication extends React.Component {
- componentWillMount() {
- this.loadPAMConfigs();
- this.loadURLs();
+ componentDidUpdate() {
+ if (this.props.wasActiveList.includes(5)) {
+ if (this.state.firstLoad) {
+ this.loadPAMConfigs();
+ this.loadURLs();
+ }
+ }
}

constructor(props) {
super(props);
this.state = {
+ firstLoad: true,
pamConfigRows: [],
urlRows: [],
attributes: [],
@@ -101,6 +106,9 @@ class PassthroughAuthentication extends React.Component {
}

loadPAMConfigs() {
+ this.setState({
+ firstLoad: false
+ });
const cmd = [
"dsconf",
"-j",
@@ -247,10 +255,7 @@ class PassthroughAuthentication extends React.Component {
this.setState({ pamExcludeSuffix: [] });
} else {
for (let value of pamConfigEntry["pamexcludesuffix"]) {
- pamExcludeSuffixList = [
- ...pamExcludeSuffixList,
- value
- ];
+ pamExcludeSuffixList = [...pamExcludeSuffixList, value];
}
this.setState({
pamExcludeSuffix: pamExcludeSuffixList
@@ -261,10 +266,7 @@ class PassthroughAuthentication extends React.Component {
this.setState({ pamIncludeSuffix: [] });
} else {
for (let value of pamConfigEntry["pamincludesuffix"]) {
- pamIncludeSuffixList = [
- ...pamIncludeSuffixList,
- value
- ];
+ pamIncludeSuffixList = [...pamIncludeSuffixList, value];
}
this.setState({
pamIncludeSuffix: pamIncludeSuffixList
diff --git a/src/cockpit/389-console/src/lib/plugins/referentialIntegrity.jsx b/src/cockpit/389-console/src/lib/plugins/referentialIntegrity.jsx
index 700c188..7419b84 100644
--- a/src/cockpit/389-console/src/lib/plugins/referentialIntegrity.jsx
+++ b/src/cockpit/389-console/src/lib/plugins/referentialIntegrity.jsx
@@ -20,8 +20,12 @@ import "../../css/ds.css";

class ReferentialIntegrity extends React.Component {
componentWillMount(prevProps) {
- this.getAttributes();
- this.updateFields();
+ if (this.props.wasActiveList.includes(5)) {
+ if (this.state.firstLoad) {
+ this.getAttributes();
+ this.updateFields();
+ }
+ }
}

componentDidUpdate(prevProps) {
@@ -34,6 +38,7 @@ class ReferentialIntegrity extends React.Component {
super(props);

this.state = {
+ firstLoad: true,
updateDelay: "",
membershipAttr: [],
entryScope: "",
@@ -138,10 +143,7 @@ class ReferentialIntegrity extends React.Component {
this.setState({ configMembershipAttr: [] });
} else {
for (let value of pluginRow["referint-membership-attr"]) {
- membershipAttrList = [
- ...membershipAttrList,
- value
- ];
+ membershipAttrList = [...membershipAttrList, value];
}
this.setState({
configMembershipAttr: membershipAttrList
@@ -342,6 +344,9 @@ class ReferentialIntegrity extends React.Component {
}

getAttributes() {
+ this.setState({
+ firstLoad: false
+ });
const attr_cmd = [
"dsconf",
"-j",
@@ -746,10 +751,7 @@ class ReferentialIntegrity extends React.Component {
/>
</Col>
<Col sm={2}>
- <Button
- bsStyle="primary"
- onClick={this.openModal}
- >
+ <Button bsStyle="primary" onClick={this.openModal}>
Manage
</Button>
</Col>
diff --git a/src/cockpit/389-console/src/lib/plugins/retroChangelog.jsx b/src/cockpit/389-console/src/lib/plugins/retroChangelog.jsx
index c1ed953..e17a903 100644
--- a/src/cockpit/389-console/src/lib/plugins/retroChangelog.jsx
+++ b/src/cockpit/389-console/src/lib/plugins/retroChangelog.jsx
@@ -18,8 +18,12 @@ import "../../css/ds.css";

class RetroChangelog extends React.Component {
componentWillMount(prevProps) {
- this.getAttributes();
- this.updateFields();
+ if (this.props.wasActiveList.includes(5)) {
+ if (this.state.firstLoad) {
+ this.getAttributes();
+ this.updateFields();
+ }
+ }
}

componentDidUpdate(prevProps) {
@@ -32,6 +36,7 @@ class RetroChangelog extends React.Component {
super(props);

this.state = {
+ firstLoad: true,
isReplicated: false,
attribute: [],
directory: "",
@@ -69,9 +74,7 @@ class RetroChangelog extends React.Component {
attribute:
pluginRow["nsslapd-attribute"] === undefined
? []
- : [
- pluginRow["nsslapd-attribute"][0]
- ],
+ : [pluginRow["nsslapd-attribute"][0]],
directory:
pluginRow["nsslapd-changelogdir"] === undefined
? ""
@@ -89,6 +92,7 @@ class RetroChangelog extends React.Component {
}

getAttributes() {
+ this.setState({ firstLoad: false });
const attr_cmd = [
"dsconf",
"-j",
diff --git a/src/cockpit/389-console/src/lib/plugins/usn.jsx b/src/cockpit/389-console/src/lib/plugins/usn.jsx
index e587755..a1080c6 100644
--- a/src/cockpit/389-console/src/lib/plugins/usn.jsx
+++ b/src/cockpit/389-console/src/lib/plugins/usn.jsx
@@ -20,7 +20,11 @@ import "../../css/ds.css";

class USN extends React.Component {
componentWillMount() {
- this.updateSwitch();
+ if (this.props.wasActiveList.includes(5)) {
+ if (this.state.firstLoad) {
+ this.updateSwitch();
+ }
+ }
}

constructor(props) {
@@ -33,6 +37,7 @@ class USN extends React.Component {
this.handleFieldChange = this.handleFieldChange.bind(this);

this.state = {
+ firstLoad: true,
globalMode: false,
disableSwitch: false,
cleanupModalShow: false,
@@ -88,6 +93,10 @@ class USN extends React.Component {
}

updateSwitch() {
+ this.setState({
+ firstLoad: false,
+ disableSwitch: true
+ });
const cmd = [
"dsconf",
"-j",
@@ -96,10 +105,6 @@ class USN extends React.Component {
"get",
"nsslapd-entryusn-global"
];
-
- this.setState({
- disableSwitch: true
- });
this.props.toggleLoadingHandler();
log_cmd("updateSwitch", "Get global USN status", cmd);
cockpit
diff --git a/src/cockpit/389-console/src/lib/server/accessLog.jsx b/src/cockpit/389-console/src/lib/server/accessLog.jsx
index 85c5623..3dcf7e8 100644
--- a/src/cockpit/389-console/src/lib/server/accessLog.jsx
+++ b/src/cockpit/389-console/src/lib/server/accessLog.jsx
@@ -1,6 +1,5 @@
import cockpit from "cockpit";
import React from "react";
-import { NotificationController } from "../notifications.jsx";
import { log_cmd } from "../tools.jsx";
import {
Button,
@@ -16,6 +15,7 @@ import {
Spinner,
TabContainer,
TabContent,
+ noop,
TabPane,
} from "patternfly-react";
import "../../css/ds.css";
@@ -61,19 +61,16 @@ export class ServerAccessLog extends React.Component {
loading: false,
loaded: false,
activeKey: 1,
- notifications: [],
saveSettingsDisabled: true,
saveRotationDisabled: true,
saveExpDisabled: true,
attrs: this.props.attrs,
};

- this.addNotification = this.addNotification.bind(this);
this.handleChange = this.handleChange.bind(this);
this.handleNavSelect = this.handleNavSelect.bind(this);
this.loadConfig = this.loadConfig.bind(this);
this.reloadConfig = this.reloadConfig.bind(this);
- this.removeNotification = this.removeNotification.bind(this);
this.saveConfig = this.saveConfig.bind(this);
}

@@ -92,29 +89,6 @@ export class ServerAccessLog extends React.Component {
this.setState({ activeKey: key });
}

- 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
- )
- });
- }
-
handleChange(e, nav_tab) {
let value = e.target.type === 'checkbox' ? e.target.checked : e.target.value;
let attr = e.target.id;
@@ -209,7 +183,7 @@ export class ServerAccessLog extends React.Component {
this.setState({
loading: false
});
- this.addNotification(
+ this.props.addNotification(
"success",
"Successfully updated Access Log settings"
);
@@ -220,7 +194,7 @@ export class ServerAccessLog extends React.Component {
this.setState({
loading: false
});
- this.addNotification(
+ this.props.addNotification(
"error",
`Error saving Access Log settings - ${errMsg.desc}`
);
@@ -308,7 +282,7 @@ export class ServerAccessLog extends React.Component {
})
.fail(err => {
let errMsg = JSON.parse(err);
- this.addNotification(
+ this.props.addNotification(
"error",
`Error loading Access Log configuration - ${errMsg.desc}`
);
@@ -728,10 +702,6 @@ export class ServerAccessLog extends React.Component {

return (
<div id="server-accesslog-page">
- <NotificationController
- notifications={this.state.notifications}
- removeNotificationAction={this.removeNotification}
- />
<Row>
<Col sm={5}>
<ControlLabel className="ds-suffix-header ds-margin-top-lg">
@@ -753,11 +723,13 @@ export class ServerAccessLog extends React.Component {
// Property types and defaults

ServerAccessLog.propTypes = {
+ addNotification: PropTypes.func,
serverId: PropTypes.string,
attrs: PropTypes.object,
};

ServerAccessLog.defaultProps = {
+ addNotification: noop,
serverId: "",
attrs: {},
};
diff --git a/src/cockpit/389-console/src/lib/server/auditLog.jsx b/src/cockpit/389-console/src/lib/server/auditLog.jsx
index 88ba26a..623231b 100644
--- a/src/cockpit/389-console/src/lib/server/auditLog.jsx
+++ b/src/cockpit/389-console/src/lib/server/auditLog.jsx
@@ -1,6 +1,5 @@
import cockpit from "cockpit";
import React from "react";
-import { NotificationController } from "../notifications.jsx";
import { log_cmd } from "../tools.jsx";
import {
Button,
@@ -16,6 +15,7 @@ import {
Spinner,
TabContainer,
TabContent,
+ noop,
TabPane,
} from "patternfly-react";
import "../../css/ds.css";
@@ -50,19 +50,16 @@ export class ServerAuditLog extends React.Component {
loading: false,
loaded: false,
activeKey: 1,
- notifications: [],
saveSettingsDisabled: true,
saveRotationDisabled: true,
saveExpDisabled: true,
attrs: this.props.attrs,
};

- this.addNotification = this.addNotification.bind(this);
this.handleChange = this.handleChange.bind(this);
this.handleNavSelect = this.handleNavSelect.bind(this);
this.loadConfig = this.loadConfig.bind(this);
this.reloadConfig = this.reloadConfig.bind(this);
- this.removeNotification = this.removeNotification.bind(this);
this.saveConfig = this.saveConfig.bind(this);
}

@@ -81,29 +78,6 @@ export class ServerAuditLog extends React.Component {
this.setState({ activeKey: key });
}

- 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
- )
- });
- }
-
handleChange(e, nav_tab) {
let value = e.target.type === 'checkbox' ? e.target.checked : e.target.value;
let attr = e.target.id;
@@ -183,7 +157,7 @@ export class ServerAuditLog extends React.Component {
this.setState({
loading: false
});
- this.addNotification(
+ this.props.addNotification(
"success",
"Successfully updated Audit Log settings"
);
@@ -194,7 +168,7 @@ export class ServerAuditLog extends React.Component {
this.setState({
loading: false
});
- this.addNotification(
+ this.props.addNotification(
"error",
`Error saving Audit Log settings - ${errMsg.desc}`
);
@@ -303,7 +277,7 @@ export class ServerAuditLog extends React.Component {
})
.fail(err => {
let errMsg = JSON.parse(err);
- this.addNotification(
+ this.props.addNotification(
"error",
`Error loading Audit Log configuration - ${errMsg.desc}`
);
@@ -588,10 +562,6 @@ export class ServerAuditLog extends React.Component {

return (
<div id="server-auditlog-page">
- <NotificationController
- notifications={this.state.notifications}
- removeNotificationAction={this.removeNotification}
- />
<Row>
<Col sm={5}>
<ControlLabel className="ds-suffix-header ds-margin-top-lg">
@@ -613,11 +583,13 @@ export class ServerAuditLog extends React.Component {
// Property types and defaults

ServerAuditLog.propTypes = {
+ addNotification: PropTypes.func,
serverId: PropTypes.string,
attrs: PropTypes.object,
};

ServerAuditLog.defaultProps = {
+ addNotification: noop,
serverId: "",
attrs: {},
};
diff --git a/src/cockpit/389-console/src/lib/server/auditfailLog.jsx b/src/cockpit/389-console/src/lib/server/auditfailLog.jsx
index e7b88d2..caf49c7 100644
--- a/src/cockpit/389-console/src/lib/server/auditfailLog.jsx
+++ b/src/cockpit/389-console/src/lib/server/auditfailLog.jsx
@@ -1,6 +1,5 @@
import cockpit from "cockpit";
import React from "react";
-import { NotificationController } from "../notifications.jsx";
import { log_cmd } from "../tools.jsx";
import {
Button,
@@ -16,6 +15,7 @@ import {
Spinner,
TabContainer,
TabContent,
+ noop,
TabPane,
} from "patternfly-react";
import "../../css/ds.css";
@@ -50,19 +50,16 @@ export class ServerAuditFailLog extends React.Component {
loading: false,
loaded: false,
activeKey: 1,
- notifications: [],
saveSettingsDisabled: true,
saveRotationDisabled: true,
saveExpDisabled: true,
attrs: this.props.attrs,
};

- this.addNotification = this.addNotification.bind(this);
this.handleChange = this.handleChange.bind(this);
this.handleNavSelect = this.handleNavSelect.bind(this);
this.loadConfig = this.loadConfig.bind(this);
this.reloadConfig = this.reloadConfig.bind(this);
- this.removeNotification = this.removeNotification.bind(this);
this.saveConfig = this.saveConfig.bind(this);
}

@@ -81,29 +78,6 @@ export class ServerAuditFailLog extends React.Component {
this.setState({ activeKey: key });
}

- 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
- )
- });
- }
-
handleChange(e, nav_tab) {
let value = e.target.type === 'checkbox' ? e.target.checked : e.target.value;
let attr = e.target.id;
@@ -183,7 +157,7 @@ export class ServerAuditFailLog extends React.Component {
this.setState({
loading: false
});
- this.addNotification(
+ this.props.addNotification(
"success",
"Successfully updated Audit Failure Log settings"
);
@@ -194,7 +168,7 @@ export class ServerAuditFailLog extends React.Component {
this.setState({
loading: false
});
- this.addNotification(
+ this.props.addNotification(
"error",
`Error saving Audit Failure Log settings - ${errMsg.desc}`
);
@@ -259,7 +233,7 @@ export class ServerAuditFailLog extends React.Component {
})
.fail(err => {
let errMsg = JSON.parse(err);
- this.addNotification(
+ this.props.addNotification(
"error",
`Error loading Audit Failure Log configuration - ${errMsg.desc}`
);
@@ -586,10 +560,6 @@ export class ServerAuditFailLog extends React.Component {

return (
<div id="server-auditfaillog-page">
- <NotificationController
- notifications={this.state.notifications}
- removeNotificationAction={this.removeNotification}
- />
<Row>
<Col sm={5}>
<ControlLabel className="ds-suffix-header ds-margin-top-lg">
@@ -611,11 +581,13 @@ export class ServerAuditFailLog extends React.Component {
// Property types and defaults

ServerAuditFailLog.propTypes = {
+ addNotification: PropTypes.func,
serverId: PropTypes.string,
attrs: PropTypes.object,
};

ServerAuditFailLog.defaultProps = {
+ addNotification: noop,
serverId: "",
attrs: {},
};
diff --git a/src/cockpit/389-console/src/lib/server/errorLog.jsx b/src/cockpit/389-console/src/lib/server/errorLog.jsx
index 6416253..b21d005 100644
--- a/src/cockpit/389-console/src/lib/server/errorLog.jsx
+++ b/src/cockpit/389-console/src/lib/server/errorLog.jsx
@@ -1,6 +1,5 @@
import cockpit from "cockpit";
import React from "react";
-import { NotificationController } from "../notifications.jsx";
import { log_cmd } from "../tools.jsx";
import {
Button,
@@ -16,6 +15,7 @@ import {
Spinner,
TabContainer,
TabContent,
+ noop,
TabPane,
} from "patternfly-react";
import "../../css/ds.css";
@@ -70,19 +70,16 @@ export class ServerErrorLog extends React.Component {
loading: false,
loaded: false,
activeKey: 1,
- notifications: [],
saveSettingsDisabled: true,
saveRotationDisabled: true,
saveExpDisabled: true,
attrs: this.props.attrs,
};

- this.addNotification = this.addNotification.bind(this);
this.handleChange = this.handleChange.bind(this);
this.handleNavSelect = this.handleNavSelect.bind(this);
this.loadConfig = this.loadConfig.bind(this);
this.reloadConfig = this.reloadConfig.bind(this);
- this.removeNotification = this.removeNotification.bind(this);
this.saveConfig = this.saveConfig.bind(this);
}

@@ -101,29 +98,6 @@ export class ServerErrorLog extends React.Component {
this.setState({ activeKey: key });
}

- 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
- )
- });
- }
-
handleChange(e, nav_tab) {
let value = e.target.type === 'checkbox' ? e.target.checked : e.target.value;
let attr = e.target.id;
@@ -218,7 +192,7 @@ export class ServerErrorLog extends React.Component {
this.setState({
loading: false
});
- this.addNotification(
+ this.props.addNotification(
"success",
"Successfully updated Error Log settings"
);
@@ -229,7 +203,7 @@ export class ServerErrorLog extends React.Component {
this.setState({
loading: false
});
- this.addNotification(
+ this.props.addNotification(
"error",
`Error saving Error Log settings - ${errMsg.desc}`
);
@@ -416,7 +390,7 @@ export class ServerErrorLog extends React.Component {
})
.fail(err => {
let errMsg = JSON.parse(err);
- this.addNotification(
+ this.props.addNotification(
"error",
`Error loading Error Log configuration - ${errMsg.desc}`
);
@@ -921,10 +895,6 @@ export class ServerErrorLog extends React.Component {

return (
<div id="server-errorlog-page">
- <NotificationController
- notifications={this.state.notifications}
- removeNotificationAction={this.removeNotification}
- />
<Row>
<Col sm={5}>
<ControlLabel className="ds-suffix-header ds-margin-top-lg">
@@ -946,11 +916,13 @@ export class ServerErrorLog extends React.Component {
// Property types and defaults

ServerErrorLog.propTypes = {
+ addNotification: PropTypes.func,
serverId: PropTypes.string,
attrs: PropTypes.object,
};

ServerErrorLog.defaultProps = {
+ addNotification: noop,
serverId: "",
attrs: {},
};
diff --git a/src/cockpit/389-console/src/lib/server/ldapi.jsx b/src/cockpit/389-console/src/lib/server/ldapi.jsx
index 904689f..42dee17 100644
--- a/src/cockpit/389-console/src/lib/server/ldapi.jsx
+++ b/src/cockpit/389-console/src/lib/server/ldapi.jsx
@@ -1,6 +1,5 @@
import cockpit from "cockpit";
import React from "react";
-import { NotificationController } from "../notifications.jsx";
import { log_cmd } from "../tools.jsx";
import {
Button,
@@ -11,6 +10,7 @@ import {
FormControl,
Icon,
Row,
+ noop,
Spinner,
} from "patternfly-react";
import "../../css/ds.css";
@@ -31,15 +31,12 @@ export class ServerLDAPI extends React.Component {
this.state = {
loading: false,
loaded: false,
- notifications: [],
saveDisabled: true,
attrs: this.props.attrs,
// settings

};

- this.removeNotification = this.removeNotification.bind(this);
- this.addNotification = this.addNotification.bind(this);
this.handleChange = this.handleChange.bind(this);
this.loadConfig = this.loadConfig.bind(this);
this.saveConfig = this.saveConfig.bind(this);
@@ -56,29 +53,6 @@ export class ServerLDAPI extends React.Component {
this.props.enableTree();
}

- 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
- )
- });
- }
-
handleChange(e) {
let value = e.target.type === 'checkbox' ? e.target.checked : e.target.value;
let attr = e.target.id;
@@ -166,7 +140,7 @@ export class ServerLDAPI extends React.Component {
this.setState({
loading: false
});
- this.addNotification(
+ this.props.addNotification(
"success",
"Successfully updated LDAPI configuration"
);
@@ -177,7 +151,7 @@ export class ServerLDAPI extends React.Component {
this.setState({
loading: false
});
- this.addNotification(
+ this.props.addNotification(
"error",
`Error updating LDAPI configuration - ${errMsg.desc}`
);
@@ -296,10 +270,6 @@ export class ServerLDAPI extends React.Component {

return (
<div id="server-ldapi-page">
- <NotificationController
- notifications={this.state.notifications}
- removeNotificationAction={this.removeNotification}
- />
<Row>
<Col sm={5}>
<ControlLabel className="ds-suffix-header ds-margin-top-lg">
@@ -321,11 +291,13 @@ export class ServerLDAPI extends React.Component {
// Property types and defaults

ServerLDAPI.propTypes = {
+ addNotification: PropTypes.func,
serverId: PropTypes.string,
attrs: PropTypes.object,
};

ServerLDAPI.defaultProps = {
+ addNotification: noop,
serverId: "",
attrs: {},
};
diff --git a/src/cockpit/389-console/src/lib/server/sasl.jsx b/src/cockpit/389-console/src/lib/server/sasl.jsx
index 7dff66f..e58a660 100644
--- a/src/cockpit/389-console/src/lib/server/sasl.jsx
+++ b/src/cockpit/389-console/src/lib/server/sasl.jsx
@@ -1,6 +1,6 @@
import cockpit from "cockpit";
import React from "react";
-import { NotificationController, DoubleConfirmModal } from "../notifications.jsx";
+import { DoubleConfirmModal } from "../notifications.jsx";
import { log_cmd } from "../tools.jsx";
import {
Button,
@@ -27,7 +27,6 @@ export class ServerSASL extends React.Component {
loaded: false,
activeKey: 1,
errObj: {},
- notifications: [],
saveDisabled: true,
supportedMechs: [],

@@ -52,8 +51,6 @@ export class ServerSASL extends React.Component {
modalChecked: false,
};

- this.removeNotification = this.removeNotification.bind(this);
- this.addNotification = this.addNotification.bind(this);
this.handleChange = this.handleChange.bind(this);
this.handleModalChange = this.handleModalChange.bind(this);
this.handleModalAddChange = this.handleModalAddChange.bind(this);
@@ -83,41 +80,18 @@ export class ServerSASL extends React.Component {
this.props.enableTree();
}

- 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
- )
- });
- }
-
handleTestRegex() {
let test_string = this.state.saslTestText;
let regex = this.state.saslMapRegex;
let cleaned_regex = regex.replace(/\\\(/g, '(').replace(/\\\)/g, ')');
let sasl_regex = RegExp(cleaned_regex);
if (sasl_regex.test(test_string)) {
- this.addNotification(
+ this.props.addNotification(
"success",
"The test string matches the Regular Expression"
);
} else {
- this.addNotification(
+ this.props.addNotification(
"warning",
"The test string does not match the Regular Expression"
);
@@ -449,7 +423,7 @@ export class ServerSASL extends React.Component {
.done(content => {
this.loadConfig();
this.closeMapping();
- this.addNotification(
+ this.props.addNotification(
"success",
"Successfully create new SASL Mapping"
);
@@ -457,7 +431,7 @@ export class ServerSASL extends React.Component {
.fail(err => {
let errMsg = JSON.parse(err);
this.loadConfig();
- this.addNotification(
+ this.props.addNotification(
"error",
`Error creating new SASL Mapping - ${errMsg.desc}`
);
@@ -505,7 +479,7 @@ export class ServerSASL extends React.Component {
.done(content => {
this.closeMapping();
this.loadConfig();
- this.addNotification(
+ this.props.addNotification(
"success",
"Successfully updated SASL Mapping"
);
@@ -514,7 +488,7 @@ export class ServerSASL extends React.Component {
let errMsg = JSON.parse(err);
this.closeMapping();
this.loadConfig();
- this.addNotification(
+ this.props.addNotification(
"error",
`Error updating SASL Mapping - ${errMsg.desc}`
);
@@ -524,7 +498,7 @@ export class ServerSASL extends React.Component {
let errMsg = JSON.parse(err);
this.loadConfig();
this.closeMapping();
- this.addNotification(
+ this.props.addNotification(
"error",
`Error replacing SASL Mapping - ${errMsg.desc}`
);
@@ -556,7 +530,7 @@ export class ServerSASL extends React.Component {
.done(content => {
this.closeConfirmDelete();
this.loadConfig();
- this.addNotification(
+ this.props.addNotification(
"success",
"Successfully deleted SASL Mapping"
);
@@ -565,7 +539,7 @@ export class ServerSASL extends React.Component {
let errMsg = JSON.parse(err);
this.loadConfig();
this.closeConfirmDelete();
- this.addNotification(
+ this.props.addNotification(
"error",
`Error deleting SASL Mapping - ${errMsg.desc}`
);
@@ -604,7 +578,7 @@ export class ServerSASL extends React.Component {
.spawn(cmd, {superuser: true, "err": "message"})
.done(content => {
this.loadConfig();
- this.addNotification(
+ this.props.addNotification(
"success",
"Successfully updated SASL configuration. These " +
"changes require the server to be restarted to take effect."
@@ -613,7 +587,7 @@ export class ServerSASL extends React.Component {
.fail(err => {
let errMsg = JSON.parse(err);
this.loadConfig();
- this.addNotification(
+ this.props.addNotification(
"error",
`Error updating SASL configuration - ${errMsg.desc}`
);
@@ -748,10 +722,6 @@ export class ServerSASL extends React.Component {

return (
<div id="server-sasl-page">
- <NotificationController
- notifications={this.state.notifications}
- removeNotificationAction={this.removeNotification}
- />
{body}
<SASLMappingModal
showModal={this.state.showMappingModal}
diff --git a/src/cockpit/389-console/src/lib/server/settings.jsx b/src/cockpit/389-console/src/lib/server/settings.jsx
index 8cc4c48..bb1ee6e 100644
--- a/src/cockpit/389-console/src/lib/server/settings.jsx
+++ b/src/cockpit/389-console/src/lib/server/settings.jsx
@@ -1,6 +1,5 @@
import cockpit from "cockpit";
import React from "react";
-import { NotificationController } from "../notifications.jsx";
import { log_cmd, valid_dn } from "../tools.jsx";
import {
Button,
@@ -16,6 +15,7 @@ import {
Spinner,
TabContainer,
TabContent,
+ noop,
TabPane,
} from "patternfly-react";
import PropTypes from "prop-types";
@@ -65,7 +65,6 @@ export class ServerSettings extends React.Component {
this.state = {
loading: true,
activeKey: 1,
- notifications: [],
attrs: this.props.attrs,
// Setting lists
configSaveDisabled: true,
@@ -82,8 +81,6 @@ export class ServerSettings extends React.Component {
errObjAdv: {},
};

- this.removeNotification = this.removeNotification.bind(this);
- this.addNotification = this.addNotification.bind(this);
this.handleNavSelect = this.handleNavSelect.bind(this);
this.handleConfigChange = this.handleConfigChange.bind(this);
this.handleRootDNChange = this.handleRootDNChange.bind(this);
@@ -111,29 +108,6 @@ export class ServerSettings extends React.Component {
this.props.enableTree();
}

- 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
- )
- });
- }
-
handleNavSelect(key) {
this.setState({ activeKey: key });
}
@@ -440,7 +414,7 @@ export class ServerSettings extends React.Component {
.spawn(cmd, {superuser: true, "err": "message"})
.done(content => {
this.reloadRootDN();
- this.addNotification(
+ this.props.addNotification(
"success",
"Successfully updated Directory Manager configuration"
);
@@ -448,7 +422,7 @@ export class ServerSettings extends React.Component {
.fail(err => {
let errMsg = JSON.parse(err);
this.reloadRootDN();
- this.addNotification(
+ this.props.addNotification(
"error",
`Error updating Directory Manager configuration - ${errMsg.desc}`
);
@@ -490,7 +464,7 @@ export class ServerSettings extends React.Component {
this.setState({
rootDNReloading: false,
});
- this.addNotification(
+ this.props.addNotification(
"error",
`Error reloading Directory Manager configuration - ${errMsg.desc}`
);
@@ -522,7 +496,7 @@ export class ServerSettings extends React.Component {
.spawn(cmd, {superuser: true, "err": "message"})
.done(content => {
this.reloadDiskMonitoring();
- this.addNotification(
+ this.props.addNotification(
"success",
"Successfully updated Disk Monitoring configuration"
);
@@ -530,7 +504,7 @@ export class ServerSettings extends React.Component {
.fail(err => {
let errMsg = JSON.parse(err);
this.reloadDiskMonitoring();
- this.addNotification(
+ this.props.addNotification(
"error",
`Error updating Disk Monitoring configuration - ${errMsg.desc}`
);
@@ -582,7 +556,7 @@ export class ServerSettings extends React.Component {
this.setState({
diskMonReloading: false,
});
- this.addNotification(
+ this.props.addNotification(
"error",
`Error reloading Disk Monitoring configuration - ${errMsg.desc}`
);
@@ -613,7 +587,7 @@ export class ServerSettings extends React.Component {
.spawn(cmd, {superuser: true, "err": "message"})
.done(content => {
this.reloadAdvanced();
- this.addNotification(
+ this.props.addNotification(
"success",
"Successfully updated Advanced configuration"
);
@@ -621,7 +595,7 @@ export class ServerSettings extends React.Component {
.fail(err => {
let errMsg = JSON.parse(err);
this.reloadAdvanced();
- this.addNotification(
+ this.props.addNotification(
"error",
`Error updating Advanced configuration - ${errMsg.desc}`
);
@@ -719,7 +693,7 @@ export class ServerSettings extends React.Component {
})
.fail(err => {
let errMsg = JSON.parse(err);
- this.addNotification(
+ this.props.addNotification(
"error",
`Error loading Advanced configuration - ${errMsg.desc}`
);
@@ -748,7 +722,7 @@ export class ServerSettings extends React.Component {
.done(content => {
// Continue with the next mod
this.reloadConfig();
- this.addNotification(
+ this.props.addNotification(
"success",
"Successfully updated server configuration. These " +
"changes require the server to be restarted to take effect."
@@ -757,7 +731,7 @@ export class ServerSettings extends React.Component {
.fail(err => {
let errMsg = JSON.parse(err);
this.reloadConfig();
- this.addNotification(
+ this.props.addNotification(
"error",
`Error updating server configuration - ${errMsg.desc}`
);
@@ -809,7 +783,7 @@ export class ServerSettings extends React.Component {
})
.fail(err => {
let errMsg = JSON.parse(err);
- this.addNotification(
+ this.props.addNotification(
"error",
`Error reloading server configuration - ${errMsg.desc}`
);
@@ -1325,10 +1299,6 @@ export class ServerSettings extends React.Component {

return (
<div id="server-settings-page">
- <NotificationController
- notifications={this.state.notifications}
- removeNotificationAction={this.removeNotification}
- />
{body}
</div>
);
@@ -1338,11 +1308,13 @@ export class ServerSettings extends React.Component {
// Property types and defaults

ServerSettings.propTypes = {
+ addNotification: PropTypes.func,
serverId: PropTypes.string,
attrs: PropTypes.object,
};

ServerSettings.defaultProps = {
+ addNotification: noop,
serverId: "",
attrs: {},
};
diff --git a/src/cockpit/389-console/src/lib/server/tuning.jsx b/src/cockpit/389-console/src/lib/server/tuning.jsx
index f688897..6f78958 100644
--- a/src/cockpit/389-console/src/lib/server/tuning.jsx
+++ b/src/cockpit/389-console/src/lib/server/tuning.jsx
@@ -1,6 +1,5 @@
import cockpit from "cockpit";
import React from "react";
-import { NotificationController } from "../notifications.jsx";
import CustomCollapse from "../customCollapse.jsx";
import { log_cmd } from "../tools.jsx";
import {
@@ -12,6 +11,7 @@ import {
Icon,
Checkbox,
Row,
+ noop,
Spinner,
} from "patternfly-react";
import PropTypes from "prop-types";
@@ -44,14 +44,11 @@ export class ServerTuning extends React.Component {
loading: false,
loaded: false,
activeKey: 1,
- notifications: [],
saveDisabled: true,
errObj: {},
attrs: this.props.attrs,
};

- this.removeNotification = this.removeNotification.bind(this);
- this.addNotification = this.addNotification.bind(this);
this.handleChange = this.handleChange.bind(this);
this.loadConfig = this.loadConfig.bind(this);
this.saveConfig = this.saveConfig.bind(this);
@@ -68,29 +65,6 @@ export class ServerTuning extends React.Component {
this.props.enableTree();
}

- 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
- )
- });
- }
-
handleChange(e) {
let value = e.target.type === 'checkbox' ? e.target.checked : e.target.value;
let attr = e.target.id;
@@ -218,7 +192,7 @@ export class ServerTuning extends React.Component {
.spawn(cmd, {superuser: true, "err": "message"})
.done(content => {
this.loadConfig(1);
- this.addNotification(
+ this.props.addNotification(
"success",
"Successfully updated Advanced configuration"
);
@@ -226,7 +200,7 @@ export class ServerTuning extends React.Component {
.fail(err => {
let errMsg = JSON.parse(err);
this.loadConfig(1);
- this.addNotification(
+ this.props.addNotification(
"error",
`Error updating Advanced configuration - ${errMsg.desc}`
);
@@ -533,10 +507,6 @@ export class ServerTuning extends React.Component {

return (
<div id="tuning-content">
- <NotificationController
- notifications={this.state.notifications}
- removeNotificationAction={this.removeNotification}
- />
{body}
</div>
);
@@ -546,11 +516,13 @@ export class ServerTuning extends React.Component {
// Property types and defaults

ServerTuning.propTypes = {
+ addNotification: PropTypes.func,
serverId: PropTypes.string,
attrs: PropTypes.object,
};

ServerTuning.defaultProps = {
+ addNotification: noop,
serverId: "",
attrs: {},
};
diff --git a/src/cockpit/389-console/src/monitor.jsx b/src/cockpit/389-console/src/monitor.jsx
index 1c97497..a155f49 100644
--- a/src/cockpit/389-console/src/monitor.jsx
+++ b/src/cockpit/389-console/src/monitor.jsx
@@ -1,6 +1,5 @@
import cockpit from "cockpit";
import React from "react";
-import { NotificationController } from "./lib/notifications.jsx";
import { log_cmd } from "./lib/tools.jsx";
import {
TreeView,
@@ -8,6 +7,7 @@ import {
Row,
Col,
Icon,
+ noop,
ControlLabel
} from "patternfly-react";
import PropTypes from "prop-types";
@@ -31,6 +31,7 @@ export class Monitor extends React.Component {
constructor(props) {
super(props);
this.state = {
+ firstLoad: true,
nodes: [],
node_name: "",
node_text: "",
@@ -41,7 +42,6 @@ export class Monitor extends React.Component {
serverData: {},
disks: [],
loadingMsg: "",
- notifications: [],
disableTree: false,
// Suffix
suffixLoading: false,
@@ -110,8 +110,6 @@ export class Monitor extends React.Component {
this.sev_all_info = [sev_warn, sev_notice, sev_info, sev_debug];

// Bindings
- this.addNotification = this.addNotification.bind(this);
- this.removeNotification = this.removeNotification.bind(this);
this.loadSuffixTree = this.loadSuffixTree.bind(this);
this.enableTree = this.enableTree.bind(this);
this.update_tree_nodes = this.update_tree_nodes.bind(this);
@@ -155,40 +153,24 @@ export class Monitor extends React.Component {
this.handleSevChange = this.handleSevChange.bind(this);
}

- componentDidMount() {
- this.loadMonitor();
- }
-
componentDidUpdate(prevProps) {
- if (this.props.serverId !== prevProps.serverId) {
- this.loadSuffixTree(false);
- }
- }
-
- addNotification(type, message, timerdelay, persistent) {
- this.setState(prevState => ({
- notifications: [
- ...prevState.notifications,
- {
- key: prevState.notifications.length + 1,
- type: type,
- persistent: persistent,
- timerdelay: timerdelay,
- message: message,
+ if (this.props.wasActiveList.includes(6)) {
+ if (this.state.firstLoad) {
+ this.loadMonitor();
+ } else {
+ if (this.props.serverId !== prevProps.serverId) {
+ this.loadSuffixTree(false);
}
- ]
- }));
- }
-
- removeNotification(notificationToRemove) {
- this.setState({
- notifications: this.state.notifications.filter(
- notification => notificationToRemove.key !== notification.key
- )
- });
+ }
+ }
}

loadSuffixTree(fullReset) {
+ if (this.state.firstLoad) {
+ this.setState({
+ firstLoad: false
+ });
+ }
const cmd = [
"dsconf", "-j", "ldapi://%2fvar%2frun%2fslapd-" + this.props.serverId + ".socket",
"backend", "get-tree",
@@ -1207,7 +1189,7 @@ export class Monitor extends React.Component {
suffix={this.state.replSuffix}
serverId={this.props.serverId}
data={this.state[this.state.replSuffix]}
- addNotification={this.addNotification}
+ addNotification={this.props.addNotification}
reloadAgmts={this.reloadReplAgmts}
reloadWinsyncAgmts={this.reloadReplWinsyncAgmts}
reloadConflicts={this.loadConflicts}
@@ -1261,10 +1243,6 @@ export class Monitor extends React.Component {
}
monitorPage =
<div className="container-fluid">
- <NotificationController
- notifications={this.state.notifications}
- removeNotificationAction={this.removeNotification}
- />
<div className="ds-container">
<div>
<div className="ds-tree">
@@ -1305,9 +1283,11 @@ export class Monitor extends React.Component {
// Property types and defaults

Monitor.propTypes = {
+ addNotification: PropTypes.func,
serverId: PropTypes.string
};

Monitor.defaultProps = {
+ addNotification: noop,
serverId: ""
};
diff --git a/src/cockpit/389-console/src/plugins.jsx b/src/cockpit/389-console/src/plugins.jsx
index 342a19c..ae24945 100644
--- a/src/cockpit/389-console/src/plugins.jsx
+++ b/src/cockpit/389-console/src/plugins.jsx
@@ -2,7 +2,7 @@ import cockpit from "cockpit";
import React from "react";
import PropTypes from "prop-types";
import { log_cmd } from "./lib/tools.jsx";
-import { Col, Row, Tab, Nav, NavItem, Spinner } from "patternfly-react";
+import { Col, Row, Tab, Nav, NavItem, noop, Spinner } from "patternfly-react";
import PluginEditModal from "./lib/plugins/pluginModal.jsx";
import { PluginTable } from "./lib/plugins/pluginTables.jsx";
import AccountPolicy from "./lib/plugins/accountPolicy.jsx";
@@ -18,25 +18,20 @@ import RetroChangelog from "./lib/plugins/retroChangelog.jsx";
import RootDNAccessControl from "./lib/plugins/rootDNAccessControl.jsx";
import USN from "./lib/plugins/usn.jsx";
import WinSync from "./lib/plugins/winsync.jsx";
-import { NotificationController } from "./lib/notifications.jsx";
import "./css/ds.css";

var cmd;

export class Plugins extends React.Component {
- componentWillMount() {
- this.pluginList();
- this.setState(prevState => ({
- pluginTabs: {
- ...prevState.pluginTabs,
- basicConfig: true
- }
- }));
- }
-
componentDidUpdate(prevProps) {
- if (this.props.serverId !== prevProps.serverId) {
- this.pluginList();
+ if (this.props.wasActiveList.includes(5)) {
+ if (this.state.firstLoad) {
+ this.pluginList();
+ } else {
+ if (this.props.serverId !== prevProps.serverId) {
+ this.pluginList();
+ }
+ }
}
}

@@ -48,14 +43,12 @@ export class Plugins extends React.Component {
this.openPluginModal = this.openPluginModal.bind(this);
this.closePluginModal = this.closePluginModal.bind(this);
this.pluginList = this.pluginList.bind(this);
- this.removeNotification = this.removeNotification.bind(this);
- this.addNotification = this.addNotification.bind(this);
this.onChangeTab = this.onChangeTab.bind(this);
this.savePlugin = this.savePlugin.bind(this);
this.toggleLoading = this.toggleLoading.bind(this);

this.state = {
- notifications: [],
+ firstLoad: true,
loading: false,
showPluginModal: false,
currentPluginTab: "",
@@ -81,29 +74,6 @@ export class Plugins extends React.Component {
this.setState({ currentPluginTab: event.target.value });
}

- 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
- )
- });
- }
-
handleFieldChange(e) {
this.setState({
[e.target.id]: e.target.value
@@ -168,6 +138,15 @@ export class Plugins extends React.Component {
}

pluginList() {
+ if (this.state.firstLoad) {
+ this.setState(prevState => ({
+ firstLoad: false,
+ pluginTabs: {
+ ...prevState.pluginTabs,
+ basicConfig: true
+ }
+ }));
+ }
cmd = [
"dsconf",
"-j",
@@ -239,7 +218,10 @@ export class Plugins extends React.Component {
.done(content => {
console.info("savePlugin", "Result", content);
basicPluginSuccess = true;
- this.addNotification("success", `Plugin ${data.name} was successfully modified`);
+ this.props.addNotification(
+ "success",
+ `Plugin ${data.name} was successfully modified`
+ );
this.pluginList();
this.closePluginModal();
this.toggleLoading();
@@ -249,7 +231,7 @@ export class Plugins extends React.Component {
if (errMsg.desc.indexOf("nothing to set") >= 0) {
nothingToSetErr = true;
} else {
- this.addNotification(
+ this.props.addNotification(
"error",
`${errMsg.desc} error during ${data.name} modification`
);
@@ -273,7 +255,7 @@ export class Plugins extends React.Component {
.done(content => {
// Notify success only one time
if (!basicPluginSuccess) {
- this.addNotification(
+ this.props.addNotification(
"success",
`Plugin ${data.name} was successfully modified`
);
@@ -289,13 +271,13 @@ export class Plugins extends React.Component {
errMsg.desc.indexOf("nothing to set") < 0
) {
if (basicPluginSuccess) {
- this.addNotification(
+ this.props.addNotification(
"success",
`Plugin ${data.name} was successfully modified`
);
this.pluginList();
}
- this.addNotification(
+ this.props.addNotification(
"error",
`${errMsg.desc} error during ${data.name} modification`
);
@@ -324,7 +306,7 @@ export class Plugins extends React.Component {
serverId={this.props.serverId}
savePluginHandler={this.savePlugin}
pluginListHandler={this.pluginList}
- addNotification={this.addNotification}
+ addNotification={this.props.addNotification}
toggleLoadingHandler={this.toggleLoading}
/>
)
@@ -337,8 +319,9 @@ export class Plugins extends React.Component {
serverId={this.props.serverId}
savePluginHandler={this.savePlugin}
pluginListHandler={this.pluginList}
- addNotification={this.addNotification}
+ addNotification={this.props.addNotification}
toggleLoadingHandler={this.toggleLoading}
+ wasActiveList={this.props.wasActiveList}
/>
)
},
@@ -350,8 +333,9 @@ export class Plugins extends React.Component {
serverId={this.props.serverId}
savePluginHandler={this.savePlugin}
pluginListHandler={this.pluginList}
- addNotification={this.addNotification}
+ addNotification={this.props.addNotification}
toggleLoadingHandler={this.toggleLoading}
+ wasActiveList={this.props.wasActiveList}
/>
)
},
@@ -363,8 +347,9 @@ export class Plugins extends React.Component {
serverId={this.props.serverId}
savePluginHandler={this.savePlugin}
pluginListHandler={this.pluginList}
- addNotification={this.addNotification}
+ addNotification={this.props.addNotification}
toggleLoadingHandler={this.toggleLoading}
+ wasActiveList={this.props.wasActiveList}
/>
)
},
@@ -376,8 +361,9 @@ export class Plugins extends React.Component {
serverId={this.props.serverId}
savePluginHandler={this.savePlugin}
pluginListHandler={this.pluginList}
- addNotification={this.addNotification}
+ addNotification={this.props.addNotification}
toggleLoadingHandler={this.toggleLoading}
+ wasActiveList={this.props.wasActiveList}
/>
)
},
@@ -389,8 +375,9 @@ export class Plugins extends React.Component {
serverId={this.props.serverId}
savePluginHandler={this.savePlugin}
pluginListHandler={this.pluginList}
- addNotification={this.addNotification}
+ addNotification={this.props.addNotification}
toggleLoadingHandler={this.toggleLoading}
+ wasActiveList={this.props.wasActiveList}
/>
)
},
@@ -402,7 +389,7 @@ export class Plugins extends React.Component {
serverId={this.props.serverId}
savePluginHandler={this.savePlugin}
pluginListHandler={this.pluginList}
- addNotification={this.addNotification}
+ addNotification={this.props.addNotification}
toggleLoadingHandler={this.toggleLoading}
/>
)
@@ -415,8 +402,9 @@ export class Plugins extends React.Component {
serverId={this.props.serverId}
savePluginHandler={this.savePlugin}
pluginListHandler={this.pluginList}
- addNotification={this.addNotification}
+ addNotification={this.props.addNotification}
toggleLoadingHandler={this.toggleLoading}
+ wasActiveList={this.props.wasActiveList}
/>
)
},
@@ -428,7 +416,7 @@ export class Plugins extends React.Component {
serverId={this.props.serverId}
savePluginHandler={this.savePlugin}
pluginListHandler={this.pluginList}
- addNotification={this.addNotification}
+ addNotification={this.props.addNotification}
toggleLoadingHandler={this.toggleLoading}
/>
)
@@ -441,8 +429,9 @@ export class Plugins extends React.Component {
serverId={this.props.serverId}
savePluginHandler={this.savePlugin}
pluginListHandler={this.pluginList}
- addNotification={this.addNotification}
+ addNotification={this.props.addNotification}
toggleLoadingHandler={this.toggleLoading}
+ wasActiveList={this.props.wasActiveList}
/>
)
},
@@ -454,8 +443,9 @@ export class Plugins extends React.Component {
serverId={this.props.serverId}
savePluginHandler={this.savePlugin}
pluginListHandler={this.pluginList}
- addNotification={this.addNotification}
+ addNotification={this.props.addNotification}
toggleLoadingHandler={this.toggleLoading}
+ wasActiveList={this.props.wasActiveList}
/>
)
},
@@ -467,7 +457,7 @@ export class Plugins extends React.Component {
serverId={this.props.serverId}
savePluginHandler={this.savePlugin}
pluginListHandler={this.pluginList}
- addNotification={this.addNotification}
+ addNotification={this.props.addNotification}
toggleLoadingHandler={this.toggleLoading}
/>
)
@@ -480,18 +470,15 @@ export class Plugins extends React.Component {
serverId={this.props.serverId}
savePluginHandler={this.savePlugin}
pluginListHandler={this.pluginList}
- addNotification={this.addNotification}
+ addNotification={this.props.addNotification}
toggleLoadingHandler={this.toggleLoading}
+ wasActiveList={this.props.wasActiveList}
/>
)
}
};
return (
<div className="container-fluid">
- <NotificationController
- notifications={this.state.notifications}
- removeNotificationAction={this.removeNotification}
- />
<Row className="clearfix">
<Col sm={12}>
<Spinner
@@ -553,9 +540,11 @@ export class Plugins extends React.Component {
}

Plugins.propTypes = {
+ addNotification: PropTypes.func,
serverId: PropTypes.string
};

Plugins.defaultProps = {
+ addNotification: noop,
serverId: ""
};
diff --git a/src/cockpit/389-console/src/replication.jsx b/src/cockpit/389-console/src/replication.jsx
index 755e1d0..2c91d15 100644
--- a/src/cockpit/389-console/src/replication.jsx
+++ b/src/cockpit/389-console/src/replication.jsx
@@ -1,10 +1,9 @@
import cockpit from "cockpit";
import React from "react";
-import { NotificationController } from "./lib/notifications.jsx";
import { log_cmd } from "./lib/tools.jsx";
import { ReplSuffix } from "./lib/replication/replSuffix.jsx";
import { Changelog } from "./lib/replication/replChangelog.jsx";
-import { TreeView, Spinner } from "patternfly-react";
+import { TreeView, noop, Spinner } from "patternfly-react";
import PropTypes from "prop-types";
import "./css/ds.css";

@@ -16,7 +15,7 @@ export class Replication extends React.Component {
constructor(props) {
super(props);
this.state = {
- notifications: [],
+ firstLoad: true,
errObj: {},
nodes: [],
node_name: "",
@@ -54,8 +53,6 @@ export class Replication extends React.Component {

// 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.disableTree = this.disableTree.bind(this);
this.enableTree = this.enableTree.bind(this);
@@ -71,24 +68,27 @@ export class Replication extends React.Component {
this.loadSuffixTree = this.loadSuffixTree.bind(this);
}

- componentWillMount () {
- this.loadReplication();
- if (!this.state.loaded) {
- this.loadAttrs();
- }
- }
-
- componentDidMount() {
- // this.loadSuffixTree(false);
- }
-
componentDidUpdate(prevProps) {
- if (this.props.serverId !== prevProps.serverId) {
- this.loadSuffixTree(true);
+ if (this.props.wasActiveList.includes(3)) {
+ if (this.state.firstLoad) {
+ this.loadReplication();
+ if (!this.state.loaded) {
+ this.loadAttrs();
+ }
+ } else {
+ if (this.props.serverId !== prevProps.serverId) {
+ this.loadSuffixTree(true);
+ }
+ }
}
}

- loadReplication () {
+ loadReplication() {
+ if (this.state.firstLoad) {
+ this.setState({
+ firstLoad: false
+ });
+ }
// Load the changelog, and build the suffix tree
this.setState({
loaded: false
@@ -375,29 +375,6 @@ export class Replication extends React.Component {
});
}

- 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. This is the last
@@ -689,7 +666,7 @@ export class Replication extends React.Component {
.fail(err => {
let errMsg = JSON.parse(err);
if (errMsg.desc != "No such object") {
- this.addNotification(
+ this.props.addNotification(
"error",
`Error loading suffix RUV - ${errMsg.desc}`
);
@@ -922,7 +899,7 @@ export class Replication extends React.Component {
.fail(err => {
let errMsg = JSON.parse(err);
if (errMsg.desc != "No such object") {
- this.addNotification(
+ this.props.addNotification(
"error",
`Error loading suffix RUV - ${errMsg.desc}`
);
@@ -935,7 +912,7 @@ export class Replication extends React.Component {
})
.fail(err => {
let errMsg = JSON.parse(err);
- this.addNotification(
+ this.props.addNotification(
"error",
`Error loading winsync agreements - ${errMsg.desc}`
);
@@ -947,7 +924,7 @@ export class Replication extends React.Component {
})
.fail(err => {
let errMsg = JSON.parse(err);
- this.addNotification(
+ this.props.addNotification(
"error",
`Error loading replication agreements configuration - ${errMsg.desc}`
);
@@ -987,7 +964,7 @@ export class Replication extends React.Component {
})
.fail(err => {
let errMsg = JSON.parse(err);
- this.addNotification(
+ this.props.addNotification(
"error",
`Failed to get attributes - ${errMsg.desc}`
);
@@ -1033,7 +1010,7 @@ export class Replication extends React.Component {
suffix={this.state.node_name}
role={this.state[this.state.node_name].role}
data={this.state[this.state.node_name]}
- addNotification={this.addNotification}
+ addNotification={this.props.addNotification}
agmtRows={this.state[this.state.node_name].agmtRows}
winsyncRows={this.state[this.state.node_name].winsyncRows}
ruvRows={this.state[this.state.node_name].ruvRows}
@@ -1059,7 +1036,7 @@ export class Replication extends React.Component {
suffix={this.state.node_name}
role=""
data=""
- addNotification={this.addNotification}
+ addNotification={this.props.addNotification}
disableWSAgmtTable={this.state.disableWSAgmtTable}
disableAgmtTable={this.state.disableAgmtTable}
reloadAgmts={this.reloadAgmts}
@@ -1087,7 +1064,7 @@ export class Replication extends React.Component {
clCompactInt={this.state.clCompactInt}
clTrimInt={this.state.clTrimInt}
clEncrypt={this.state.clEncrypt}
- addNotification={this.addNotification}
+ addNotification={this.props.addNotification}
enableTree={this.enableTree}
reload={this.reloadChangelog}
loading={this.state.clLoading}
@@ -1096,10 +1073,6 @@ export class Replication extends React.Component {
}
repl_page =
<div className="container-fluid">
- <NotificationController
- notifications={this.state.notifications}
- removeNotificationAction={this.removeNotification}
- />
<div className="ds-container">
<div>
<div className="ds-tree">
@@ -1138,10 +1111,12 @@ export class Replication extends React.Component {
// Property types and defaults

Replication.propTypes = {
+ addNotification: PropTypes.func,
serverId: PropTypes.string
};

Replication.defaultProps = {
+ addNotification: noop,
serverId: ""
};

diff --git a/src/cockpit/389-console/src/schema.jsx b/src/cockpit/389-console/src/schema.jsx
index 7e6ade6..0078e47 100644
--- a/src/cockpit/389-console/src/schema.jsx
+++ b/src/cockpit/389-console/src/schema.jsx
@@ -1,6 +1,5 @@
import cockpit from "cockpit";
import React from "react";
-import { NotificationController } from "./lib/notifications.jsx";
import { log_cmd, searchFilter } from "./lib/tools.jsx";
import {
ObjectClassesTable,
@@ -16,27 +15,30 @@ import {
TabContent,
TabPane,
Spinner,
+ noop,
Button
} from "patternfly-react";
import PropTypes from "prop-types";
import "./css/ds.css";

export class Schema extends React.Component {
- componentWillMount() {
- this.loadSyntaxesFirst();
- }
-
componentDidUpdate(prevProps) {
- if (this.props.serverId !== prevProps.serverId) {
- this.loadSyntaxesFirst();
+ if (this.props.wasActiveList.includes(4)) {
+ if (this.state.firstLoad) {
+ this.loadSyntaxesFirst();
+ } else {
+ if (this.props.serverId !== prevProps.serverId) {
+ this.loadSyntaxesFirst();
+ }
+ }
}
}

constructor(props) {
super(props);
this.state = {
+ firstLoad: true,
loading: false,
- notifications: [],
activeKey: 1,

objectclassRows: [],
@@ -84,8 +86,6 @@ export class Schema extends React.Component {
};

this.handleFieldChange = this.handleFieldChange.bind(this);
- this.addNotification = this.addNotification.bind(this);
- this.removeNotification = this.removeNotification.bind(this);
this.handleNavSelect = this.handleNavSelect.bind(this);
this.handleTypeaheadChange = this.handleTypeaheadChange.bind(this);
this.loadSchemaData = this.loadSchemaData.bind(this);
@@ -138,6 +138,12 @@ export class Schema extends React.Component {
}

loadSyntaxesFirst() {
+ if (this.state.firstLoad) {
+ this.setState({
+ firstLoad: false
+ });
+ }
+ this.toggleLoading("allSchema");
let cmd = [
"dsconf",
"-j",
@@ -172,9 +178,6 @@ export class Schema extends React.Component {
"schema",
"list"
];
- if (initialLoading) {
- this.toggleLoading("allSchema");
- }
log_cmd("loadSchemaData", "Get schema objects in one batch", cmd);
cockpit
.spawn(cmd, { superuser: true, err: "message" })
@@ -389,13 +392,13 @@ export class Schema extends React.Component {
})
.done(content => {
console.info("deleteObjectclass", "Result", content);
- this.addNotification("success", `ObjectClass ${name} was successfully deleted`);
+ this.props.addNotification("success", `ObjectClass ${name} was successfully deleted`);
this.loadSchemaData();
this.toggleLoading("ocTable");
})
.fail(err => {
let errMsg = JSON.parse(err);
- this.addNotification(
+ this.props.addNotification(
"error",
`Error during ObjectClass removal operation - ${errMsg.desc}`
);
@@ -415,7 +418,7 @@ export class Schema extends React.Component {
cmdOperationObjectclass(action) {
const { ocName, ocDesc, ocOID, ocParent, ocKind, ocMust, ocMay } = this.state;
if (ocName == "") {
- this.addNotification("warning", "ObjectClass Name is required.");
+ this.props.addNotification("warning", "ObjectClass Name is required.");
} else {
let cmd = [
"dsconf",
@@ -461,7 +464,7 @@ export class Schema extends React.Component {
})
.done(content => {
console.info("cmdOperationObjectclass", "Result", content);
- this.addNotification(
+ this.props.addNotification(
"success",
`ObjectClass ${ocName} - ${action} operation was successfull`
);
@@ -471,7 +474,7 @@ export class Schema extends React.Component {
})
.fail(err => {
let errMsg = JSON.parse(err);
- this.addNotification(
+ this.props.addNotification(
"error",
`Error during the ObjectClass ${action} operation - ${errMsg.desc}`
);
@@ -665,13 +668,13 @@ export class Schema extends React.Component {
})
.done(content => {
console.info("deleteAttribute", "Result", content);
- this.addNotification("success", `Attribute ${name} was successfully deleted`);
+ this.props.addNotification("success", `Attribute ${name} was successfully deleted`);
this.loadSchemaData();
this.toggleLoading("atTable");
})
.fail(err => {
let errMsg = JSON.parse(err);
- this.addNotification(
+ this.props.addNotification(
"error",
`Error during Attribute removal operation - ${errMsg.desc}`
);
@@ -705,7 +708,7 @@ export class Schema extends React.Component {
} = this.state;

if (atName == "" || atSyntax.length == 0) {
- this.addNotification("warning", "Attribute Name and Syntax are required.");
+ this.props.addNotification("warning", "Attribute Name and Syntax are required.");
} else {
let cmd = [
"dsconf",
@@ -774,7 +777,7 @@ export class Schema extends React.Component {
})
.done(content => {
console.info("cmdOperationAttribute", "Result", content);
- this.addNotification(
+ this.props.addNotification(
"success",
`Attribute ${atName} - ${action} operation was successfull`
);
@@ -784,7 +787,7 @@ export class Schema extends React.Component {
})
.fail(err => {
let errMsg = JSON.parse(err);
- this.addNotification(
+ this.props.addNotification(
"error",
`Error during the Attribute ${action} operation - ${errMsg.desc}`
);
@@ -795,29 +798,6 @@ export class Schema extends React.Component {
}
}

- 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
- )
- });
- }
-
handleNavSelect(key) {
this.setState({
activeKey: key
@@ -876,10 +856,6 @@ export class Schema extends React.Component {
} else {
schemaPage = (
<div className="container-fluid">
- <NotificationController
- notifications={this.state.notifications}
- removeNotificationAction={this.removeNotification}
- />
<div className="ds-tab-table">
<TabContainer
id="basic-tabs-pf"
@@ -1032,10 +1008,12 @@ export class Schema extends React.Component {
// Props and defaultProps

Schema.propTypes = {
+ addNotification: PropTypes.func,
serverId: PropTypes.string
};

Schema.defaultProps = {
+ addNotification: noop,
serverId: ""
};

diff --git a/src/cockpit/389-console/src/security.jsx b/src/cockpit/389-console/src/security.jsx
index 062be2e..815f664 100644
--- a/src/cockpit/389-console/src/security.jsx
+++ b/src/cockpit/389-console/src/security.jsx
@@ -1,7 +1,7 @@
import cockpit from "cockpit";
import React from "react";
import Switch from "react-switch";
-import { NotificationController, ConfirmPopup } from "./lib/notifications.jsx";
+import { ConfirmPopup } from "./lib/notifications.jsx";
import { log_cmd } from "./lib/tools.jsx";
import { Typeahead } from "react-bootstrap-typeahead";
import { CertificateManagement } from "./lib/security/certificateManagement.jsx";
@@ -21,7 +21,8 @@ import {
Spinner,
TabContainer,
TabContent,
- TabPane,
+ noop,
+ TabPane
} from "patternfly-react";
import PropTypes from "prop-types";
import "./css/ds.css";
@@ -32,7 +33,6 @@ export class Security extends React.Component {
this.state = {
loaded: false,
saving: false,
- notifications: [],
activeKey: 1,

errObj: {},
@@ -71,8 +71,6 @@ export class Security extends React.Component {
};

this.handleChange = this.handleChange.bind(this);
- this.addNotification = this.addNotification.bind(this);
- this.removeNotification = this.removeNotification.bind(this);
this.handleNavSelect = this.handleNavSelect.bind(this);
this.handleSwitchChange = this.handleSwitchChange.bind(this);
this.handleTypeaheadChange = this.handleTypeaheadChange.bind(this);
@@ -88,29 +86,6 @@ export class Security extends React.Component {
this.closeSecurityEnableModal = this.closeSecurityEnableModal.bind(this);
}

- 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
- )
- });
- }
-
componentWillMount () {
if (!this.state.loaded) {
this.setState({securityEnabled: true}, this.setState({securityEnabled: false}));
@@ -122,6 +97,12 @@ export class Security extends React.Component {
this.props.enableTree();
}

+ componentDidUpdate(prevProps) {
+ if (this.props.serverId !== prevProps.serverId) {
+ this.loadSecurityConfig();
+ }
+ }
+
loadSupportedCiphers () {
const cmd = [
"dsconf", "-j", "ldapi://%2fvar%2frun%2fslapd-" + this.props.serverId + ".socket",
@@ -142,7 +123,7 @@ export class Security extends React.Component {
if ('info' in errMsg) {
msg = errMsg.desc + " - " + errMsg.info;
}
- this.addNotification(
+ this.props.addNotification(
"error",
`Error loading security configuration - ${msg}`
);
@@ -169,7 +150,7 @@ export class Security extends React.Component {
if ('info' in errMsg) {
msg = errMsg.desc + " - " + errMsg.info;
}
- this.addNotification(
+ this.props.addNotification(
"error",
`Error loading security configuration - ${msg}`
);
@@ -199,7 +180,7 @@ export class Security extends React.Component {
if ('info' in errMsg) {
msg = errMsg.desc + " - " + errMsg.info;
}
- this.addNotification(
+ this.props.addNotification(
"error",
`Error loading CA certificates - ${msg}`
);
@@ -234,7 +215,7 @@ export class Security extends React.Component {
if ('info' in errMsg) {
msg = errMsg.desc + " - " + errMsg.info;
}
- this.addNotification(
+ this.props.addNotification(
"error",
`Error loading server certificates - ${msg}`
);
@@ -265,7 +246,7 @@ export class Security extends React.Component {
if ('info' in errMsg) {
msg = errMsg.desc + " - " + errMsg.info;
}
- this.addNotification(
+ this.props.addNotification(
"error",
`Error loading security RSA configuration - ${msg}`
);
@@ -363,7 +344,7 @@ export class Security extends React.Component {
if ('info' in errMsg) {
msg = errMsg.desc + " - " + errMsg.info;
}
- this.addNotification(
+ this.props.addNotification(
"error",
`Error loading security configuration - ${msg}`
);
@@ -389,7 +370,7 @@ export class Security extends React.Component {
showSecurityEnableModal: true,
});
} else {
- this.addNotification(
+ this.props.addNotification(
"error",
`There must be at least one server certificate present in the security database to enable security`
);
@@ -430,7 +411,7 @@ export class Security extends React.Component {
cockpit
.spawn(cmd, { superuser: true, err: "message" })
.done(() => {
- this.addNotification(
+ this.props.addNotification(
"success",
`Successfully enabled security. You must restart the server for this to take effect.`
);
@@ -446,7 +427,7 @@ export class Security extends React.Component {
if ('info' in errMsg) {
msg = errMsg.desc + " - " + errMsg.info;
}
- this.addNotification(
+ this.props.addNotification(
"error",
`Error enabling security - ${msg}`
);
@@ -466,7 +447,7 @@ export class Security extends React.Component {
cockpit
.spawn(cmd, { superuser: true, err: "message" })
.done(() => {
- this.addNotification(
+ this.props.addNotification(
"success",
`Successfully disabled security. You must restart the server for this to take effect.`
);
@@ -480,7 +461,7 @@ export class Security extends React.Component {
if ('info' in errMsg) {
msg = errMsg.desc + " - " + errMsg.info;
}
- this.addNotification(
+ this.props.addNotification(
"error",
`Error disabling security - ${msg}`
);
@@ -499,7 +480,7 @@ export class Security extends React.Component {
}

if (sslMin > sslMax) {
- this.addNotification(
+ this.props.addNotification(
"error",
`The TLS minimum version but be less than or equal to the TLS maximum version`
);
@@ -571,7 +552,7 @@ export class Security extends React.Component {
.spawn(cmd, {superuser: true, "err": "message"})
.done(content => {
this.loadSecurityConfig(1);
- this.addNotification(
+ this.props.addNotification(
"success",
msg
);
@@ -589,7 +570,7 @@ export class Security extends React.Component {
if ('info' in errMsg) {
msg = errMsg.desc + " - " + errMsg.info;
}
- this.addNotification(
+ this.props.addNotification(
"error",
`Error updating security configuration - ${msg}`
);
@@ -778,10 +759,6 @@ export class Security extends React.Component {

securityPage =
<div className="container-fluid">
- <NotificationController
- notifications={this.state.notifications}
- removeNotificationAction={this.removeNotification}
- />
<Row>
<Col sm={11}>
<ControlLabel className="ds-suffix-header">
@@ -835,7 +812,7 @@ export class Security extends React.Component {
serverId={this.props.serverId}
CACerts={this.state.CACerts}
ServerCerts={this.state.serverCerts}
- addNotification={this.addNotification}
+ addNotification={this.props.addNotification}
/>
</div>
</TabPane>
@@ -847,7 +824,7 @@ export class Security extends React.Component {
supportedCiphers={this.state.supportedCiphers}
cipherPref={this.state.cipherPref}
enabledCiphers={this.state.enabledCiphers}
- addNotification={this.addNotification}
+ addNotification={this.props.addNotification}
/>
</div>
</TabPane>
@@ -898,10 +875,12 @@ export class Security extends React.Component {
// Props and defaultProps

Security.propTypes = {
+ addNotification: PropTypes.func,
serverId: PropTypes.string,
};

Security.defaultProps = {
+ addNotification: noop,
serverId: "",
};

diff --git a/src/cockpit/389-console/src/server.jsx b/src/cockpit/389-console/src/server.jsx
index 7ad9fea..a67ba40 100644
--- a/src/cockpit/389-console/src/server.jsx
+++ b/src/cockpit/389-console/src/server.jsx
@@ -1,11 +1,7 @@
import cockpit from "cockpit";
import React from "react";
-import { NotificationController } from "./lib/notifications.jsx";
import { log_cmd } from "./lib/tools.jsx";
-import {
- TreeView,
- Spinner,
-} from "patternfly-react";
+import { TreeView, Spinner, noop } from "patternfly-react";
import PropTypes from "prop-types";
import { ServerSettings } from "./lib/server/settings.jsx";
import { ServerTuning } from "./lib/server/tuning.jsx";
@@ -18,88 +14,77 @@ import { ServerErrorLog } from "./lib/server/errorLog.jsx";
import { Security } from "./security.jsx";

const treeViewContainerStyles = {
- width: '295px',
+ width: "295px"
};

export class Server extends React.Component {
constructor(props) {
super(props);
this.state = {
+ firstLoad: true,
nodes: [],
node_name: "",
node_text: "",
attrs: [],
loaded: false,
- disableTree: false,
+ disableTree: false
};

- this.addNotification = this.addNotification.bind(this);
- this.removeNotification = this.removeNotification.bind(this);
this.loadTree = this.loadTree.bind(this);
this.enableTree = this.enableTree.bind(this);
this.selectNode = this.selectNode.bind(this);
}

- componentWillMount() {
- this.loadConfig();
+ componentDidUpdate(prevProps) {
+ if (this.props.wasActiveList.includes(1)) {
+ if (this.state.firstLoad) {
+ this.loadConfig();
+ } else {
+ if (this.props.serverId !== prevProps.serverId) {
+ this.loadConfig();
+ }
+ }
+ }
}

enableTree() {
this.setState({
- disableTree: false,
+ disableTree: false
});
}

- loadConfig () {
- let cmd = [
- "dsconf", "-j", this.props.serverId, "config", "get"
- ];
+ loadConfig() {
+ this.setState({
+ loaded: false,
+ firstLoad: false
+ });
+ let cmd = ["dsconf", "-j", this.props.serverId, "config", "get"];
log_cmd("loadConfig", "Load server configuration", cmd);
cockpit
.spawn(cmd, { superuser: true, err: "message" })
.done(content => {
let config = JSON.parse(content);
let attrs = config.attrs;
- this.setState({
- loaded: true,
- attrs: attrs
- }, this.loadTree());
+ this.setState(
+ {
+ loaded: true,
+ attrs: attrs
+ },
+ this.loadTree()
+ );
})
.fail(err => {
let errMsg = JSON.parse(err);
this.setState({
- loaded: true,
+ loaded: true
});
- this.addNotification(
+ this.props.addNotification(
"error",
`Error loading server configuration - ${errMsg.desc}`
);
});
}

- 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
- )
- });
- }
-
loadTree() {
let basicData = [
{
@@ -107,7 +92,7 @@ export class Server extends React.Component {
selectable: true,
selected: true,
icon: "pficon-settings",
- state: {"expanded": true},
+ state: { expanded: true },
id: "settings-config",
nodes: []
},
@@ -144,42 +129,42 @@ export class Server extends React.Component {
icon: "pficon-catalog",
selectable: false,
id: "logging-config",
- state: {"expanded": true},
+ state: { expanded: true },
nodes: [
{
text: "Access Log",
icon: "glyphicon glyphicon-book",
selectable: true,
id: "access-log-config",
- type: "log",
+ type: "log"
},
{
text: "Audit Log",
icon: "glyphicon glyphicon-book",
selectable: true,
id: "audit-log-config",
- type: "log",
+ type: "log"
},
{
text: "Audit Failure Log",
icon: "glyphicon glyphicon-book",
selectable: true,
id: "auditfail-log-config",
- type: "log",
+ type: "log"
},
{
text: "Errors Log",
icon: "glyphicon glyphicon-book",
selectable: true,
id: "error-log-config",
- type: "log",
- },
+ type: "log"
+ }
]
- },
+ }
];
this.setState({
nodes: basicData,
- node_name: this.state.node_name,
+ node_name: this.state.node_name
});
}

@@ -188,7 +173,7 @@ export class Server extends React.Component {
return;
}
this.setState({
- disableTree: true, // Disable the tree to allow node to be fully loaded
+ disableTree: true // Disable the tree to allow node to be fully loaded
});

this.setState(prevState => {
@@ -196,7 +181,7 @@ export class Server extends React.Component {
nodes: this.nodeSelector(prevState.nodes, selectedNode),
node_name: selectedNode.id,
node_text: selectedNode.text,
- bename: "",
+ bename: ""
};
});
}
@@ -221,12 +206,13 @@ export class Server extends React.Component {

render() {
const { nodes } = this.state;
- let serverPage =
+ let serverPage = (
<div className="ds-loading-spinner ds-center">
<p />
<h4>Loading server configuration ...</h4>
<Spinner className="ds-margin-top-lg" loading size="md" />
- </div>;
+ </div>
+ );

let server_element = "";
let disabled = "tree-view-container";
@@ -236,79 +222,85 @@ export class Server extends React.Component {

if (this.state.loaded) {
if (this.state.node_name == "settings-config" || this.state.node_name == "") {
- server_element =
+ server_element = (
<ServerSettings
serverId={this.props.serverId}
attrs={this.state.attrs}
enableTree={this.enableTree}
- />;
+ />
+ );
} else if (this.state.node_name == "tuning-config") {
- server_element =
+ server_element = (
<ServerTuning
serverId={this.props.serverId}
attrs={this.state.attrs}
enableTree={this.enableTree}
- />;
+ />
+ );
} else if (this.state.node_name == "sasl-config") {
- server_element =
- <ServerSASL
- serverId={this.props.serverId}
- enableTree={this.enableTree}
- />;
+ server_element = (
+ <ServerSASL serverId={this.props.serverId} enableTree={this.enableTree} />
+ );
} else if (this.state.node_name == "security-config") {
- server_element =
+ server_element = (
<Security
+ addNotification={this.props.addNotification}
serverId={this.props.serverId}
enableTree={this.enableTree}
- />;
+ />
+ );
} else if (this.state.node_name == "ldapi-config") {
- server_element =
+ server_element = (
<ServerLDAPI
serverId={this.props.serverId}
attrs={this.state.attrs}
enableTree={this.enableTree}
- />;
+ />
+ );
} else if (this.state.node_name == "access-log-config") {
- server_element =
+ server_element = (
<ServerAccessLog
serverId={this.props.serverId}
attrs={this.state.attrs}
enableTree={this.enableTree}
- />;
+ />
+ );
} else if (this.state.node_name == "audit-log-config") {
- server_element =
+ server_element = (
<ServerAuditLog
serverId={this.props.serverId}
attrs={this.state.attrs}
enableTree={this.enableTree}
- />;
+ />
+ );
} else if (this.state.node_name == "auditfail-log-config") {
- server_element =
+ server_element = (
<ServerAuditFailLog
serverId={this.props.serverId}
attrs={this.state.attrs}
enableTree={this.enableTree}
- />;
+ />
+ );
} else if (this.state.node_name == "error-log-config") {
- server_element =
+ server_element = (
<ServerErrorLog
serverId={this.props.serverId}
attrs={this.state.attrs}
enableTree={this.enableTree}
- />;
+ />
+ );
}

- serverPage =
+ serverPage = (
<div className="container-fluid">
- <NotificationController
- notifications={this.state.notifications}
- removeNotificationAction={this.removeNotification}
- />
<div className="ds-container">
<div>
<div className="ds-tree">
- <div className={disabled} id="server-tree"
- style={treeViewContainerStyles}>
+ <div
+ className={disabled}
+ id="server-tree"
+ style={treeViewContainerStyles}
+ >
<TreeView
nodes={nodes}
highlightOnHover
@@ -319,27 +311,24 @@ export class Server extends React.Component {
</div>
</div>
</div>
- <div className="ds-tree-content">
- {server_element}
- </div>
+ <div className="ds-tree-content">{server_element}</div>
</div>
- </div>;
+ </div>
+ );
}

- return (
- <div>
- {serverPage}
- </div>
- );
+ return <div>{serverPage}</div>;
}
}

// Property types and defaults

Server.propTypes = {
+ addNotification: PropTypes.func,
serverId: PropTypes.string
};

Server.defaultProps = {
+ addNotification: noop,
serverId: ""
};
diff --git a/src/cockpit/389-console/webpack.config.js b/src/cockpit/389-console/webpack.config.js
index 3389135..972bc5a 100644
--- a/src/cockpit/389-console/webpack.config.js
+++ b/src/cockpit/389-console/webpack.config.js
@@ -26,7 +26,6 @@ var info = {
files: [
"banner.html",
"css",
- "ds.js",
"fonts",
"images",
"index.html",
diff --git a/src/lib389/cli/dsctl b/src/lib389/cli/dsctl
index 97424b9..69be810 100755
--- a/src/lib389/cli/dsctl
+++ b/src/lib389/cli/dsctl
@@ -10,6 +10,7 @@
#
# PYTHON_ARGCOMPLETE_OK

+import json
import argparse, argcomplete
import logging
import sys
@@ -81,8 +82,11 @@ if __name__ == '__main__':

if args.list:
insts = get_instance_list()
- for inst in insts:
- print(inst)
+ if args.json:
+ print(json.dumps({"type": "result", "insts": insts}, indent=4))
+ else:
+ for inst in insts:
+ print(inst)
sys.exit(0)
elif args.remove_all is not False:
instance_remove_all(log, args)
diff --git a/src/lib389/lib389/cli_ctl/instance.py b/src/lib389/lib389/cli_ctl/instance.py
index bdeaa9f..d82c1a9 100644
--- a/src/lib389/lib389/cli_ctl/instance.py
+++ b/src/lib389/lib389/cli_ctl/instance.py
@@ -78,7 +78,7 @@ def instance_create(inst, log, args):

def instance_example(inst, log, args):
header = """
-;
+;
; This is a version 2 ds setup inf file.
; It is used by the python versions of setup-ds-*
; Most options map 1 to 1 to the original .inf file.

--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
_______________________________________________
389-commits mailing list -- 389-commits@lists.fedoraproject.org
To unsubscribe send an email to 389-commits-leave@lists.fedoraproject.org
Fedora Code of Conduct: https://docs.fedoraproject.org/en-US/project/code-of-conduct/
List Guidelines: https://fedoraproject.org/wiki/Mailing_list_guidelines
List Archives: https://lists.fedoraproject.org/archives/list/389-commits@lists.fedoraproject.org

No comments:

Post a Comment