Skip to content

Commit

Permalink
Merge pull request #175 from Spyderisk/102-add-filters-for-control-an…
Browse files Browse the repository at this point in the history
…d-control-strategy-lists

#102: Add filters for control and control strategy lists
  • Loading branch information
kenmeacham authored May 28, 2024
2 parents c31b86a + 3b679c2 commit 7db0d46
Show file tree
Hide file tree
Showing 3 changed files with 130 additions and 16 deletions.
1 change: 0 additions & 1 deletion src/main/webapp/app/modeller/actions/ModellerActions.js
Original file line number Diff line number Diff line change
Expand Up @@ -1454,7 +1454,6 @@ export function resetControls(modelId, controls) {

//Update multiple controls with new proposed value
export function updateControls(modelId, controls, proposed, workInProgress, controlsReset) {
console.log("updateControls: controlsReset = " + controlsReset);
let controlsUpdateRequest = {
controls: controls,
proposed: proposed,
Expand Down
142 changes: 127 additions & 15 deletions src/main/webapp/app/modeller/components/panes/details/ModelSummary.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,9 @@ class ModelSummary extends Component {
this.renderPossibleModellingErrorsPanel = this.renderPossibleModellingErrorsPanel.bind(this);
this.renderCompliancePanel = this.renderCompliancePanel.bind(this);
this.renderControlSetsPanel = this.renderControlSetsPanel.bind(this);
this.renderControlSetOptions = this.renderControlSetOptions.bind(this);
this.renderControlStrategiesPanel = this.renderControlStrategiesPanel.bind(this);
this.renderCsgOptions = this.renderCsgOptions.bind(this);
this.resetControls = this.resetControls.bind(this);
this.togglePanel = this.togglePanel.bind(this);
this.formatRiskCalcMode = this.formatRiskCalcMode.bind(this);
Expand All @@ -62,7 +64,6 @@ class ModelSummary extends Component {
this.countProposedControls = this.countProposedControls.bind(this);
this.countProposedControlStrategies = this.countProposedControlStrategies.bind(this);


this.state = {
changeRelationModal: {
show: false,
Expand All @@ -79,8 +80,14 @@ class ModelSummary extends Component {
selectedAssetOnly: true
},
controls: {
search: "",
filter: false,
updating: []
},
csgs: {
search: "",
filter: false
},
}
}

Expand All @@ -90,6 +97,7 @@ class ModelSummary extends Component {
this.setState({
...this.state,
controls: {
...this.state.controls,
updating: []
}
})
Expand Down Expand Up @@ -448,6 +456,18 @@ class ModelSummary extends Component {
controlSets.map((controlSet, index) => {
let name = controlSet[0]; //e.g. AccessControl
let csList = controlSet[1]; //list of cs uris
let nProposedControls = this.countProposedControls(csList);
let proposed = nProposedControls > 0;

// If text search filter is defined, filter out controls with names that don't match
if (this.state.controls.search !== "") {
let search = this.state.controls.search.toLowerCase();
if (name.toLowerCase().indexOf(search) === -1) return;
}

// If filter is active, filter out control set groups that have no proposed controls
if (this.state.controls.filter && (nProposedControls === 0)) return;

let listName = "ControlSet" + index;
var assetUris = new Map();
csList.forEach((c) => {
Expand Down Expand Up @@ -478,12 +498,12 @@ class ModelSummary extends Component {
<OverlayTrigger {...ctrlSetOverlayProps}>
<span onMouseEnter={() => this.hoverControl(assets, true)}
onMouseLeave={() => this.hoverControl(assets, false)}
className="clickable"
className={"clickable" + (proposed ? " proposed" : "")}
onClick={() => {
this.props.dispatch(openControlExplorer(csList[0].control));
this.props.dispatch(bringToFrontWindow("controlExplorer"));
}}>
{name} : {this.countProposedControls(csList)} of {csList.length} {" "}
{name} : {nProposedControls} of {csList.length} {" "}
{spinnerActive ? <i className="fa fa-spinner fa-pulse fa-lg fa-fw"/> : null}
</span>
</OverlayTrigger>
Expand All @@ -492,18 +512,9 @@ class ModelSummary extends Component {
</Row>);
});

let controlSetReset = <FormGroup>
<Button bsStyle="danger" bsSize="xsmall"
onClick={() => this.resetControls(
Array.from(this.props.model.controlSets)
)}>
Remove All Controls
</Button>
</FormGroup>

return (
<div>
{ controlSets.length > 0 ? controlSetReset : "" }
{ controlSets.length > 0 ? this.renderControlSetOptions() : "" }
<PagedPanel panelData={controlsRender}
pageSize={15}
context={"controls-" + this.props.model.id}
Expand All @@ -512,15 +523,74 @@ class ModelSummary extends Component {
)
}

renderControlSetOptions() {
return (
<Form>
<FormGroup>
<Button bsStyle="danger" bsSize="xsmall"
onClick={() => this.resetControls(
Array.from(this.props.model.controlSets)
)}>
Remove All Controls
</Button>
</FormGroup>
<FormGroup>
<InputGroup>
<InputGroup.Addon><i className="fa fa-lg fa-filter"/></InputGroup.Addon>
<FormControl
type="text"
placeholder="Filter controls by name"
value={this.state.controls.search}
onChange={(e) => {
this.setState({
...this.state,
controls: {...this.state.controls, search: e.nativeEvent.target.value.trim()}
})
}}
// need to prevent the Form being submitted when Return is pressed
onKeyPress={(e) => { e.key === 'Enter' && e.preventDefault(); }}
/>
</InputGroup>
</FormGroup>
<FormGroup>
<Checkbox
checked={this.state.controls.filter}
onChange={(e) => {
this.setState({
...this.state,
controls: {
...this.state.controls,
filter: e.nativeEvent.target.checked
}
})
}}>
Only asserted controls
</Checkbox>
</FormGroup>
</Form>
)
}

renderControlStrategiesPanel(csgs) {
let csgsRender = [];

csgs.map((csgEntry, index) => {
let name = csgEntry[0];
let csgList = csgEntry[1];
let nProposedCsgs = this.countProposedControlStrategies(csgList);
let proposed = nProposedCsgs > 0;
let context = {"selection": "csgType"};
let spinnerActive = false; //may not need this

// If text search filter is defined, filter out control strategies with names that don't match
if (this.state.csgs.search !== "") {
let search = this.state.csgs.search.toLowerCase();
if (name.toLowerCase().indexOf(search) === -1) return;
}

// If filter is active, filter out CSG groups that have no proposed CSGs
if (this.state.csgs.filter && (nProposedCsgs === 0)) return;

let csgOverlayProps = {
delayShow: Constants.TOOLTIP_DELAY, placement: "left",
overlay: <Tooltip id={"csg-" + 1 + "-error-tooltip"}
Expand All @@ -536,12 +606,12 @@ class ModelSummary extends Component {
>
<OverlayTrigger {...csgOverlayProps}>
<span
className="clickable"
className={"clickable" + (proposed ? " proposed" : "")}
onClick={() => {
this.props.dispatch(openControlStrategyExplorer(csgList, context));
this.props.dispatch(bringToFrontWindow("controlStrategyExplorer"));
}}>
{name} : {this.countProposedControlStrategies(csgList)} of {csgList.length} {" "}
{name} : {nProposedCsgs} of {csgList.length} {" "}
{spinnerActive ? <i className="fa fa-spinner fa-pulse fa-lg fa-fw"/> : null}
</span>
</OverlayTrigger>
Expand All @@ -550,6 +620,7 @@ class ModelSummary extends Component {

return (
<div>
{csgs.length > 0 ? this.renderCsgOptions() : ""}
<PagedPanel panelData={csgsRender}
pageSize={15}
context={"csgs-" + this.props.model.id}
Expand All @@ -558,6 +629,46 @@ class ModelSummary extends Component {
)
}

renderCsgOptions() {
return (
<Form>
<FormGroup>
<InputGroup>
<InputGroup.Addon><i className="fa fa-lg fa-filter"/></InputGroup.Addon>
<FormControl
type="text"
placeholder="Filter control strategies by name"
value={this.state.csgs.search}
onChange={(e) => {
this.setState({
...this.state,
csgs: {...this.state.csgs, search: e.nativeEvent.target.value.trim()}
})
}}
// need to prevent the Form being submitted when Return is pressed
onKeyPress={(e) => { e.key === 'Enter' && e.preventDefault(); }}
/>
</InputGroup>
</FormGroup>
<FormGroup>
<Checkbox
checked={this.state.csgs.filter}
onChange={(e) => {
this.setState({
...this.state,
csgs: {
...this.state.csgs,
filter: e.nativeEvent.target.checked
}
})
}}>
Only enabled control strategies
</Checkbox>
</FormGroup>
</Form>
)
}

updateModel(id, updatedModel) {
this.setState({ ...this.state, editDetailsModal: false });
this.props.dispatch(updateModel(id, updatedModel));
Expand Down Expand Up @@ -590,6 +701,7 @@ class ModelSummary extends Component {
updateControlsState(controlLabels) {
this.setState({...this.state,
controls: {
...this.state.controls,
updating: controlLabels
}
});
Expand Down
3 changes: 3 additions & 0 deletions src/main/webapp/app/modeller/index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -902,6 +902,9 @@ select.level + .fa-spinner {
.clickable {
color: #337ab7;
cursor: pointer;
&.proposed {
font-weight: bold;
}
}

.clickable:hover {
Expand Down

0 comments on commit 7db0d46

Please sign in to comment.