Skip to content

Commit

Permalink
#1670 Add a UpdatableTagList component to include selection of taxono…
Browse files Browse the repository at this point in the history
…my tags
  • Loading branch information
nadouani committed Jan 27, 2021
1 parent 909a33a commit a87cdea
Show file tree
Hide file tree
Showing 7 changed files with 253 additions and 1 deletion.
3 changes: 3 additions & 0 deletions frontend/app/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,7 @@
<script src="scripts/directives/updatableDate.js"></script>
<script src="scripts/directives/updatableSelect.js"></script>
<script src="scripts/directives/updatableSimpleText.js"></script>
<script src="scripts/directives/updatableTagList.js"></script>
<script src="scripts/directives/updatableTags.js"></script>
<script src="scripts/directives/updatableText.js"></script>
<script src="scripts/directives/updatableUser.js"></script>
Expand All @@ -276,6 +277,7 @@
<script src="scripts/filters/sha256.js"></script>
<script src="scripts/filters/shortDate.js"></script>
<script src="scripts/filters/showDate.js"></script>
<script src="scripts/filters/tag-value.js"></script>
<script src="scripts/filters/urlencode.js"></script>
<script src="scripts/services/AnalyzerInfoSrv.js"></script>
<script src="scripts/services/api/AlertingSrv.js"></script>
Expand All @@ -297,6 +299,7 @@
<script src="scripts/services/api/ProfileSrv.js"></script>
<script src="scripts/services/api/TagSrv.js"></script>
<script src="scripts/services/api/TaskLogSrv.js"></script>
<script src="scripts/services/api/TaxonomyCacheSrv.js"></script>
<script src="scripts/services/api/TaxonomySrv.js"></script>
<script src="scripts/services/api/UiSettingsSrv.js"></script>
<script src="scripts/services/api/UserSrv.js"></script>
Expand Down
91 changes: 91 additions & 0 deletions frontend/app/scripts/directives/updatableTagList.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
(function() {
'use strict';
angular.module('theHiveDirectives')
.controller('UpdatableTagListModalCtrl', function($uibModalInstance, taxonomies) {
var self = this;

this.taxonomies = angular.copy(taxonomies);

this.formData = {
selectedTaxonomy: null,
selectedTags: null
};

this.addSelectedTags = function() {
if (!self.formData.selectedTaxonomy) {
return;
}

var selection = _.filter(self.formData.selectedTaxonomy.tags, function(tag) {
return tag.selected;
});

if (selection.length === 0) {
return;
}

$uibModalInstance.close(selection);
};

this.cancel = function() {
$uibModalInstance.dismiss();
};
})
.directive('updatableTagList', function(UtilsSrv, $uibModal, $filter, NotificationSrv, TaxonomyCacheSrv) {
return {
restrict: 'E',
link: UtilsSrv.updatableLink,
templateUrl: 'views/directives/updatable-tag-list.html',
scope: {
value: '=?',
onUpdate: '&',
active: '=?',
source: '=',
clearable: '<?'
},
controllerAs: '$cmp',
controller: function($scope) {
this.state = {
type: null,
};

this.fromLibrary = function() {
this.state.type = 'library';

var modalInstance = $uibModal.open({
controller: 'UpdatableTagListModalCtrl',
controllerAs: '$modal',
animation: true,
templateUrl: 'views/directives/updatable-tag-list-modal.html',
size: 'lg',
resolve: {
taxonomies: function() {
return TaxonomyCacheSrv.all();
}
}
});

modalInstance.result
.then(function(selectedTags) {
var filterFn = $filter('tagValue'),
tags = [];

_.each(selectedTags, function(tag) {
tags.push({
text: filterFn(tag)
});
});

$scope.value = $scope.value.concat(tags);
})
.catch(function(err) {
if (err && !_.isString(err)) {
NotificationSrv.error('Tag selection', err.data, err.status);
}
});
};

}
};
});
})();
18 changes: 18 additions & 0 deletions frontend/app/scripts/filters/tag-value.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
(function() {
'use strict';

angular.module('theHiveFilters').filter('tagValue', function () {
return function (tag) {
if (!tag) {
return '';
}

return _.without([
tag.namespace,
':',
tag.predicate,
tag.value ? ("=\"" + tag.value + "\"") : null
], null).join('');
};
});
})();
50 changes: 50 additions & 0 deletions frontend/app/scripts/services/api/TaxonomyCacheSrv.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
(function() {
'use strict';
angular.module('theHiveServices')
.service('TaxonomyCacheSrv', function($http, $q, QuerySrv) {
var self = this;

this.cache = null;

this.list = function() {
return QuerySrv.call('v1', [
{ _name: 'listTaxonomy' }
], {
name:'list-taxonomies'
}, {
name: 'filter',
_field: 'enabled',
_value: true
});
};

this.clearCache = function() {
self.cache = null;
};

this.getCache = function(name) {
return self.cache[name];
};

this.all = function(reload) {
var deferred = $q.defer();

if (self.cache === null || reload === true) {
self.list()
.then(function(response) {
self.cache = {};

_.each(response, function(taxonomy) {
self.cache[taxonomy.namespace] = taxonomy;
});

deferred.resolve(self.cache);
});
} else {
deferred.resolve(self.cache);
}

return deferred.promise;
};
});
})();
53 changes: 53 additions & 0 deletions frontend/app/views/directives/updatable-tag-list-modal.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<form name="tagsForm" ng-submit="$modal.addSelectedTags()" novalidate>
<div class="modal-header bg-primary">
<h3 class="modal-title">Select tags from library</h3>
</div>
<div class="modal-body">
<div class="form-group" ng-class="{ 'has-error' : tagsForm.taxonomy.$invalid && !tagsForm.taxonomy.$pristine }">
<label>
Taxonomy
<i class="fa fa-asterisk text-danger"></i>
</label>
<select class="form-control" name="taxonomy" ng-model="$modal.formData.selectedTaxonomy"
ng-options="taxonomy as taxonomy.namespace for taxonomy in $modal.taxonomies" required>
<option value="" disabled selected>-- Select Taxonomy --</option>
</select>
<p class="help-block" ng-show="$modal.formData.selectedTaxonomy">{{$modal.formData.selectedTaxonomy.description}}</p>
<p class="help-block" ng-show="tagsForm.taxonomy.$invalid && !tagsForm.taxonomy.$pristine">This field is required.</p>
</div>

