Wednesday, April 1, 2020

[389-commits] [389-ds-base] branch 389-ds-base-1.4.1 updated: Issue 50994 - Fix latest UI bugs found by QE

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 950bbc9 Issue 50994 - Fix latest UI bugs found by QE
950bbc9 is described below

commit 950bbc971666a3963d7469a473cc8453883e9195
Author: Mark Reynolds <mreynolds@redhat.com>
AuthorDate: Mon Mar 30 14:04:29 2020 -0400

Issue 50994 - Fix latest UI bugs found by QE

Description:

This address many bugs, most of whioch is very small fixes:

- [Bug 1816563] Referential integrity scope values are not saved in cockpit
- [Bug 1816599] Initializing database from Ldif is broken in Cockpit
- [Bug 1816708] Removing objectclass does not ask for confirmation
- [Bug 1816712] Removing attribute does not ask for confirmation
- [Bug 1816928] Other tabs become unclickable Or unresponsive if you click on Replication tab under Monitoring tab (WORKED FOR ME)
- [Bug 1816956] Removing an attribute uniqueness does not ask for confirmation
- [Bug 1816958] Run Fixup Task for USN under Plugins tab either Cleanup Suffix Or Cleanup Backend option should be there not the both
- [Bug 1817062] Created attribute uniqueness is not visible after page refresh
- [Bug 1817098] Instance fails to start after creating attribute uniqueness because of a missing attribute
- [Bug 1817396] Various display problems on 'Server Settings'/'Security' Tab
- [Bug 1817415] The 'Security Settings' refresh button does not work
- [Bug 1817526] Cannot change Bind DN name in agreement
- [Bug 1817554] cockpit crashes when creating new sasl mapping
- [Bug 1817580] Reindex button is greyed out in Reindex Suffix
- [Bug 1817585] Changing the SASL mapping priority prevents to create mapping
- [Bug 1817983] Directory Manager Password can only be change when user click on Storage Scheme option
- [Bug 1818016] Directory Manager Password is changing before the change in password storage scheme
- [Bug 1818020] Confirm password field under Server setting's Directory manager tab not doing field check
- [Bug 1818027] Cockpit broken when saving new changelog directory
- [Bug 1818823] Can create replication manager without password and then it can't be deleted

relates: https://pagure.io/389-ds-base/issue/50994

Reviewed by: firstyear & spichugi(Thanks!!)

Updates

- Remove excessive/nested spinner toggling for many of the plugins
- Updated specfile for cockpit-389-ds to require 389-ds-base
- Fixed how attribute uniquness plugins are created and found, and
made it more robust to handle enabled and disabled plugins
---
rpm/389-ds-base.spec.in | 3 +-
src/cockpit/389-console/src/ds.jsx | 38 +----
.../389-console/src/lib/database/databaseModal.jsx | 6 +-
.../389-console/src/lib/database/suffix.jsx | 10 +-
.../389-console/src/lib/database/vlvIndexes.jsx | 4 +-
.../389-console/src/lib/monitor/replMonitor.jsx | 16 +--
.../src/lib/plugins/attributeUniqueness.jsx | 91 +++++++++---
.../389-console/src/lib/plugins/autoMembership.jsx | 3 -
src/cockpit/389-console/src/lib/plugins/dna.jsx | 6 -
.../src/lib/plugins/linkedAttributes.jsx | 3 -
.../389-console/src/lib/plugins/managedEntries.jsx | 3 -
.../src/lib/plugins/passthroughAuthentication.jsx | 3 -
.../389-console/src/lib/plugins/pluginTables.jsx | 2 +-
.../src/lib/plugins/referentialIntegrity.jsx | 12 +-
src/cockpit/389-console/src/lib/plugins/usn.jsx | 76 +++++-----
.../389-console/src/lib/replication/replAgmts.jsx | 2 +-
.../src/lib/replication/replChangelog.jsx | 2 +-
.../389-console/src/lib/replication/replModals.jsx | 2 +-
.../389-console/src/lib/replication/replSuffix.jsx | 4 +-
.../389-console/src/lib/schema/schemaTables.jsx | 4 +-
.../src/lib/security/certificateManagement.jsx | 4 +-
.../389-console/src/lib/security/ciphers.jsx | 21 +--
src/cockpit/389-console/src/lib/server/sasl.jsx | 8 +-
.../389-console/src/lib/server/settings.jsx | 19 +--
src/cockpit/389-console/src/lib/tools.jsx | 2 +-
src/cockpit/389-console/src/plugins.jsx | 160 ++++++++++++---------
src/cockpit/389-console/src/schema.jsx | 111 +++++++++++---
src/cockpit/389-console/src/security.jsx | 17 ++-
src/cockpit/389-console/src/server.jsx | 13 +-
src/cockpit/389-console/webpack.config.js | 6 +-
src/lib389/lib389/cli_conf/plugins/attruniq.py | 15 +-
src/lib389/lib389/cli_conf/plugins/usn.py | 6 +-
src/lib389/lib389/cli_conf/replication.py | 29 +++-
src/lib389/lib389/plugins.py | 8 +-
34 files changed, 436 insertions(+), 273 deletions(-)

diff --git a/rpm/389-ds-base.spec.in b/rpm/389-ds-base.spec.in
index 50ddc4a..ede7b79 100644
--- a/rpm/389-ds-base.spec.in
+++ b/rpm/389-ds-base.spec.in
@@ -315,7 +315,8 @@ This module contains tools and libraries for accessing, testing,
%package -n cockpit-389-ds
Summary: Cockpit UI Plugin for configuring and administering the 389 Directory Server
BuildArch: noarch
-Requires: cockpit >= 198
+Requires: cockpit
+Requires: 389-ds-base
Requires: python%{python3_pkgversion}
Requires: python%{python3_pkgversion}-lib389

