Skip to content

Commit

Permalink
#12 Add custom field create/update dialog to admin section
Browse files Browse the repository at this point in the history
  • Loading branch information
nadouani committed Jun 22, 2017
1 parent 7bec5f2 commit 6355b90
Show file tree
Hide file tree
Showing 11 changed files with 186 additions and 82 deletions.
2 changes: 2 additions & 0 deletions thehive-backend/conf/routes
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,11 @@ POST /api/maintenance/migrate org.elastic4play.controllers.M

GET /api/list org.elastic4play.controllers.DBListCtrl.list()
DELETE /api/list/:itemId org.elastic4play.controllers.DBListCtrl.deleteItem(itemId)
PATCH /api/list/:itemId org.elastic4play.controllers.DBListCtrl.updateItem(itemId)
POST /api/list/:listName org.elastic4play.controllers.DBListCtrl.addItem(listName)
GET /api/list/:listName org.elastic4play.controllers.DBListCtrl.listItems(listName)


GET /api/user/current controllers.UserCtrl.currentUser()
POST /api/user/_search controllers.UserCtrl.find()
POST /api/user controllers.UserCtrl.create()
Expand Down
1 change: 1 addition & 0 deletions ui/app/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@
<script src="scripts/controllers/SettingsCtrl.js"></script>
<script src="scripts/controllers/StatisticsCtrl.js"></script>
<script src="scripts/controllers/admin/AdminCaseTemplatesCtrl.js"></script>
<script src="scripts/controllers/admin/AdminCustomFieldDialogCtrl.js"></script>
<script src="scripts/controllers/admin/AdminCustomFieldsCtrl.js"></script>
<script src="scripts/controllers/admin/AdminMetricsCtrl.js"></script>
<script src="scripts/controllers/admin/AdminObservablesCtrl.js"></script>
Expand Down
46 changes: 46 additions & 0 deletions ui/app/scripts/controllers/admin/AdminCustomFieldDialogCtrl.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
(function() {
'use strict';

angular.module('theHiveControllers').controller('AdminCustomFieldDialogCtrl',
function($scope, $uibModalInstance, ListSrv, NotificationSrv, customField) {
var self = this;
self.reference = {
types: ['string', 'number', 'boolean', 'date']
};

self.customField = customField;
self.customField.options = (customField.options || []).join('\n');

var onSuccess = function(data) {
$uibModalInstance.close(data);
};

var onFailure = function(response) {
NotificationSrv.error('AdminCustomFieldDialogCtrl', response.data, response.status);
};

self.saveField = function() {
var postData = _.pick(self.customField, 'name', 'title', 'label', 'description', 'type');
postData.options = _.isArray(self.customField.options) ? self.customField.options : self.customField.options.split('\n');

if(self.customField.id) {
ListSrv.update(
{'itemId': self.customField.id},
{'value': JSON.stringify(postData)},
onSuccess,
onFailure);
} else {
ListSrv.save(
{'listId': 'custom_fields'},
{'value': JSON.stringify(postData)},
onSuccess,
onFailure);
}
};

self.cancel = function() {
$uibModalInstance.dismiss();
}

});
})();
44 changes: 26 additions & 18 deletions ui/app/scripts/controllers/admin/AdminCustomFieldsCtrl.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
'use strict';