<div class="form-group" ng-class="{ 'has-error' : tagsForm.tags.$invalid && !tagsForm.tags.$pristine }" ng-if="$modal.formData.selectedTaxonomy">
<label>
Tags
<i class="fa fa-asterisk text-danger"></i>
</label>
<div>
<table class="table table-striped">
<tbody>
<tr ng-repeat="tag in $modal.formData.selectedTaxonomy.tags">
<td>
<div class="checkbox mv-0">
<label class="center-block">
<input type="checkbox" ng-model="tag.selected">
<span class="label">
<tag value="tag"></tag>
</span>
</label>
</div>
</td>
<td width="10">
<span ng-if="::tag.description" uib-tooltip="{{::tag.description}}" tooltip-placement="left">
<i class="fa fa-question-circle"></i>
</span>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<div class="modal-footer">
<button class="btn btn-default pull-left" type="button" ng-click="$modal.cancel()">Cancel</button>
<button class="btn btn-primary pull-right" type="submit" ng-disabled="tagsForm.$invalid">Add Selected tags</button>
</div>
</form>
37 changes: 37 additions & 0 deletions frontend/app/views/directives/updatable-tag-list.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<div class="updatable-input updatable-input-tags-list">
<span class="updatable-input-value-wrapper" ng-hide="updatable.updating" ng-click="edit()"
ng-class="{'tags-list flexwrap': value.length > 0}">
<span class="updatable-value text-warning" ng-show="!value || value.length === 0"><em>Not Specified</em></span>

<span ng-repeat="tag in value" class="label label-primary mb-xxxs mr-xxxs">{{tag.text}}</span>

<small class="updatable-input-icon" ng-class="{'lg': value.length > 0}">
<i class="glyphicon glyphicon-pencil"></i>
</small>
</span>

<span ng-show="updatable.updating">
<div class="form-group">
<tags-input class="ti-input-sm" min-length="2" ng-model="value" placeholder="Add labels" replace-spaces-with-dashes="false">
<auto-complete ng-if="source" min-length="3" debounce-delay="400" source="source($query)"></auto-complete>
</tags-input>
</div>
<div class="btn-group btn-group-sm">
<button type="button" class="btn btn-sm btn-default" ng-click='update()'>
<i class="text-success glyphicon glyphicon-ok"></i>
</button>
<button type="button" class="btn btn-sm btn-default" ng-click='cancel()'>
<i class="text-danger glyphicon glyphicon-remove"></i>
</button>
<button class="btn btn-sm btn-default" type="button" ng-click="clear()" ng-if="clearable === true">
<i class="text-danger glyphicon glyphicon-erase"></i>
</button>
</div>

<div class="btn-group btn-group-sm pull-right">
<button class="btn btn-sm btn-default" type="button" ng-click="$cmp.fromLibrary()">
<i class="glyphicon glyphicon-plus"></i> Add from Library
</button>
</div>
</span>
</div>
2 changes: 1 addition & 1 deletion frontend/app/views/partials/case/case.details.html
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ <h4 class="vpad10 text-primary">Basic Information</h4>
<dl class="dl-horizontal">
<dt class="pull-left">Tags</dt>
<dd ng-if="canEdit">
<updatable-tags on-update="updateField('tags', getTags(newValue))" value="caze.tags" source="getCaseTags"></updatable-tags>
<updatable-tag-list on-update="updateField('tags', getTags(newValue))" value="caze.tags" source="getCaseTags"></updatable-tag-list>
</dd>
<dd ng-if="!canEdit">
<tag-list data="caze.tags"></tag-list>
Expand Down

0 comments on commit a87cdea

Please sign in to comment.