diff --git a/src/cockpit/389-console/src/ds.jsx b/src/cockpit/389-console/src/ds.jsx
index f83ce55..b8be78e 100644
--- a/src/cockpit/389-console/src/ds.jsx
+++ b/src/cockpit/389-console/src/ds.jsx
@@ -61,7 +61,8 @@ const staticStates = {

export class DSInstance extends React.Component {
componentWillMount() {
- this.checkPackageAndLoad();
+ this.loadInstanceList();
+ this.updateProgress(25);
}

constructor(props) {
@@ -94,7 +95,6 @@ export class DSInstance extends React.Component {
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);
@@ -114,7 +114,7 @@ export class DSInstance extends React.Component {
progressValue: prevState.progressValue + value
}),
() => {
- if (this.state.progressValue >= 100) {
+ if (this.state.progressValue > 100) {
this.setState(prevState => ({
pageLoadingState: {
...prevState.pageLoadingState,
@@ -135,6 +135,7 @@ export class DSInstance extends React.Component {
.done(status_data => {
let status_json = JSON.parse(status_data);
if (status_json.running) {
+ this.updateProgress(25);
let cmd = [
"dsconf",
"-j",
@@ -148,17 +149,12 @@ export class DSInstance extends React.Component {
cockpit
.spawn(cmd, { superuser: true, err: "message" })
.done(_ => {
+ this.updateProgress(25);
this.setState(
{
serverId: serverId
},
() => {
- this.setState(prevState => ({
- pageLoadingState: {
- ...prevState.pageLoadingState,
- state: "success"
- }
- }));
this.loadBackups();
}
);
@@ -174,7 +170,6 @@ export class DSInstance extends React.Component {
}
);
}
- this.updateProgress(25);
})
.fail(err => {
let errMsg = JSON.parse(err);
@@ -193,7 +188,6 @@ export class DSInstance extends React.Component {
}
);
});
- this.updateProgress(25);
} else {
this.setState(
{
@@ -229,25 +223,6 @@ export class DSInstance extends React.Component {
});
}

- 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 => ({
@@ -262,6 +237,7 @@ export class DSInstance extends React.Component {
cockpit
.spawn(cmd, { superuser: true })
.done(data => {
+ this.updateProgress(25);
let myObject = JSON.parse(data);
this.setState({
instList: myObject.insts,
@@ -289,7 +265,6 @@ export class DSInstance extends React.Component {
});
}
}
- this.updateProgress(25);
})
.fail(_ => {
this.setState({
@@ -308,6 +283,7 @@ export class DSInstance extends React.Component {
const cmd = ["dsctl", "-j", this.state.serverId, "backups"];
log_cmd("loadBackupsDSInstance", "Load Backups", cmd);
cockpit.spawn(cmd, { superuser: true, err: "message" }).done(content => {
+ this.updateProgress(25);
const config = JSON.parse(content);
let rows = [];
for (let row of config.items) {
diff --git a/src/cockpit/389-console/src/lib/database/databaseModal.jsx b/src/cockpit/389-console/src/lib/database/databaseModal.jsx
index de0aed1..92fd79f 100644
--- a/src/cockpit/389-console/src/lib/database/databaseModal.jsx
+++ b/src/cockpit/389-console/src/lib/database/databaseModal.jsx
@@ -224,7 +224,7 @@ class ExportModal extends React.Component {
spinner =
<Row>
<div className="ds-margin-top-lg ds-modal-spinner">
- <Spinner loading inline size="lg" />Exporting database... <font size="1">(You can safely close this window)</font>
+ <Spinner loading inline size="lg" />Exporting database... <font size="2">(You can safely close this window)</font>
</div>
</Row>;
}
@@ -313,7 +313,7 @@ class ImportModal extends React.Component {
spinner =
<Row>
<div className="ds-margin-top-lg ds-modal-spinner">
- <Spinner loading inline size="lg" />Importing LDIF file... <font size="1">(You can safely close this window)</font>
+ <Spinner loading inline size="lg" />Importing LDIF file... <font size="2">(You can safely close this window)</font>
</div>
</Row>;
}
@@ -412,7 +412,7 @@ class ReindexModal extends React.Component {
<Form horizontal autoComplete="off">
<div className="ds-modal-spinner">
<Spinner loading inline size="lg" /> Indexing <b>{msg}</b> ...
- <p className="ds-margin-top-lg"><font size="1">(You can safely close this window)</font></p>
+ <p className="ds-margin-top-lg"><font size="2">(You can safely close this window)</font></p>
</div>
</Form>
</Modal.Body>
diff --git a/src/cockpit/389-console/src/lib/database/suffix.jsx b/src/cockpit/389-console/src/lib/database/suffix.jsx
index 5f3e19b..3558191 100644
--- a/src/cockpit/389-console/src/lib/database/suffix.jsx
+++ b/src/cockpit/389-console/src/lib/database/suffix.jsx
@@ -72,6 +72,7 @@ export class Suffix extends React.Component {
exportSpinner: false,
importSpinner: false,
showConfirmLDIFImport: false,
+ importLDIFName: "",
deleleLDIFName: "",
modalChecked: false,
modalSpinning: false,
@@ -196,15 +197,16 @@ export class Suffix extends React.Component {
});
}

- importLDIF (ldif) {
+ importLDIF () {
// Do import
let import_cmd = [
"dsconf", "-j", "ldapi://%2fvar%2frun%2fslapd-" + this.props.serverId + ".socket",
- "backend", "import", this.props.suffix, ldif, "--encrypted"
+ "backend", "import", this.props.suffix, this.state.importLDIFName, "--encrypted"
];

this.setState({
importSpinner: true,
+ showConfirmLDIFImport: false,
});

log_cmd("doImport", "Do online import", import_cmd);
@@ -375,6 +377,7 @@ export class Suffix extends React.Component {
);
this.setState({
showReindexModal: false,
+ showReindexConfirm: false,
});
})
.fail(err => {
@@ -385,6 +388,7 @@ export class Suffix extends React.Component {
);
this.setState({
showReindexModal: false,
+ showReindexConfirm: false,
});
});
}
@@ -947,7 +951,7 @@ export class Suffix extends React.Component {
<DoubleConfirmModal
showModal={this.state.showReindexConfirm}
closeHandler={this.closeReindexConfirm}
- handleChange={this.handlChange}
+ handleChange={this.handleChange}
actionHandler={this.doReindex}
spinning={this.state.modalSpinning}
item={this.props.suffix}
diff --git a/src/cockpit/389-console/src/lib/database/vlvIndexes.jsx b/src/cockpit/389-console/src/lib/database/vlvIndexes.jsx
index 582bfd2..4ffe0f8 100644
--- a/src/cockpit/389-console/src/lib/database/vlvIndexes.jsx
+++ b/src/cockpit/389-console/src/lib/database/vlvIndexes.jsx
@@ -525,9 +525,9 @@ export class VLVIndexes extends React.Component {
vlvItem.sorts.map(sort => {
let indexState;
if (sort.attrs.vlvenabled[0] == "0") {
- indexState = <font size="1" color="#d01c8b"><b>Disabled</b></font>;
+ indexState = <font size="2" color="#d01c8b"><b>Disabled</b></font>;
} else {
- indexState = <font size="1" color="#4dac26"><b>Uses: </b>{sort.attrs.vlvuses[0]}</font>;
+ indexState = <font size="2" color="#4dac26"><b>Uses: </b>{sort.attrs.vlvuses[0]}</font>;
}
return (<p key={sort.dn + sort.attrs.vlvsort[0]}><label className="ds-divider-lrg">Sort</label>{sort.attrs.vlvsort[0]} ({indexState})</p>);
})
diff --git a/src/cockpit/389-console/src/lib/monitor/replMonitor.jsx b/src/cockpit/389-console/src/lib/monitor/replMonitor.jsx
index 482834b..f70c973 100644
--- a/src/cockpit/389-console/src/lib/monitor/replMonitor.jsx
+++ b/src/cockpit/389-console/src/lib/monitor/replMonitor.jsx
@@ -1348,8 +1348,8 @@ export class ReplMonitor extends React.Component {
</TabPane>
</TabContent>
</div>;
- let cleanNavTitle = 'CleanAllRUV Tasks <font size="1">(' + cleanTasks.length + ')</font>';
- let abortNavTitle = 'Abort CleanAllRUV Tasks <font size="1">(' + abortTasks.length + ')</font>';
+ let cleanNavTitle = 'CleanAllRUV Tasks <font size="2">(' + cleanTasks.length + ')</font>';
+ let abortNavTitle = 'Abort CleanAllRUV Tasks <font size="2">(' + abortTasks.length + ')</font>';
let taskContent =
<div>
<Nav bsClass="nav nav-tabs nav-tabs-pf">
@@ -1380,8 +1380,8 @@ export class ReplMonitor extends React.Component {
</TabContent>
</div>;

- let conflictNavTitle = 'Conflict Entries <font size="1">(' + conflictEntries.length + ')</font>';
- let glueNavTitle = 'Glue Entries <font size="1">(' + glueEntries.length + ')</font>';
+ let conflictNavTitle = 'Conflict Entries <font size="2">(' + conflictEntries.length + ')</font>';
+ let glueNavTitle = 'Glue Entries <font size="2">(' + glueEntries.length + ')</font>';
let conflictContent =
<div>
<Nav bsClass="nav nav-tabs nav-tabs-pf">
@@ -1431,10 +1431,10 @@ export class ReplMonitor extends React.Component {
</div>;

let fullReportTitle = 'Sync Report';
- let replAgmtNavTitle = 'Agreements <font size="1">(' + replAgmts.length + ')</font>';
- let winsyncNavTitle = 'Winsync <font size="1">(' + replWinsyncAgmts.length + ')</font>';
- let tasksNavTitle = 'Tasks <font size="1">(' + (cleanTasks.length + abortTasks.length) + ')</font>';
- let conflictsNavTitle = 'Conflicts <font size="1">(' + (conflictEntries.length + glueEntries.length) + ')</font>';
+ let replAgmtNavTitle = 'Agreements <font size="2">(' + replAgmts.length + ')</font>';
+ let winsyncNavTitle = 'Winsync <font size="2">(' + replWinsyncAgmts.length + ')</font>';
+ let tasksNavTitle = 'Tasks <font size="2">(' + (cleanTasks.length + abortTasks.length) + ')</font>';
+ let conflictsNavTitle = 'Conflicts <font size="2">(' + (conflictEntries.length + glueEntries.length) + ')</font>';

return (
<div id="monitor-suffix-page" className="ds-tab-table">
diff --git a/src/cockpit/389-console/src/lib/plugins/attributeUniqueness.jsx b/src/cockpit/389-console/src/lib/plugins/attributeUniqueness.jsx
index e31532c..59e7525 100644
--- a/src/cockpit/389-console/src/lib/plugins/attributeUniqueness.jsx
+++ b/src/cockpit/389-console/src/lib/plugins/attributeUniqueness.jsx
@@ -16,6 +16,7 @@ import {
} from "patternfly-react";
import { Typeahead } from "react-bootstrap-typeahead";
import { AttrUniqConfigTable } from "./pluginTables.jsx";
+import { DoubleConfirmModal } from "../notifications.jsx";
import PluginBasicConfig from "./pluginBasicConfig.jsx";
import PropTypes from "prop-types";
import { log_cmd } from "../tools.jsx";
@@ -37,6 +38,8 @@ class AttributeUniqueness extends React.Component {
configRows: [],
attributes: [],
objectClasses: [],
+ modalChecked: false,
+ modalSpinning: false,

configName: "",
configEnabled: false,
@@ -48,12 +51,13 @@ class AttributeUniqueness extends React.Component {

newEntry: false,
showConfigModal: false,
- showConfirmDeleteConfig: false
+ showConfirmDelete: false
};

this.handleSwitchChange = this.handleSwitchChange.bind(this);
this.handleCheckboxChange = this.handleCheckboxChange.bind(this);
this.handleFieldChange = this.handleFieldChange.bind(this);
+ this.handleTypeaheadChange = this.handleTypeaheadChange.bind(this);
this.loadConfigs = this.loadConfigs.bind(this);
this.showEditConfigModal = this.showEditConfigModal.bind(this);
this.showAddConfigModal = this.showAddConfigModal.bind(this);
@@ -62,6 +66,8 @@ class AttributeUniqueness extends React.Component {
this.closeModal = this.closeModal.bind(this);
this.openModal = this.openModal.bind(this);
this.cmdOperation = this.cmdOperation.bind(this);
+ this.closeConfirmDelete = this.closeConfirmDelete.bind(this);
+ this.showConfirmDelete = this.showConfirmDelete.bind(this);
this.deleteConfig = this.deleteConfig.bind(this);
this.addConfig = this.addConfig.bind(this);
this.editConfig = this.editConfig.bind(this);
@@ -85,6 +91,18 @@ class AttributeUniqueness extends React.Component {
});
}

+ handleTypeaheadChange(values) {
+ // When typaheads allow new values, an object is returned
+ // instead of string. Grab the "label" in this case
+ let new_values = [];
+ for (let val of values) {
+ new_values.push(val.label);
+ }
+ this.setState({
+ subtrees: new_values
+ });
+ }
+
loadConfigs() {
this.setState({
firstLoad: false
@@ -98,23 +116,20 @@ class AttributeUniqueness extends React.Component {
"attr-uniq",
"list"
];
- this.props.toggleLoadingHandler();
log_cmd("loadConfigs", "Get Attribute Uniqueness Plugin configs", cmd);
cockpit
.spawn(cmd, { superuser: true, err: "message" })
.done(content => {
let myObject = JSON.parse(content);
this.setState({
- configRows: myObject.items.map(item => JSON.parse(item).attrs)
+ configRows: myObject.items.map(item => item.attrs)
});
- this.props.toggleLoadingHandler();
})
.fail(err => {
if (err != 0) {
let errMsg = JSON.parse(err);
console.log("loadConfigs failed", errMsg.desc);
}
- this.props.toggleLoadingHandler();
});
}

@@ -153,7 +168,6 @@ class AttributeUniqueness extends React.Component {
name
];

- this.props.toggleLoadingHandler();
log_cmd("openModal", "Fetch the Attribute Uniqueness Plugin config entry", cmd);
cockpit
.spawn(cmd, {
@@ -200,7 +214,6 @@ class AttributeUniqueness extends React.Component {
}
this.setState({ subtrees: configSubtreesList });
}
- this.props.toggleLoadingHandler();
})
.fail(_ => {
this.setState({
@@ -213,7 +226,6 @@ class AttributeUniqueness extends React.Component {
topEntryOc: [],
subtreeEnriesOc: []
});
- this.props.toggleLoadingHandler();
});
}
}
@@ -247,6 +259,15 @@ class AttributeUniqueness extends React.Component {
acrossAllSubtrees ? "on" : "off"
];

+ if (subtrees.length == 0 && subtreeEnriesOc.length == 0) {
+ // There me a subtree or entry OC sets
+ this.props.addNotification(
+ "error",
+ `There must be at least one Subtree or Subtree Entries OC set`
+ );
+ return;
+ }
+
// Delete attributes if the user set an empty value to the field
if (!(action == "add" && attrNames.length == 0)) {
cmd = [...cmd, "--attr-name"];
@@ -320,13 +341,29 @@ class AttributeUniqueness extends React.Component {
`Error during the config entry ${action} operation - ${errMsg.desc}`
);
this.loadConfigs();
- this.closeModal();
this.props.toggleLoadingHandler();
});
}

- deleteConfig(rowData) {
- let configName = rowData.cn[0];
+ showConfirmDelete (name) {
+ this.setState({
+ showConfirmDelete: true,
+ modalChecked: false,
+ modalSpinning: false,
+ deleteName: name
+ });
+ }
+
+ closeConfirmDelete () {
+ this.setState({
+ showConfirmDelete: false,
+ modalChecked: false,
+ modalSpinning: false,
+ deleteName: ""
+ });
+ }
+
+ deleteConfig() {
let cmd = [
"dsconf",
"-j",
@@ -334,10 +371,13 @@ class AttributeUniqueness extends React.Component {
"plugin",
"attr-uniq",
"delete",
- configName
+ this.state.deleteName
];

- this.props.toggleLoadingHandler();
+ this.setState({
+ modalSpinning: true
+ });
+
log_cmd("deleteConfig", "Delete the Attribute Uniqueness Plugin config entry", cmd);
cockpit
.spawn(cmd, {
@@ -348,11 +388,11 @@ class AttributeUniqueness extends React.Component {
console.info("deleteConfig", "Result", content);
this.props.addNotification(
"success",
- `Config entry ${configName} was successfully deleted`
+ `Config entry ${this.state.deleteName} was successfully deleted`
);
this.loadConfigs();
this.closeModal();
- this.props.toggleLoadingHandler();
+ this.closeConfirmDelete();
})
.fail(err => {
let errMsg = JSON.parse(err);
@@ -361,8 +401,8 @@ class AttributeUniqueness extends React.Component {
`Error during the config entry removal operation - ${errMsg.desc}`
);
this.loadConfigs();
+ this.closeConfirmDelete();
this.closeModal();
- this.props.toggleLoadingHandler();
});
}

@@ -528,9 +568,7 @@ class AttributeUniqueness extends React.Component {
allowNew
multiple
onChange={values => {
- this.setState({
- subtrees: values
- });
+ this.handleTypeaheadChange(values);
}}
selected={subtrees}
options={[""]}
@@ -672,7 +710,7 @@ class AttributeUniqueness extends React.Component {
<AttrUniqConfigTable
rows={this.state.configRows}
editConfig={this.showEditConfigModal}
- deleteConfig={this.deleteConfig}
+ deleteConfig={this.showConfirmDelete}
/>
<Button
className="ds-margin-top"
@@ -684,6 +722,19 @@ class AttributeUniqueness extends React.Component {
</Col>
</Row>
</PluginBasicConfig>
+ <DoubleConfirmModal
+ showModal={this.state.showConfirmDelete}
+ closeHandler={this.closeConfirmDelete}
+ handleChange={this.handleCheckboxChange}
+ actionHandler={this.deleteConfig}
+ spinning={this.state.modalSpinning}
+ item={this.state.deleteName}
+ checked={this.state.modalChecked}
+ mTitle="Delete Attribute Uniqueness Configuration"
+ mMsg="Are you sure you want to delete this configuration?"
+ mSpinningMsg="Deleting attribute uniqueness configuration..."
+ mBtnName="Delete Configuration"
+ />
</div>
);
}
diff --git a/src/cockpit/389-console/src/lib/plugins/autoMembership.jsx b/src/cockpit/389-console/src/lib/plugins/autoMembership.jsx
index ab0661c..ff4d9d4 100644
--- a/src/cockpit/389-console/src/lib/plugins/autoMembership.jsx
+++ b/src/cockpit/389-console/src/lib/plugins/autoMembership.jsx
@@ -99,7 +99,6 @@ class AutoMembership extends React.Component {
"list",
"definitions"
];
- this.props.toggleLoadingHandler();
log_cmd("loadDefinitions", "Get Auto Membership Plugin definitions", cmd);
cockpit
.spawn(cmd, { superuser: true, err: "message" })
@@ -108,14 +107,12 @@ class AutoMembership extends React.Component {
this.setState({
definitionRows: myObject.items.map(item => JSON.parse(item).attrs)
});
- this.props.toggleLoadingHandler();
})
.fail(err => {
let errMsg = JSON.parse(err);
if (err != 0) {
console.log("loadDefinitions failed", errMsg.desc);
}
- this.props.toggleLoadingHandler();
});
}

diff --git a/src/cockpit/389-console/src/lib/plugins/dna.jsx b/src/cockpit/389-console/src/lib/plugins/dna.jsx
index f4b1e05..f083937 100644
--- a/src/cockpit/389-console/src/lib/plugins/dna.jsx
+++ b/src/cockpit/389-console/src/lib/plugins/dna.jsx
@@ -138,7 +138,6 @@ class DNA extends React.Component {
"list",
"configs"
];
- this.props.toggleLoadingHandler();
log_cmd("loadConfigs", "Get DNA Plugin configs", cmd);
cockpit
.spawn(cmd, { superuser: true, err: "message" })
@@ -147,14 +146,12 @@ class DNA extends React.Component {
this.setState({
configRows: myObject.items.map(item => JSON.parse(item).attrs)
});
- this.props.toggleLoadingHandler();
})
.fail(err => {
let errMsg = JSON.parse(err);
if (err != 0) {
console.log("loadConfigs failed", errMsg.desc);
}
- this.props.toggleLoadingHandler();
});
}

@@ -169,7 +166,6 @@ class DNA extends React.Component {
"shared-configs",
basedn
];
- this.props.toggleLoadingHandler();
log_cmd("loadSharedConfigs", "Get DNA Plugin shared configs", cmd);
cockpit
.spawn(cmd, { superuser: true, err: "message" })
@@ -178,14 +174,12 @@ class DNA extends React.Component {
this.setState({
sharedConfigRows: myObject.items.map(item => JSON.parse(item).attrs)
});
- this.props.toggleLoadingHandler();
})
.fail(err => {
let errMsg = JSON.parse(err);
if (err != 0) {
console.log("loadSharedConfigs failed", errMsg.desc);
}
- this.props.toggleLoadingHandler();
});
}

diff --git a/src/cockpit/389-console/src/lib/plugins/linkedAttributes.jsx b/src/cockpit/389-console/src/lib/plugins/linkedAttributes.jsx
index accd694..88bb399 100644
--- a/src/cockpit/389-console/src/lib/plugins/linkedAttributes.jsx
+++ b/src/cockpit/389-console/src/lib/plugins/linkedAttributes.jsx
@@ -77,7 +77,6 @@ class LinkedAttributes extends React.Component {
"linked-attr",
"list"
];
- this.props.toggleLoadingHandler();
log_cmd("loadConfigs", "Get Linked Attributes Plugin configs", cmd);
cockpit
.spawn(cmd, { superuser: true, err: "message" })
@@ -86,14 +85,12 @@ class LinkedAttributes extends React.Component {
this.setState({
configRows: myObject.items.map(item => JSON.parse(item).attrs)
});
- this.props.toggleLoadingHandler();
})
.fail(err => {
let errMsg = JSON.parse(err);
if (err != 0) {
console.log("loadConfigs failed", errMsg.desc);
}
- this.props.toggleLoadingHandler();
});
}

diff --git a/src/cockpit/389-console/src/lib/plugins/managedEntries.jsx b/src/cockpit/389-console/src/lib/plugins/managedEntries.jsx
index 679e919..7afdd2c 100644
--- a/src/cockpit/389-console/src/lib/plugins/managedEntries.jsx
+++ b/src/cockpit/389-console/src/lib/plugins/managedEntries.jsx
@@ -93,7 +93,6 @@ class ManagedEntries extends React.Component {
"list",
"configs"
];
- this.props.toggleLoadingHandler();
log_cmd("loadConfigs", "Get Managed Entries Plugin configs", cmd);
cockpit
.spawn(cmd, { superuser: true, err: "message" })
@@ -102,14 +101,12 @@ class ManagedEntries extends React.Component {
this.setState({
configRows: myObject.items.map(item => JSON.parse(item).attrs)
});
- this.props.toggleLoadingHandler();
})
.fail(err => {
let errMsg = JSON.parse(err);
if (err != 0) {
console.log("loadConfigs failed", errMsg.desc);
}
- this.props.toggleLoadingHandler();
});
}

diff --git a/src/cockpit/389-console/src/lib/plugins/passthroughAuthentication.jsx b/src/cockpit/389-console/src/lib/plugins/passthroughAuthentication.jsx
index 6b2d067..a7f3b98 100644
--- a/src/cockpit/389-console/src/lib/plugins/passthroughAuthentication.jsx
+++ b/src/cockpit/389-console/src/lib/plugins/passthroughAuthentication.jsx
@@ -118,7 +118,6 @@ class PassthroughAuthentication extends React.Component {
"list",
"pam-configs"
];
- this.props.toggleLoadingHandler();
log_cmd("loadPAMConfigs", "Get PAM Passthough Authentication Plugin pamConfigs", cmd);
cockpit
.spawn(cmd, { superuser: true, err: "message" })
@@ -127,14 +126,12 @@ class PassthroughAuthentication extends React.Component {
this.setState({
pamConfigRows: myObject.items.map(item => JSON.parse(item).attrs)
});
- this.props.toggleLoadingHandler();
})
.fail(err => {
let errMsg = JSON.parse(err);
if (err != 0) {
console.log("loadPAMConfigs failed", errMsg.desc);
}
- this.props.toggleLoadingHandler();
});
}

diff --git a/src/cockpit/389-console/src/lib/plugins/pluginTables.jsx b/src/cockpit/389-console/src/lib/plugins/pluginTables.jsx
index 49abfa1..ce9de8c 100644
--- a/src/cockpit/389-console/src/lib/plugins/pluginTables.jsx
+++ b/src/cockpit/389-console/src/lib/plugins/pluginTables.jsx
@@ -258,7 +258,7 @@ class AttrUniqConfigTable extends React.Component {
<MenuItem
eventKey="2"
onClick={() => {
- this.props.deleteConfig(rowData);
+ this.props.deleteConfig(rowData.cn[0]);
}}
>
Delete Config
diff --git a/src/cockpit/389-console/src/lib/plugins/referentialIntegrity.jsx b/src/cockpit/389-console/src/lib/plugins/referentialIntegrity.jsx
index 7419b84..e65cbcc 100644
--- a/src/cockpit/389-console/src/lib/plugins/referentialIntegrity.jsx
+++ b/src/cockpit/389-console/src/lib/plugins/referentialIntegrity.jsx
@@ -311,17 +311,17 @@ class ReferentialIntegrity extends React.Component {
? ""
: pluginRow["referint-update-delay"][0],
entryScope:
- pluginRow["nsslapd-pluginEntryScope"] === undefined
+ pluginRow["nsslapd-pluginentryscope"] === undefined
? ""
- : pluginRow["nsslapd-pluginEntryScope"][0],
+ : pluginRow["nsslapd-pluginentryscope"][0],
excludeEntryScope:
- pluginRow["nsslapd-pluginExcludeEntryScope"] === undefined
+ pluginRow["nsslapd-pluginexcludeentryscope"] === undefined
? ""
- : pluginRow["nsslapd-pluginExcludeEntryScope"][0],
+ : pluginRow["nsslapd-pluginexcludeentryscope"][0],
containerScope:
- pluginRow["nsslapd-pluginContainerScope"] === undefined
+ pluginRow["nsslapd-plugincontainerscope"] === undefined
? ""
- : pluginRow["nsslapd-pluginContainerScope"][0],
+ : pluginRow["nsslapd-plugincontainerscope"][0],
referintConfigEntry:
pluginRow["nsslapd-pluginConfigArea"] === undefined
? ""
diff --git a/src/cockpit/389-console/src/lib/plugins/usn.jsx b/src/cockpit/389-console/src/lib/plugins/usn.jsx
index a1080c6..6a3acad 100644
--- a/src/cockpit/389-console/src/lib/plugins/usn.jsx
+++ b/src/cockpit/389-console/src/lib/plugins/usn.jsx
@@ -22,6 +22,7 @@ class USN extends React.Component {
componentWillMount() {
if (this.props.wasActiveList.includes(5)) {
if (this.state.firstLoad) {
+ this.loadSuffixList();
this.updateSwitch();
}
}
@@ -35,6 +36,7 @@ class USN extends React.Component {
this.updateSwitch = this.updateSwitch.bind(this);
this.handleSwitchChange = this.handleSwitchChange.bind(this);
this.handleFieldChange = this.handleFieldChange.bind(this);
+ this.loadSuffixList = this.loadSuffixList.bind(this);

this.state = {
firstLoad: true,
@@ -42,11 +44,28 @@ class USN extends React.Component {
disableSwitch: false,
cleanupModalShow: false,
cleanupSuffix: "",
- cleanupBackend: "",
- cleanupMaxUSN: ""
+ cleanupMaxUSN: "",
+ suffixList: [],
};
}

+ loadSuffixList () {
+ const cmd = [
+ "dsconf", "-j", "ldapi://%2fvar%2frun%2fslapd-" + this.props.serverId + ".socket",
+ "backend", "suffix", "list", "--suffix"
+ ];
+ log_cmd("loadSuffixList", "Get a list of all the suffixes", cmd);
+ cockpit
+ .spawn(cmd, { superuser: true, err: "message" })
+ .done(content => {
+ const suffixList = JSON.parse(content);
+ this.setState({
+ suffixList: suffixList.items,
+ cleanupSuffix: suffixList.items[0]
+ });
+ });
+ }
+
handleFieldChange(e) {
this.setState({
[e.target.id]: e.target.value
@@ -135,15 +154,14 @@ class USN extends React.Component {
toggleCleanupModal() {
this.setState(prevState => ({
cleanupModalShow: !prevState.cleanupModalShow,
- cleanupSuffix: "",
- cleanupBackend: "",
+ cleanupSuffix: prevState.suffixList[0],
cleanupMaxUSN: ""
}));
}

runCleanup() {
- if (!this.state.cleanupSuffix && !this.state.cleanupBackend) {
- this.props.addNotification("warning", "Suffix or backend name is required.");
+ if (!this.state.cleanupSuffix) {
+ this.props.addNotification("warning", "Suffix is required.");
} else {
let cmd = [
"dsconf",
@@ -157,9 +175,6 @@ class USN extends React.Component {
if (this.state.cleanupSuffix) {
cmd = [...cmd, "--suffix", this.state.cleanupSuffix];
}
- if (this.state.cleanupBackend) {
- cmd = [...cmd, "--backend", this.state.cleanupBackend];
- }
if (this.state.cleanupMaxUSN) {
cmd = [...cmd, "--max-usn", this.state.cleanupMaxUSN];
}
@@ -201,10 +216,14 @@ class USN extends React.Component {
disableSwitch,
cleanupModalShow,
cleanupSuffix,
- cleanupBackend,
- cleanupMaxUSN
+ cleanupMaxUSN,
+ suffixList
} = this.state;

+ let suffixes = suffixList.map((name) =>
+ <option key={name} value={name}>{name}</option>
+ );
+
return (
<div>
<Modal show={cleanupModalShow} onHide={this.toggleCleanupModal}>
@@ -225,42 +244,27 @@ class USN extends React.Component {
<Col sm={12}>
<Form horizontal>
<FormGroup controlId="cleanupSuffix" key="cleanupSuffix">
- <Col sm={3}>
- <ControlLabel title="Gives the suffix or subtree in the Directory Server to run the cleanup operation against">
+ <Col sm={4}>
+ <ControlLabel title="Gives the suffix in the Directory Server to run the cleanup operation against">
Cleanup Suffix
</ControlLabel>
</Col>
- <Col sm={9}>
- <FormControl
- type="text"
- value={cleanupSuffix}
- onChange={this.handleFieldChange}
- />
- </Col>
- </FormGroup>
- <FormGroup controlId="cleanupBackend" key="cleanupBackend">
- <Col sm={3}>
- <ControlLabel title="Gives the Directory Server instance back end, or database, to run the cleanup operation against">
- Cleanup Backend
- </ControlLabel>
- </Col>
- <Col sm={9}>
- <FormControl
- type="text"
- value={cleanupBackend}
- onChange={this.handleFieldChange}
- />
+ <Col sm={8}>
+ <select id="cleanupSuffix" onChange={this.handleFieldChange} defaultValue={cleanupSuffix}>
+ {suffixes}
+ </select>
</Col>
</FormGroup>
<FormGroup controlId="cleanupMaxUSN" key="cleanupMaxUSN">
- <Col sm={3}>
+ <Col sm={4}>
<ControlLabel title="Gives the highest USN value to delete when removing tombstone entries. All tombstone entries up to and including that number are deleted. Tombstone entries with higher USN values (that means more recent entries) are not deleted">
Cleanup Max USN
</ControlLabel>
</Col>
- <Col sm={9}>
+ <Col sm={8}>
<FormControl
- type="text"
+ type="number"
+ min="1"
value={cleanupMaxUSN}
onChange={this.handleFieldChange}
/>
diff --git a/src/cockpit/389-console/src/lib/replication/replAgmts.jsx b/src/cockpit/389-console/src/lib/replication/replAgmts.jsx
index e3c4781..ec1beef 100644
--- a/src/cockpit/389-console/src/lib/replication/replAgmts.jsx
+++ b/src/cockpit/389-console/src/lib/replication/replAgmts.jsx
@@ -682,7 +682,7 @@ export class ReplAgmts extends React.Component {
cmd.push('--bind-passwd=' + this.state.agmtBindPW);
}
if (this.state.agmtBindDN != this.state._agmtBindDN) {
- cmd.push('--bind-passwd=' + this.state.agmtBindDN);
+ cmd.push('--bind-dn=' + this.state.agmtBindDN);
}
if (this.state.agmtFracAttrs != this.state._agmtFracAttrs) {
cmd.push('--frac-list=' + this.state.agmtFracAttrs.join(' '));
diff --git a/src/cockpit/389-console/src/lib/replication/replChangelog.jsx b/src/cockpit/389-console/src/lib/replication/replChangelog.jsx
index 1386393..b1c318e 100644
--- a/src/cockpit/389-console/src/lib/replication/replChangelog.jsx
+++ b/src/cockpit/389-console/src/lib/replication/replChangelog.jsx
@@ -151,7 +151,7 @@ export class Changelog extends React.Component {
});
return;
}
- cmd.push("--cl-dir =" + this.state.clDir);
+ cmd.push("--cl-dir=" + this.state.clDir);
}
if (this.state.clMaxEntries != this.state._clMaxEntries) {
cmd.push("--max-entries=" + this.state.clMaxEntries);
diff --git a/src/cockpit/389-console/src/lib/replication/replModals.jsx b/src/cockpit/389-console/src/lib/replication/replModals.jsx
index 0ea6f47..4c4fe88 100644
--- a/src/cockpit/389-console/src/lib/replication/replModals.jsx
+++ b/src/cockpit/389-console/src/lib/replication/replModals.jsx
@@ -1402,7 +1402,7 @@ export class ExportModal extends React.Component {
spinner =
<Row>
<div className="ds-margin-top ds-modal-spinner">
- <Spinner loading inline size="lg" />Exporting database... <font size="1">(You can safely close this window)</font>
+ <Spinner loading inline size="lg" />Exporting database... <font size="2">(You can safely close this window)</font>
</div>
</Row>;
}
diff --git a/src/cockpit/389-console/src/lib/replication/replSuffix.jsx b/src/cockpit/389-console/src/lib/replication/replSuffix.jsx
index a83ca37..9cbd729 100644
--- a/src/cockpit/389-console/src/lib/replication/replSuffix.jsx
+++ b/src/cockpit/389-console/src/lib/replication/replSuffix.jsx
@@ -280,8 +280,8 @@ export class ReplSuffix extends React.Component {
if (this.props.disabled) {
suffixClass = "ds-margin-top-xlg ds-disabled";
}
- let replAgmtNavTitle = 'Replication Agreements <font size="1">(' + this.props.agmtRows.length + ')</font>';
- let winsyncNavTitle = 'Winsync Agreements <font size="1">(' + this.props.winsyncRows.length + ')</font>';
+ let replAgmtNavTitle = 'Replication Agreements <font size="2">(' + this.props.agmtRows.length + ')</font>';
+ let winsyncNavTitle = 'Winsync Agreements <font size="2">(' + this.props.winsyncRows.length + ')</font>';

let enabledContent =
<div className={suffixClass}>
diff --git a/src/cockpit/389-console/src/lib/schema/schemaTables.jsx b/src/cockpit/389-console/src/lib/schema/schemaTables.jsx
index 296845c..813ed2f 100644
--- a/src/cockpit/389-console/src/lib/schema/schemaTables.jsx
+++ b/src/cockpit/389-console/src/lib/schema/schemaTables.jsx
@@ -162,7 +162,7 @@ class ObjectClassesTable extends React.Component {
eventKey="2"
className="ds-schema-dropdown"
onClick={() => {
- this.props.deleteHandler(rowData);
+ this.props.deleteHandler(rowData.name[0]);
}}
>
Delete ObjectClass
@@ -374,7 +374,7 @@ class AttributesTable extends React.Component {
eventKey="2"
className="ds-schema-dropdown"
onClick={() => {
- this.props.deleteHandler(rowData);
+ this.props.deleteHandler(rowData.name[0]);
}}
>
Delete Attribute
diff --git a/src/cockpit/389-console/src/lib/security/certificateManagement.jsx b/src/cockpit/389-console/src/lib/security/certificateManagement.jsx
index 5bf091c..1635372 100644
--- a/src/cockpit/389-console/src/lib/security/certificateManagement.jsx
+++ b/src/cockpit/389-console/src/lib/security/certificateManagement.jsx
@@ -492,8 +492,8 @@ export class CertificateManagement extends React.Component {
}

render () {
- let CATitle = 'Trusted Certificate Authorites <font size="1">(' + this.state.CACerts.length + ')</font>';
- let ServerTitle = 'TLS Certificates <font size="1">(' + this.state.ServerCerts.length + ')</font>';
+ let CATitle = 'Trusted Certificate Authorites <font size="2">(' + this.state.CACerts.length + ')</font>';
+ let ServerTitle = 'TLS Certificates <font size="2">(' + this.state.ServerCerts.length + ')</font>';

let certificatePage = '';

diff --git a/src/cockpit/389-console/src/lib/security/ciphers.jsx b/src/cockpit/389-console/src/lib/security/ciphers.jsx
index d8af1d6..a4199eb 100644
--- a/src/cockpit/389-console/src/lib/security/ciphers.jsx
+++ b/src/cockpit/389-console/src/lib/security/ciphers.jsx
@@ -184,20 +184,21 @@ export class Ciphers extends React.Component {
<option key={name}>{name}</option>
);

+ let eCiphers = '<h4>Enabled Ciphers <font size="2">(' + enabledList.length + ')</font></h4>';
+ let sCiphers = '<h4>Other Available Ciphers <font size="2">(' + supportedList.length + ')</font><h4>';
+
if (this.state.saving) {
cipherPage =
- <div className="ds-loading-spinner ds-center ds-margin-top-lg">
+ <div className="ds-center ds-margin-top-lg">
<h4>Saving cipher preferences ...</h4>
<Spinner loading size="md" />
</div>;
} else {
cipherPage =
- <div className="container-fluid">
+ <div>
<div className="ds-container">
<div className='ds-inline'>
- <div>
- <h4>Enabled Ciphers</h4>
- </div>
+ <div dangerouslySetInnerHTML={{__html: eCiphers}} />
<div>
<select
className="ds-cipher-width"
@@ -211,7 +212,7 @@ export class Ciphers extends React.Component {
<div className="ds-divider-lrg" />
<div className='ds-inline'>
<div>
- <h4>Other Available Ciphers</h4>
+ <div dangerouslySetInnerHTML={{__html: sCiphers}} />
</div>
<div>
<select className="ds-cipher-width" size="16">
@@ -222,7 +223,7 @@ export class Ciphers extends React.Component {
</div>
<hr />
<Row>
- <Col componentClass={ControlLabel} sm={2}>
+ <Col componentClass={ControlLabel} sm={3}>
Cipher Suite
</Col>
<Col sm={9}>
@@ -238,7 +239,7 @@ export class Ciphers extends React.Component {
</Col>
</Row>
<Row className="ds-margin-top">
- <Col componentClass={ControlLabel} sm={2}>
+ <Col componentClass={ControlLabel} sm={3}>
Allow Specific Ciphers
</Col>
<Col sm={9}>
@@ -256,7 +257,7 @@ export class Ciphers extends React.Component {
</Col>
</Row>
<Row className="ds-margin-top">
- <Col componentClass={ControlLabel} sm={2}>
+ <Col componentClass={ControlLabel} sm={3}>
Deny Specific Ciphers
</Col>
<Col sm={9}>
@@ -286,7 +287,7 @@ export class Ciphers extends React.Component {
}

return (
- <div>
+ <div className="container-fluid">
{cipherPage}
</div>
);
diff --git a/src/cockpit/389-console/src/lib/server/sasl.jsx b/src/cockpit/389-console/src/lib/server/sasl.jsx
index e58a660..28cc330 100644
--- a/src/cockpit/389-console/src/lib/server/sasl.jsx
+++ b/src/cockpit/389-console/src/lib/server/sasl.jsx
@@ -123,6 +123,8 @@ export class ServerSASL extends React.Component {
// Check if a setting was changed, if so enable the save button
if (attr == 'mappingFallback' && this.state._mappingFallback != value) {
disableSaveBtn = false;
+ } else if (attr == 'saslPriority' && this.state._saslPriority != value) {
+ disableSaveBtn = false;
} else if (attr == 'maxBufSize' && this.state._maxBufSize != value) {
disableSaveBtn = false;
} else if (attr == 'allowedMechs' && this.state._allowedMechs.join(' ') != value.join(' ')) {
@@ -139,6 +141,8 @@ export class ServerSASL extends React.Component {
// Now check for differences in values that we did not touch
if (attr != 'mappingFallback' && this.state._mappingFallback != this.state.mappingFallback) {
disableSaveBtn = false;
+ } else if (attr != 'saslPriority' && this.state._saslPriority != this.state.saslPriority) {
+ disableSaveBtn = false;
} else if (attr != 'maxBufSize' && this.state._maxBufSize != this.state.maxBufSize) {
disableSaveBtn = false;
} else if (attr != 'allowedMechs' && this.state._allowedMechs.join(' ') != this.state.allowedMechs.join(' ')) {
@@ -173,6 +177,8 @@ export class ServerSASL extends React.Component {
disableSaveBtn = false;
} else if (attr == 'saslBase' && value != "") {
disableSaveBtn = false;
+ } else if (attr == 'saslPriority' && value != "0") {
+ disableSaveBtn = false;
} else if (attr == 'saslFilter' && value != "") {
disableSaveBtn = false;
}
@@ -192,7 +198,7 @@ export class ServerSASL extends React.Component {
}
}

- // Handle TEst Text filed and buttons
+ // Handle Test Text field and buttons
if (attr == 'saslTestText' && value != "" && this.state.saslMapRegex != "") {
disableRegexTestBtn = false;
}
diff --git a/src/cockpit/389-console/src/lib/server/settings.jsx b/src/cockpit/389-console/src/lib/server/settings.jsx
index bb1ee6e..bc81310 100644
--- a/src/cockpit/389-console/src/lib/server/settings.jsx
+++ b/src/cockpit/389-console/src/lib/server/settings.jsx
@@ -33,8 +33,9 @@ const general_attrs = [
];

const rootdn_attrs = [
- 'nsslapd-rootpw',
'nsslapd-rootpwstoragescheme',
+ 'nsslapd-rootpw',
+ 'confirmRootpw',
];

const disk_attrs = [
@@ -173,15 +174,15 @@ export class ServerSettings extends React.Component {

// Handle validating passwords are in sync
if (attr == 'nsslapd-rootpw') {
- if (value != this.state._confirmRootpw) {
+ if (value != this.state.confirmRootpw) {
disableSaveBtn = true;
errObj['nsslapd-rootpw'] = true;
} else {
- errObj['nsslapdrootpw'] = false;
+ errObj['nsslapd-rootpw'] = false;
}
}
if (attr == 'confirmRootpw') {
- if (value != this.state['_nsslapd-rootpw']) {
+ if (value != this.state['nsslapd-rootpw']) {
disableSaveBtn = true;
errObj['confirmRootpw'] = true;
} else {
@@ -347,7 +348,7 @@ export class ServerSettings extends React.Component {
'nsslapd-certdir': attrs['nsslapd-certdir'][0],
'nsslapd-rootdn': attrs['nsslapd-rootdn'][0],
'nsslapd-rootpw': attrs['nsslapd-rootpw'][0],
- confirmRootpw: attrs['nsslapd-rootpw'][0],
+ 'confirmRootpw': attrs['nsslapd-rootpw'][0],
'nsslapd-rootpwstoragescheme': attrs['nsslapd-rootpwstoragescheme'][0],
'nsslapd-anonlimitsdn': attrs['nsslapd-anonlimitsdn'][0],
'nsslapd-disk-monitoring-threshold': attrs['nsslapd-disk-monitoring-threshold'][0],
@@ -376,7 +377,7 @@ export class ServerSettings extends React.Component {
'_nsslapd-certdir': attrs['nsslapd-certdir'][0],
'_nsslapd-rootdn': attrs['nsslapd-rootdn'][0],
'_nsslapd-rootpw': attrs['nsslapd-rootpw'][0],
- _confirmRootpw: attrs['nsslapd-rootpw'][0],
+ '_confirmRootpw': attrs['nsslapd-rootpw'][0],
'_nsslapd-rootpwstoragescheme': attrs['nsslapd-rootpwstoragescheme'][0],
'_nsslapd-anonlimitsdn': attrs['nsslapd-anonlimitsdn'][0],
'_nsslapd-disk-monitoring-threshold': attrs['nsslapd-disk-monitoring-threshold'][0],
@@ -404,7 +405,7 @@ export class ServerSettings extends React.Component {
];

for (let attr of rootdn_attrs) {
- if (this.state['_' + attr] != this.state[attr]) {
+ if (attr != 'confirmRootpw' && this.state['_' + attr] != this.state[attr]) {
cmd.push(attr + "=" + this.state[attr]);
}
}
@@ -448,12 +449,12 @@ export class ServerSettings extends React.Component {
rootDNReloading: false,
'nsslapd-rootdn': attrs['nsslapd-rootdn'][0],
'nsslapd-rootpw': attrs['nsslapd-rootpw'][0],
- confirmRootpw: attrs['nsslapd-rootpw'][0],
+ 'confirmRootpw': attrs['nsslapd-rootpw'][0],
'nsslapd-rootpwstoragescheme': attrs['nsslapd-rootpwstoragescheme'][0],
// Record original values
'_nsslapd-rootdn': attrs['nsslapd-rootdn'][0],
'_nsslapd-rootpw': attrs['nsslapd-rootpw'][0],
- _confirmRootpw: attrs['nsslapd-rootpw'][0],
+ '_confirmRootpw': attrs['nsslapd-rootpw'][0],
'_nsslapd-rootpwstoragescheme': attrs['nsslapd-rootpwstoragescheme'][0],
rootDNSaveDisabled: true
})
diff --git a/src/cockpit/389-console/src/lib/tools.jsx b/src/cockpit/389-console/src/lib/tools.jsx
index 7617a78..ea51c73 100644
--- a/src/cockpit/389-console/src/lib/tools.jsx
+++ b/src/cockpit/389-console/src/lib/tools.jsx
@@ -31,7 +31,7 @@ export function searchFilter(searchFilterValue, columnsToSearch, rows) {

export function log_cmd(js_func, desc, cmd_array) {
if (console) {
- let pw_args = ["--passwd", "--bind-pw"];
+ let pw_args = ["--passwd", "--bind-pw", "--nsslapd-rootpw"];
let cmd_list = [];
let converted_pw = false;

diff --git a/src/cockpit/389-console/src/plugins.jsx b/src/cockpit/389-console/src/plugins.jsx
index 53ef514..15e7cf6 100644
--- a/src/cockpit/389-console/src/plugins.jsx
+++ b/src/cockpit/389-console/src/plugins.jsx
@@ -94,7 +94,7 @@ export class Plugins extends React.Component {

toggleLoading() {
this.setState(prevState => ({
- loading: !prevState.loading
+ loading: !prevState.loading,
}));
}

@@ -138,15 +138,6 @@ export class Plugins extends React.Component {
}

pluginList() {
- if (this.state.firstLoad) {
- this.setState(prevState => ({
- firstLoad: false,
- pluginTabs: {
- ...prevState.pluginTabs,
- basicConfig: true
- }
- }));
- }
cmd = [
"dsconf",
"-j",
@@ -154,22 +145,33 @@ export class Plugins extends React.Component {
"plugin",
"list"
];
- this.toggleLoading();
+
log_cmd("pluginList", "Get plugins for table rows", cmd);
cockpit
.spawn(cmd, { superuser: true, err: "message" })
.done(content => {
var myObject = JSON.parse(content);
- this.setState({
- rows: myObject.items
- }, this.toggleLoading());
+ if (this.state.firstLoad) {
+ this.setState(prevState => ({
+ pluginTabs: {
+ ...prevState.pluginTabs,
+ basicConfig: true
+ },
+ rows: myObject.items,
+ firstLoad: false,
+ }));
+ } else {
+ this.setState({
+ rows: myObject.items
+ });
+ }
})
.fail(err => {
- if (err != 0) {
- let errMsg = JSON.parse(err);
- console.log("pluginList failed: ", errMsg.desc);
- }
- this.toggleLoading();
+ let errMsg = JSON.parse(err);
+ this.props.addNotification(
+ "error",
+ `${errMsg.desc} error during plugin loading`
+ );
});
}

@@ -321,6 +323,7 @@ export class Plugins extends React.Component {
addNotification={this.props.addNotification}
toggleLoadingHandler={this.toggleLoading}
wasActiveList={this.props.wasActiveList}
+ key={this.props.wasActiveList}
/>
)
},
@@ -335,6 +338,7 @@ export class Plugins extends React.Component {
addNotification={this.props.addNotification}
toggleLoadingHandler={this.toggleLoading}
wasActiveList={this.props.wasActiveList}
+ key={this.props.wasActiveList}
/>
)
},
@@ -349,6 +353,7 @@ export class Plugins extends React.Component {
addNotification={this.props.addNotification}
toggleLoadingHandler={this.toggleLoading}
wasActiveList={this.props.wasActiveList}
+ key={this.props.wasActiveList}
/>
)
},
@@ -363,6 +368,7 @@ export class Plugins extends React.Component {
addNotification={this.props.addNotification}
toggleLoadingHandler={this.toggleLoading}
wasActiveList={this.props.wasActiveList}
+ key={this.props.wasActiveList}
/>
)
},
@@ -377,6 +383,7 @@ export class Plugins extends React.Component {
addNotification={this.props.addNotification}
toggleLoadingHandler={this.toggleLoading}
wasActiveList={this.props.wasActiveList}
+ key={this.props.wasActiveList}
/>
)
},
@@ -404,6 +411,7 @@ export class Plugins extends React.Component {
addNotification={this.props.addNotification}
toggleLoadingHandler={this.toggleLoading}
wasActiveList={this.props.wasActiveList}
+ key={this.props.wasActiveList}
/>
)
},
@@ -431,6 +439,7 @@ export class Plugins extends React.Component {
addNotification={this.props.addNotification}
toggleLoadingHandler={this.toggleLoading}
wasActiveList={this.props.wasActiveList}
+ key={this.props.wasActiveList}
/>
)
},
@@ -445,6 +454,7 @@ export class Plugins extends React.Component {
addNotification={this.props.addNotification}
toggleLoadingHandler={this.toggleLoading}
wasActiveList={this.props.wasActiveList}
+ key={this.props.wasActiveList}
/>
)
},
@@ -472,67 +482,75 @@ export class Plugins extends React.Component {
addNotification={this.props.addNotification}
toggleLoadingHandler={this.toggleLoading}
wasActiveList={this.props.wasActiveList}
+ key={this.props.wasActiveList}
/>
)
}
};
+
return (
<div className="container-fluid">
- <Row className="clearfix">
- <Col sm={12}>
- <Spinner
- className="ds-float-left ds-plugin-spinner"
- loading={this.state.loading}
- size="md"
- />
- </Col>
- </Row>
- <Tab.Container
- id="left-tabs-example"
- defaultActiveKey={Object.keys(selectPlugins)[0]}
- >
+ <div className="ds-loading-spinner ds-center" hidden={!this.state.firstLoad}>
+ <h4>Loading plugins ...</h4>
+ <Spinner className="ds-margin-top" loading size="md" />
+ </div>
+ <div hidden={this.state.firstLoad}>
<Row className="clearfix">
- <Col sm={3}>
- <Nav bsStyle="pills" stacked>
- {Object.entries(selectPlugins).map(([id, item]) => (
- <NavItem key={id} eventKey={id}>
- {item.name}
- </NavItem>
- ))}
- </Nav>
- </Col>
- <Col sm={9}>
- <Tab.Content animation={false}>
- {Object.entries(selectPlugins).map(([id, item]) => (
- <Tab.Pane key={id} eventKey={id}>
- {item.component}
- </Tab.Pane>
- ))}
- </Tab.Content>
+ <Col sm={12}>
+ <Spinner
+ className="ds-float-left ds-plugin-spinner"
+ loading={this.state.loading}
+ size="md"
+ />
</Col>
</Row>
- </Tab.Container>
- <PluginEditModal
- handleChange={this.handleFieldChange}
- handleSwitchChange={this.handleSwitchChange}
- pluginData={{
- currentPluginName: this.state.currentPluginName,
- currentPluginType: this.state.currentPluginType,
- currentPluginEnabled: this.state.currentPluginEnabled,
- currentPluginPath: this.state.currentPluginPath,
- currentPluginInitfunc: this.state.currentPluginInitfunc,
- currentPluginId: this.state.currentPluginId,
- currentPluginVendor: this.state.currentPluginVendor,
- currentPluginVersion: this.state.currentPluginVersion,
- currentPluginDescription: this.state.currentPluginDescription,
- currentPluginDependsOnType: this.state.currentPluginDependsOnType,
- currentPluginDependsOnNamed: this.state.currentPluginDependsOnNamed,
- currentPluginPrecedence: this.state.currentPluginPrecedence
- }}
- closeHandler={this.closePluginModal}
- showModal={this.state.showPluginModal}
- savePluginHandler={this.savePlugin}
- />
+ <Tab.Container
+ id="left-tabs-example"
+ defaultActiveKey={Object.keys(selectPlugins)[0]}
+ >
+ <Row className="clearfix">
+ <Col sm={3}>
+ <Nav bsStyle="pills" stacked>
+ {Object.entries(selectPlugins).map(([id, item]) => (
+ <NavItem key={id} eventKey={id}>
+ {item.name}
+ </NavItem>
+ ))}
+ </Nav>
+ </Col>
+ <Col sm={9}>
+ <Tab.Content animation={false}>
+ {Object.entries(selectPlugins).map(([id, item]) => (
+ <Tab.Pane key={id} eventKey={id}>
+ {item.component}
+ </Tab.Pane>
+ ))}
+ </Tab.Content>
+ </Col>
+ </Row>
+ </Tab.Container>
+ <PluginEditModal
+ handleChange={this.handleFieldChange}
+ handleSwitchChange={this.handleSwitchChange}
+ pluginData={{
+ currentPluginName: this.state.currentPluginName,
+ currentPluginType: this.state.currentPluginType,
+ currentPluginEnabled: this.state.currentPluginEnabled,
+ currentPluginPath: this.state.currentPluginPath,
+ currentPluginInitfunc: this.state.currentPluginInitfunc,
+ currentPluginId: this.state.currentPluginId,
+ currentPluginVendor: this.state.currentPluginVendor,
+ currentPluginVersion: this.state.currentPluginVersion,
+ currentPluginDescription: this.state.currentPluginDescription,
+ currentPluginDependsOnType: this.state.currentPluginDependsOnType,
+ currentPluginDependsOnNamed: this.state.currentPluginDependsOnNamed,
+ currentPluginPrecedence: this.state.currentPluginPrecedence
+ }}
+ closeHandler={this.closePluginModal}
+ showModal={this.state.showPluginModal}
+ savePluginHandler={this.savePlugin}
+ />
+ </div>
</div>
);
}
diff --git a/src/cockpit/389-console/src/schema.jsx b/src/cockpit/389-console/src/schema.jsx
index 0078e47..9c3ac5e 100644
--- a/src/cockpit/389-console/src/schema.jsx
+++ b/src/cockpit/389-console/src/schema.jsx
@@ -7,6 +7,7 @@ import {
MatchingRulesTable
} from "./lib/schema/schemaTables.jsx";
import { ObjectClassModal, AttributeTypeModal } from "./lib/schema/schemaModals.jsx";
+import { DoubleConfirmModal } from "./lib/notifications.jsx";
import {
Nav,
NavItem,
@@ -50,6 +51,7 @@ export class Schema extends React.Component {
attributes: [],
objectclasses: [],
matchingrules: [],
+ deleteName: "",

ocModalViewOnly: false,
ocName: "",
@@ -97,20 +99,24 @@ export class Schema extends React.Component {
this.showAddObjectclassModal = this.showAddObjectclassModal.bind(this);
this.openObjectclassModal = this.openObjectclassModal.bind(this);
this.closeObjectclassModal = this.closeObjectclassModal.bind(this);
- this.deleteObjectclass = this.deleteObjectclass.bind(this);
+ this.doDeleteOC = this.doDeleteOC.bind(this);
this.addObjectclass = this.addObjectclass.bind(this);
this.editObjectclass = this.editObjectclass.bind(this);
this.cmdOperationObjectclass = this.cmdOperationObjectclass.bind(this);
+ this.showConfirmOCDelete = this.showConfirmOCDelete.bind(this);
+ this.closeConfirmOCDelete = this.closeConfirmOCDelete.bind(this);

this.showViewAttributeModal = this.showViewAttributeModal.bind(this);
this.showEditAttributeModal = this.showEditAttributeModal.bind(this);
this.showAddAttributeModal = this.showAddAttributeModal.bind(this);
this.openAttributeModal = this.openAttributeModal.bind(this);
this.closeAttributeModal = this.closeAttributeModal.bind(this);
- this.deleteAttribute = this.deleteAttribute.bind(this);
+ this.doDeleteAttr = this.doDeleteAttr.bind(this);
this.addAttribute = this.addAttribute.bind(this);
this.editAttribute = this.editAttribute.bind(this);
this.cmdOperationAttribute = this.cmdOperationAttribute.bind(this);
+ this.showConfirmAttrDelete = this.showConfirmAttrDelete.bind(this);
+ this.closeConfirmAttrDelete = this.closeConfirmAttrDelete.bind(this);
}

toggleLoading(item) {
@@ -371,8 +377,25 @@ export class Schema extends React.Component {
this.setState({ objectclassModalShow: false });
}

- deleteObjectclass(rowData) {
- let name = rowData.name[0];
+ closeConfirmOCDelete () {
+ // call doDeleteOC
+ this.setState({
+ showConfirmDeleteOC: false,
+ modalChecked: false,
+ modalSpinning: false,
+ });
+ }
+
+ showConfirmOCDelete(oc_name) {
+ this.setState({
+ showConfirmDeleteOC: true,
+ modalChecked: false,
+ modalSpinning: false,
+ deleteName: oc_name
+ });
+ }
+
+ doDeleteOC() {
let cmd = [
"dsconf",
"-j",
@@ -380,10 +403,13 @@ export class Schema extends React.Component {
"schema",
"objectclasses",
"remove",
- name
+ this.state.deleteName
];

- this.toggleLoading("ocTable");
+ this.setState({
+ modalSpinning: true,
+ });
+
log_cmd("deleteObjectclass", "Delete ObjectClass from schema", cmd);
cockpit
.spawn(cmd, {
@@ -392,9 +418,9 @@ export class Schema extends React.Component {
})
.done(content => {
console.info("deleteObjectclass", "Result", content);
- this.props.addNotification("success", `ObjectClass ${name} was successfully deleted`);
+ this.props.addNotification("success", `ObjectClass ${this.state.deleteName} was successfully deleted`);
this.loadSchemaData();
- this.toggleLoading("ocTable");
+ this.closeConfirmOCDelete();
})
.fail(err => {
let errMsg = JSON.parse(err);
@@ -403,7 +429,7 @@ export class Schema extends React.Component {
`Error during ObjectClass removal operation - ${errMsg.desc}`
);
this.loadSchemaData();
- this.toggleLoading("ocTable");
+ this.closeConfirmOCDelete();
});
}

@@ -644,11 +670,29 @@ export class Schema extends React.Component {
}

closeAttributeModal() {
- this.setState({ attributeModalShow: false });
+ this.setState({
+ attributeModalShow: false
+ });
+ }
+
+ closeConfirmAttrDelete () {
+ this.setState({
+ showConfirmAttrDelete: false,
+ modalChecked: false,
+ modalSpinning: false,
+ });
+ }
+
+ showConfirmAttrDelete(attr_name) {
+ this.setState({
+ showConfirmAttrDelete: true,
+ modalChecked: false,
+ modalSpinning: false,
+ deleteName: attr_name
+ });
}

- deleteAttribute(rowData) {
- let name = rowData.name[0];
+ doDeleteAttr() {
let cmd = [
"dsconf",
"-j",
@@ -656,10 +700,13 @@ export class Schema extends React.Component {
"schema",
"attributetypes",
"remove",
- name
+ this.state.deleteName
];

- this.toggleLoading("atTable");
+ this.setState({
+ modalSpinning: true,
+ });
+
log_cmd("deleteAttribute", "Delete Attribute from schema", cmd);
cockpit
.spawn(cmd, {
@@ -668,9 +715,9 @@ export class Schema extends React.Component {
})
.done(content => {
console.info("deleteAttribute", "Result", content);
- this.props.addNotification("success", `Attribute ${name} was successfully deleted`);
+ this.props.addNotification("success", `Attribute ${this.state.deleteName} was successfully deleted`);
this.loadSchemaData();
- this.toggleLoading("atTable");
+ this.closeConfirmAttrDelete();
})
.fail(err => {
let errMsg = JSON.parse(err);
@@ -679,7 +726,7 @@ export class Schema extends React.Component {
`Error during Attribute removal operation - ${errMsg.desc}`
);
this.loadSchemaData();
- this.toggleLoading("atTable");
+ this.closeConfirmAttrDelete();
});
}

@@ -895,7 +942,7 @@ export class Schema extends React.Component {
rows={this.state.filteredObjectclassRows}
viewModalHandler={this.showViewObjectclassModal}
editModalHandler={this.showEditObjectclassModal}
- deleteHandler={this.deleteObjectclass}
+ deleteHandler={this.showConfirmOCDelete}
loading={this.state.ocTableLoading}
/>
<Button
@@ -946,7 +993,7 @@ export class Schema extends React.Component {
rows={this.state.filteredAttributesRows}
viewModalHandler={this.showViewAttributeModal}
editModalHandler={this.showEditAttributeModal}
- deleteHandler={this.deleteAttribute}
+ deleteHandler={this.showConfirmAttrDelete}
syntaxes={this.state.syntaxes}
loading={this.state.atTableLoading}
/>
@@ -998,6 +1045,32 @@ export class Schema extends React.Component {
</div>
</TabContainer>
</div>
+ <DoubleConfirmModal
+ showModal={this.state.showConfirmDeleteOC}
+ closeHandler={this.closeConfirmOCDelete}
+ handleChange={this.handleFieldChange}
+ actionHandler={this.doDeleteOC}
+ spinning={this.state.modalSpinning}
+ item={this.state.deleteName}
+ checked={this.state.modalChecked}
+ mTitle="Delete An Objectclass"
+ mMsg="Are you sure you want to delete this Objectclass?"
+ mSpinningMsg="Deleting objectclass ..."
+ mBtnName="Delete Objectclass"
+ />
+ <DoubleConfirmModal
+ showModal={this.state.showConfirmAttrDelete}
+ closeHandler={this.closeConfirmAttrDelete}
+ handleChange={this.handleFieldChange}
+ actionHandler={this.doDeleteAttr}
+ spinning={this.state.modalSpinning}
+ item={this.state.deleteName}
+ checked={this.state.modalChecked}
+ mTitle="Delete An Attribute"
+ mMsg="Are you sure you want to delete this Attribute?"
+ mSpinningMsg="Deleting attribute ..."
+ mBtnName="Delete Attribute"
+ />
</div>
);
}
diff --git a/src/cockpit/389-console/src/security.jsx b/src/cockpit/389-console/src/security.jsx
index 815f664..5d6d84f 100644
--- a/src/cockpit/389-console/src/security.jsx
+++ b/src/cockpit/389-console/src/security.jsx
@@ -84,6 +84,7 @@ export class Security extends React.Component {
this.disableSecurity = this.disableSecurity.bind(this);
this.saveSecurityConfig = this.saveSecurityConfig.bind(this);
this.closeSecurityEnableModal = this.closeSecurityEnableModal.bind(this);
+ this.reloadConfig = this.reloadConfig.bind(this);
}

componentWillMount () {
@@ -103,6 +104,12 @@ export class Security extends React.Component {
}
}

+ reloadConfig () {
+ this.setState({
+ loaded: false
+ }, this.loadSecurityConfig);
+ }
+
loadSupportedCiphers () {
const cmd = [
"dsconf", "-j", "ldapi://%2fvar%2frun%2fslapd-" + this.props.serverId + ".socket",
@@ -482,7 +489,7 @@ export class Security extends React.Component {
if (sslMin > sslMax) {
this.props.addNotification(
"error",
- `The TLS minimum version but be less than or equal to the TLS maximum version`
+ `The TLS minimum version must be less than or equal to the TLS maximum version`
);
// Reset page
this.loadSecurityConfig();
@@ -620,7 +627,7 @@ export class Security extends React.Component {
<Col componentClass={ControlLabel} sm={4}>
Secure Listen Host
</Col>
- <Col sm={4}>
+ <Col sm={8}>
<FormControl
id="secureListenhost"
type="text"
@@ -633,7 +640,7 @@ export class Security extends React.Component {
<Col componentClass={ControlLabel} sm={4}>
Server Certificate Name
</Col>
- <Col sm={4}>
+ <Col sm={8}>
<Typeahead
id="serverCertNameTypeahead"
onChange={this.handleTypeaheadChange}
@@ -649,7 +656,7 @@ export class Security extends React.Component {
<Col componentClass={ControlLabel} sm={4}>
Minimum TLS Version
</Col>
- <Col sm={4}>
+ <Col sm={8}>
<select id="sslVersionMin" className="btn btn-default dropdown ds-select" onChange={this.handleChange} value={this.state.sslVersionMin}>
<option>TLS1.3</option>
<option>TLS1.2</option>
@@ -765,7 +772,7 @@ export class Security extends React.Component {
Security Settings
<Icon className="ds-left-margin ds-refresh"
type="fa" name="refresh" title="Refresh configuration settings"
- onClick={this.loadSecurityConfig}
+ onClick={this.reloadConfig}
/>
</ControlLabel>
</Col>
diff --git a/src/cockpit/389-console/src/server.jsx b/src/cockpit/389-console/src/server.jsx
index a67ba40..4501a48 100644
--- a/src/cockpit/389-console/src/server.jsx
+++ b/src/cockpit/389-console/src/server.jsx
@@ -227,6 +227,7 @@ export class Server extends React.Component {
serverId={this.props.serverId}
attrs={this.state.attrs}
enableTree={this.enableTree}
+ addNotification={this.props.addNotification}
/>
);
} else if (this.state.node_name == "tuning-config") {
@@ -235,11 +236,16 @@ export class Server extends React.Component {
serverId={this.props.serverId}
attrs={this.state.attrs}
enableTree={this.enableTree}
+ addNotification={this.props.addNotification}
/>
);
} else if (this.state.node_name == "sasl-config") {
server_element = (
- <ServerSASL serverId={this.props.serverId} enableTree={this.enableTree} />
+ <ServerSASL
+ serverId={this.props.serverId}
+ enableTree={this.enableTree}
+ addNotification={this.props.addNotification}
+ />
);
} else if (this.state.node_name == "security-config") {
server_element = (
@@ -255,6 +261,7 @@ export class Server extends React.Component {
serverId={this.props.serverId}
attrs={this.state.attrs}
enableTree={this.enableTree}
+ addNotification={this.props.addNotification}
/>
);
} else if (this.state.node_name == "access-log-config") {
@@ -263,6 +270,7 @@ export class Server extends React.Component {
serverId={this.props.serverId}
attrs={this.state.attrs}
enableTree={this.enableTree}
+ addNotification={this.props.addNotification}
/>
);
} else if (this.state.node_name == "audit-log-config") {
@@ -271,6 +279,7 @@ export class Server extends React.Component {
serverId={this.props.serverId}
attrs={this.state.attrs}
enableTree={this.enableTree}
+ addNotification={this.props.addNotification}
/>
);
} else if (this.state.node_name == "auditfail-log-config") {
@@ -279,6 +288,7 @@ export class Server extends React.Component {
serverId={this.props.serverId}
attrs={this.state.attrs}
enableTree={this.enableTree}
+ addNotification={this.props.addNotification}
/>
);
} else if (this.state.node_name == "error-log-config") {
@@ -287,6 +297,7 @@ export class Server extends React.Component {
serverId={this.props.serverId}
attrs={this.state.attrs}
enableTree={this.enableTree}
+ addNotification={this.props.addNotification}
/>
);
}
diff --git a/src/cockpit/389-console/webpack.config.js b/src/cockpit/389-console/webpack.config.js
index ce8e3d1..0c44247 100644
--- a/src/cockpit/389-console/webpack.config.js
+++ b/src/cockpit/389-console/webpack.config.js
@@ -167,5 +167,9 @@ module.exports = {
}
]
},
- plugins: plugins
+ plugins: plugins,
+ watchOptions: {
+ poll: true,
+ ignored: /node_modules/
+ }
};
diff --git a/src/lib389/lib389/cli_conf/plugins/attruniq.py b/src/lib389/lib389/cli_conf/plugins/attruniq.py
index fee4137..7793337 100644
--- a/src/lib389/lib389/cli_conf/plugins/attruniq.py
+++ b/src/lib389/lib389/cli_conf/plugins/attruniq.py
@@ -11,7 +11,6 @@ import ldap
from lib389.plugins import AttributeUniquenessPlugin, AttributeUniquenessPlugins
from lib389.cli_conf import (add_generic_plugin_parsers, generic_object_edit, generic_object_add,
generic_enable, generic_disable, generic_status)
-from lib389._constants import DN_PLUGIN

arg_to_attr = {
'enabled': 'nsslapd-pluginenabled',
@@ -22,6 +21,7 @@ arg_to_attr = {
'subtree_entries_oc': 'uniqueness-subtree-entries-oc'
}

+PLUGIN_DN = "cn=plugins,cn=config"

def attruniq_list(inst, basedn, log, args):
log = log.getChild('attruniq_list')
@@ -30,11 +30,11 @@ def attruniq_list(inst, basedn, log, args):
result_json = []
for plugin in plugins.list():
if args.json:
- result_json.append(plugin.get_all_attrs_json())
+ result_json.append(json.loads(plugin.get_all_attrs_json()))
else:
result.append(plugin.rdn)
if args.json:
- log.info(json.dumps({"type": "list", "items": result_json}))
+ log.info(json.dumps({"type": "list", "items": result_json}, indent=4))
else:
if len(result) > 0:
for i in result:
@@ -46,7 +46,11 @@ def attruniq_list(inst, basedn, log, args):
def attruniq_add(inst, basedn, log, args):
log = log.getChild('attruniq_add')
props = {'cn': args.NAME}
- generic_object_add(AttributeUniquenessPlugin, inst, log, args, arg_to_attr, basedn=DN_PLUGIN, props=props)
+ # We require a subtree, or a target Objectclass
+ if args.subtree_entries_oc is None and args.subtree is None:
+ raise ValueError("A attribute uniqueness configuration requires a 'subtree' or 'subtree-entries-oc' to be set")
+
+ generic_object_add(AttributeUniquenessPlugin, inst, log, args, arg_to_attr, basedn=PLUGIN_DN, props=props)


def attruniq_edit(inst, basedn, log, args):
@@ -64,8 +68,7 @@ def attruniq_show(inst, basedn, log, args):
if not plugin.exists():
raise ldap.NO_SUCH_OBJECT("Entry %s doesn't exists" % args.name)
if args and args.json:
- o_str = plugin.get_all_attrs_json()
- log.info(o_str)
+ log.info(plugin.get_all_attrs_json())
else:
log.info(plugin.display())

diff --git a/src/lib389/lib389/cli_conf/plugins/usn.py b/src/lib389/lib389/cli_conf/plugins/usn.py
index 634ca7f..68e2527 100644
--- a/src/lib389/lib389/cli_conf/plugins/usn.py
+++ b/src/lib389/lib389/cli_conf/plugins/usn.py
@@ -35,7 +35,7 @@ def tombstone_cleanup(inst, basedn, log, args):
log.info('Attempting to add task entry...')
if not plugin.status():
log.error("'%s' is disabled. Fix up task can't be executed" % plugin.rdn)
- task = plugin.cleanup(args.suffix, args.backend, args.maxusn)
+ task = plugin.cleanup(args.suffix, args.backend, args.max_usn)
task.wait()
exitcode = task.get_exit_code()
if exitcode != 0:
@@ -66,6 +66,6 @@ def create_parser(subparsers):
cleanup_group.add_argument('-n', '--backend',
help='Gives the Directory Server instance back end, or database, to run the cleanup '
'operation against. If the back end is not specified, then the suffix must be '
- 'specified.Backend instance in which USN tombstone entries (backend)')
- cleanup_parser.add_argument('-m', '--maxusn', type=int, help='Gives the highest USN value to delete when '
+ 'specified. Backend instance in which USN tombstone entries (backend)')
+ cleanup_parser.add_argument('-m', '--max-usn', type=int, help='Gives the highest USN value to delete when '
'removing tombstone entries (max_usn_to_delete)')
diff --git a/src/lib389/lib389/cli_conf/replication.py b/src/lib389/lib389/cli_conf/replication.py
index 8e77c36..09cb9b4 100644
--- a/src/lib389/lib389/cli_conf/replication.py
+++ b/src/lib389/lib389/cli_conf/replication.py
@@ -580,17 +580,38 @@ def create_repl_manager(inst, basedn, log, args):


def del_repl_manager(inst, basedn, log, args):
+ """Delete the manager entry is it exists, and remove it from replica
+ configuration if a suffix was provided.
+ """
+ deleted_manager_entry = False
if is_a_dn(args.name):
manager_dn = args.name
else:
manager_dn = "cn={},cn=config".format(args.name)
manager = BootstrapReplicationManager(inst, dn=manager_dn)
- manager.delete()
- if args.suffix:
- # Add supplier DN to config
+
+ try:
+ manager.delete()
+ deleted_manager_entry = True
+ except ldap.NO_SUCH_OBJECT:
+ # This is not okay if we did not specify a suffix
+ if args.suffix is None:
+ raise ValueError(f"The replication manager entry ({manager_dn}) does not exist.")
+
+ if args.suffix is not None:
+ # Delete supplier DN from the replication config
replicas = Replicas(inst)
replica = replicas.get(args.suffix)
- replica.remove('nsds5ReplicaBindDN', manager_dn)
+ try:
+ replica.remove('nsds5ReplicaBindDN', manager_dn)
+ except ldap.NO_SUCH_ATTRIBUTE:
+ # The manager was not in the config
+ msg = f"The replication manager ({manager_dn}) does not exist in the suffix replication configuration"
+ if deleted_manager_entry:
+ # We already deleted the manager entry, better say something
+ msg += ", but the replication manager entry has been deleted from the global configuration."
+ raise ValueError(msg)
+
log.info("Successfully deleted replication manager: " + manager_dn)


diff --git a/src/lib389/lib389/plugins.py b/src/lib389/lib389/plugins.py
index 0775e46..d6c9561 100644
--- a/src/lib389/lib389/plugins.py
+++ b/src/lib389/lib389/plugins.py
@@ -134,7 +134,7 @@ class AttributeUniquenessPlugin(Plugin):
'nsslapd-pluginDescription': 'Enforce unique attribute values',
}

- def __init__(self, instance, dn="cn=attribute uniqueness,cn=plugins,cn=config"):
+ def __init__(self, instance, dn="cn=plugins,cn=config"):
super(AttributeUniquenessPlugin, self).__init__(instance, dn)
self._protected = False
self._create_objectclasses = ['top', 'nsslapdplugin', 'extensibleObject']
@@ -192,13 +192,13 @@ class AttributeUniquenessPlugins(DSLdapObjects):
self._basedn = basedn
# This is used to allow entry to instance to work
self._list_attrlist = ['dn', 'nsslapd-pluginPath']
- self._search_filter = "(nsslapd-pluginId=NSUniqueAttr)"
+ self._search_filter = "(nsslapd-pluginInitfunc=NSUniqueAttr_Init)"
self._scope = ldap.SCOPE_SUBTREE
self._server_controls = None
self._client_controls = None

def list(self):
- """Get a list of all plugin instances where nsslapd-pluginId: NSUniqueAttr
+ """Get a list of all plugin instances where nsslapd-pluginInitfunc: NSUniqueAttr_Init

:returns: A list of children entries
"""
@@ -206,7 +206,7 @@ class AttributeUniquenessPlugins(DSLdapObjects):
try:
results = self._instance.search_ext_s(
base=self._basedn,
- scope=ldap.SCOPE_ONELEVEL,
+ scope=self._scope,
filterstr=self._search_filter,
attrlist=self._list_attrlist,
serverctrls=self._server_controls, clientctrls=self._client_controls

--
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