angular.module('theHiveControllers').controller('AdminCustomFieldsCtrl',
function($scope, ListSrv, CustomFieldsCacheSrv, NotificationSrv) {
function($scope, $uibModal, ListSrv, CustomFieldsCacheSrv, NotificationSrv) {
var self = this;

self.reference = {
Expand All @@ -24,31 +24,39 @@
'listId': 'custom_fields'
}, {}, function(response) {

self.customFields = _.values(response).filter(_.isString).map(function(item) {
return JSON.parse(item);
// self.customFields = _.values(response).filter(_.isString).map(function(item) {
// return JSON.parse(item);
// });

self.customFields = _.map(response.toJSON(), function(value, key) {
var obj = JSON.parse(value);
obj.id = key;

return obj;
});

}, function(response) {
NotificationSrv.error('AdminCustomfieldsCtrl', response.data, response.status);
});
};

self.addCustomField = function() {
ListSrv.save({
'listId': 'custom_fields'
}, {
'value': JSON.stringify(self.formData)
}, function() {
self.initCustomfields();

CustomFieldsCacheSrv.clearCache();
self.showFieldDialog = function(customField) {
var modalInstance = $uibModal.open({
templateUrl: 'views/partials/admin/custom-field-dialog.html',
controller: 'AdminCustomFieldDialogCtrl',
controllerAs: '$vm',
size: 'lg',
resolve: {
customField: angular.copy(customField) || {}
}
});

$scope.$emit('custom-fields:refresh');
},
function(response) {
NotificationSrv.error('AdminCustomfieldsCtrl', response.data, response.status);
});
};
modalInstance.result.then(function(data) {
self.initCustomfields();
CustomFieldsCacheSrv.clearCache();
$scope.$emit('custom-fields:refresh');
});
}

self.initCustomfields();
});
Expand Down
4 changes: 4 additions & 0 deletions ui/app/scripts/services/ListSrv.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@
},
add: {
method: 'PUT'
},
update: {
url: './api/list/:itemId',
method: 'PATCH',
}
});
});
Expand Down
7 changes: 4 additions & 3 deletions ui/app/styles/main.css
Original file line number Diff line number Diff line change
Expand Up @@ -260,8 +260,9 @@ ul.observable-reports-summary li {
padding: 20px 10px 10px 10px;
}

.case-metrics dt {
width: 300px !important;
.case-metrics dt,
.case-custom-fields dt {
width: 200px !important;
}

.scrollable {
Expand Down Expand Up @@ -495,7 +496,7 @@ tags-input.input-sm .tags.focused {
}

footer.main-footer {
padding: 2px;
padding: 2px;
line-height: 40px;
}

Expand Down
34 changes: 18 additions & 16 deletions ui/app/views/directives/updatable-date.html
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<span ng-hide="updatable.updating" ng-init="active = false" ng-mouseenter="active = true" ng-mouseleave="active = false">
<span class="updatable-value" ng-bind="value | showDate" style="vertical-align:top"></span>
<span ng-if="value!==null && value !==''" style="vertical-align:top" class="updatable-value" >{{value | showDate}}</span>
<span ng-if="value===null || value ===''" style="vertical-align: top; white-space: pre-wrap" class="updatable-value text-warning"><em>Not Specified</em></span>
<small ng-show="active">
<a style="cursor: pointer;" target="_self" tooltip-popup-delay='500' uib-tooltip="edit">
<i class="glyphicon glyphicon-pencil" ng-click="edit()"></i>
Expand All @@ -8,20 +9,21 @@
<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>
</span>
<span ng-init="updatable.dropdownOpen=false" ng-show="updatable.updating">
<div class="form-inline">
<div class="form-group">
<div class="input-group">
<input class="input-datetime form-control input-sm" ng-click="dateNow=false" ng-model="humanDate" type="datetime"/>
<span uib-btn-checkbox="" class="btn btn-primary input-group-addon" ng-model="dateNow">now</span>
</div>
</div>
<div class="form-group">
<span class="btn" ng-click='update()' target="_self" tooltip-placement="top" tooltip-popup-delay='500' uib-tooltip="save">
<i class="text-success glyphicon glyphicon-ok"></i>

<form ng-submit="update()">
<div class="input-group input-group-sm">
<input class="input-datetime form-control input-sm" ng-click="dateNow=false" ng-model="humanDate" type="datetime"/>
<span class="input-group-btn">
<span uib-btn-checkbox="" class="btn btn-sm btn-primary" ng-model="dateNow">
Now
</span>
<button class="btn btn-sm btn-default" type="submit">
<i class="text-success glyphicon glyphicon-ok"></i>
</button>
<button class="btn btn-sm btn-default" type="button" ng-click="cancel()">
<i class="text-danger glyphicon glyphicon-remove"></i>
</button>
</span>
<span class="btn" ng-click='cancel()' target="_self" tooltip-placement="top" tooltip-popup-delay='500' uib-tooltip="cancel">
<i class="text-danger glyphicon glyphicon-remove"></i>
</span>
</div>
</div>
</div>
</form>
</span>
64 changes: 64 additions & 0 deletions ui/app/views/partials/admin/custom-field-dialog.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
<form class="form-horizontal" name="fieldsForm" ng-submit="$vm.saveField()" novalidate>
<div class="modal-header bg-primary">
<h3 class="modal-title">{{$vm.customField.id ? 'Update' : 'Add'}} custom field</h3>
</div>
<div class="modal-body">

<div class="form-group" ng-class="{ 'has-error' : fieldsForm.name.$invalid && !fieldsForm.name.$pristine }">
<label class="col-sm-2 control-label">
Name
<i class="fa fa-asterisk text-danger"></i>
</label>
<div class="col-sm-10">
<input class="form-control" name="name" ng-model="$vm.customField.name" placeholder="Ex: cvss, threatActor, businessRisk" required type="text">
<p class="help-block" ng-show="fieldsForm.name.$invalid && !fieldsForm.name.$pristine">This field is required.</p>
</div>
</div>
<div class="form-group" ng-class="{ 'has-error' : fieldsForm.label.$invalid && !fieldsForm.label.$pristine }">
<label class="col-sm-2 control-label">
Label
<i class="fa fa-asterisk text-danger"></i>
</label>
<div class="col-sm-10">
<input class="form-control" name="label" ng-model="$vm.customField.label" placeholder="Ex: CVSS, Threat actor, Business risk" required type="text">
<p class="help-block" ng-show="fieldsForm.label.$invalid && !fieldsForm.label.$pristine">This field is required.</p>
</div>
</div>

<div class="form-group" ng-class="{ 'has-error' : fieldsForm.description.$invalid && !fieldsForm.description.$pristine }">
<label class="col-sm-2 control-label">
Description
<i class="fa fa-asterisk text-danger"></i>
</label>
<div class="col-sm-10">
<input class="form-control" name="description" ng-model="$vm.customField.description" placeholder="A brief description of the custom field" required type="text">
<p class="help-block" ng-show="fieldsForm.description.$invalid && !fieldsForm.description.$pristine">This field is required.</p>
</div>
</div>
<div class="form-group" ng-class="{ 'has-error' : fieldsForm.type.$invalid && !fieldsForm.type.$pristine }">
<label class="col-sm-2 control-label">
Type
<i class="fa fa-asterisk text-danger"></i>
</label>
<div class="col-sm-10">
<select class="form-control" name="type" ng-model="$vm.customField.type"
ng-options="fieldType for fieldType in $vm.reference.types"
placeholder="Field's type" required></select>
<p class="help-block" ng-show="fieldsForm.type.$invalid && !fieldsForm.type.$pristine">This field is required.</p>
</div>
</div>

<div class="form-group">
<label class="col-sm-2 control-label">
Possible values
</label>
<div class="col-sm-10">
<textarea class="form-control" name="options" ng-model="$vm.customField.options" rows="5" placeholder="Possible values, one per line" type="text"></textarea>
</div>
</div>
</div>
<div class="modal-footer text-left">
<button class="btn btn-default" ng-click="$vm.cancel()" type="button">Cancel</button>
<button class="btn btn-primary pull-right" ng-disabled="fieldsForm.$invalid" type="submit">Save field</button>
</div>
</form>
62 changes: 19 additions & 43 deletions ui/app/views/partials/admin/custom-fields.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,44 +3,8 @@
<h3 class="box-title">Case custom fields ({{$vm.customFields.length}})</h3>
</div>
<div class="box-body">
<form name="fieldsForm" ng-submit="$vm.addCustomField()">
<div class="row">
<div class="col-sm-4">
<div class="form-group">
<label>Name</label>
<input class="form-control" ng-model="$vm.formData.name" placeholder="Field's name" required type="text">
</div>
<div class="form-group">
<label>Label</label>
<input class="form-control" ng-model="$vm.formData.label" placeholder="Field's label" required type="text">
</div>
</div>

<div class="col-sm-4">
<div class="form-group">
<label>Description</label>
<input class="form-control" ng-model="$vm.formData.description" placeholder="A brief description of the custom field" type="text">
</div>
<div class="form-group">
<label>Type</label>
<!-- <input class="form-control" ng-model="$vm.formData.type" placeholder="Field's type" required type="text"> -->
<select class="form-control" ng-model="$vm.formData.type"
ng-options="fieldType for fieldType in $vm.reference.types"
placeholder="Field's type"></select>
</div>
</div>


<div class="form-group col-sm-4">
<label>Options</label>
<textarea class="form-control" ng-model="$vm.formData.options" rows="5" placeholder="Possible values, one per line" type="text"></textarea>
</div>
</div>
<div class="text-right">
<button class="btn btn-primary" type="submit" ng-disabled="fieldsForm.$invalid">Add custom field</button>
</div>
</form>
<hr>
<button class="btn btn-sm btn-primary" type="button" ng-click="$vm.showFieldDialog({})">Add custom field</button>

<div class="row mt-xs">
<div class="col-md-12" ng-if="$vm.customFields.length === 0">
Expand All @@ -50,18 +14,30 @@ <h3 class="box-title">Case custom fields ({{$vm.customFields.length}})</h3>
<table class="table table-striped">
<thead>
<tr>
<th class="col-md-3">Name</th>
<th class="col-md-3">Label</th>
<th class="col-md-3">Type</th>
<th width="80">Type</th>
<th width="250">Name</th>
<th width="250">Label</th>
<th>Description</th>
<th width="200">Options</th>
<th width="200">Actions</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="field in $vm.customFields">
<td>{{field.name}}</td>
<tr ng-repeat="field in $vm.customFields | orderBy:'name'">
<td align="center">
<span class="label label-default">{{field.type | uppercase}}</span>
</td>
<td><a href ng-click="$vm.showFieldDialog(field)">{{field.name}}</a></td>
<td>{{field.label}}</td>
<td><span class="label label-default">{{field.type | uppercase}}</span></td>
<td>{{field.description || 'N/A'}}</td>
<td ng-if="field.options.length === 0">
<em>None</em>
</td>
<td ng-if="field.options.length > 0">
<ul class="list list-unstyled" ng-repeat="option in field.options track by $index">
<li>{{option}}</li>
</ul>
</td>
</tr>
</tbody>
</table>
Expand Down
2 changes: 1 addition & 1 deletion ui/app/views/partials/admin/report-template-dialog.html
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,6 @@ <h3 class="modal-title">{{vm.reportTemplate.id ? 'Update' : 'Add'}} report templ
</div>
<div class="modal-footer text-left">
<button class="btn btn-default" ng-click="vm.cancel()" type="button">Cancel</button>
<button class="btn btn-primary pull-right" ng-disabled="taskForm.$invalid" type="submit">Save template</button>
<button class="btn btn-primary pull-right" ng-disabled="tplForm.$invalid" type="submit">Save template</button>
</div>
</form>
2 changes: 1 addition & 1 deletion ui/app/views/partials/case/case.details.html
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ <h4 class="vpad10 text-primary">Basic information</h4>
</dd>
</dl>
</div>
<div class="col-md-5 case-metrics">
<div class="col-md-5">

<ng-include src="'views/partials/case/details/custom.fields.html'"></ng-include>
<ng-include src="'views/partials/case/details/metrics.html'"></ng-include>
Expand Down

0 comments on commit 6355b90

Please sign in to comment.