[Feature] 资产列表标签搜索

pull/968/head
ibuler 2018-01-26 14:47:10 +08:00
parent 7433327d75
commit cb902362b5
8 changed files with 140 additions and 35 deletions

View File

@ -30,12 +30,13 @@ from . import serializers
from .tasks import update_asset_hardware_info_manual, test_admin_user_connectability_manual, \ from .tasks import update_asset_hardware_info_manual, test_admin_user_connectability_manual, \
test_asset_connectability_manual, push_system_user_to_cluster_assets_manual, \ test_asset_connectability_manual, push_system_user_to_cluster_assets_manual, \
test_system_user_connectability_manual test_system_user_connectability_manual
from .utils import LabelFilter
logger = get_logger(__file__) logger = get_logger(__file__)
class AssetViewSet(CustomFilterMixin, BulkModelViewSet): class AssetViewSet(CustomFilterMixin, LabelFilter, BulkModelViewSet):
""" """
API endpoint that allows Asset to be viewed or edited. API endpoint that allows Asset to be viewed or edited.
""" """

View File

@ -5,7 +5,6 @@ from django.utils.translation import gettext_lazy as _
from .models import Cluster, Asset, AssetGroup, AdminUser, SystemUser, Label from .models import Cluster, Asset, AssetGroup, AdminUser, SystemUser, Label
from common.utils import validate_ssh_private_key, ssh_pubkey_gen, ssh_key_gen, get_logger from common.utils import validate_ssh_private_key, ssh_pubkey_gen, ssh_key_gen, get_logger
logger = get_logger(__file__) logger = get_logger(__file__)
@ -19,10 +18,18 @@ class AssetCreateForm(forms.ModelForm):
] ]
widgets = { widgets = {
'groups': forms.SelectMultiple(attrs={'class': 'select2', 'data-placeholder': _('Select asset groups')}), 'groups': forms.SelectMultiple(attrs={
'cluster': forms.Select(attrs={'class': 'select2', 'data-placeholder': _('Select cluster')}), 'class': 'select2', 'data-placeholder': _('Select asset groups')
'admin_user': forms.Select(attrs={'class': 'select2', 'data-placeholder': _('Select admin user')}), }),
'labels': forms.Select(attrs={'class': 'select2', 'data-placeholder': _('Select labels')}), 'cluster': forms.Select(attrs={
'class': 'select2', 'data-placeholder': _('Select cluster')
}),
'admin_user': forms.Select(attrs={
'class': 'select2', 'data-placeholder': _('Select admin user')
}),
'labels': forms.SelectMultiple(attrs={
'class': 'select2', 'data-placeholder': _('Select labels')
}),
'port': forms.TextInput(), 'port': forms.TextInput(),
} }
help_texts = { help_texts = {
@ -40,9 +47,13 @@ class AssetCreateForm(forms.ModelForm):
raise forms.ValidationError(_("You need set a admin user if cluster not have")) raise forms.ValidationError(_("You need set a admin user if cluster not have"))
return self.cleaned_data['admin_user'] return self.cleaned_data['admin_user']
def save(self, commit=True): def is_valid(self):
print(self.cleaned_data) print(self.data)
return super().save(commit=commit) result = super().is_valid()
if not result:
print(self.errors)
print(self.cleaned_data)
return result
class AssetUpdateForm(forms.ModelForm): class AssetUpdateForm(forms.ModelForm):
@ -54,8 +65,19 @@ class AssetUpdateForm(forms.ModelForm):
'cabinet_pos', 'number', 'comment', 'admin_user', 'labels' 'cabinet_pos', 'number', 'comment', 'admin_user', 'labels'
] ]
widgets = { widgets = {
'groups': forms.SelectMultiple(attrs={'class': 'select2', 'data-placeholder': _('Select asset groups')}), 'groups': forms.SelectMultiple(attrs={
'admin_user': forms.Select(attrs={'class': 'select2', 'data-placeholder': _("Default using cluster admin user")}) 'class': 'select2', 'data-placeholder': _('Select asset groups')
}),
'cluster': forms.Select(attrs={
'class': 'select2', 'data-placeholder': _('Select cluster')
}),
'admin_user': forms.Select(attrs={
'class': 'select2', 'data-placeholder': _('Select admin user')
}),
'labels': forms.SelectMultiple(attrs={
'class': 'select2', 'data-placeholder': _('Select labels')
}),
'port': forms.TextInput(),
} }
help_texts = { help_texts = {
'hostname': '* required', 'hostname': '* required',
@ -72,9 +94,9 @@ class AssetUpdateForm(forms.ModelForm):
raise forms.ValidationError(_("You need set a admin user if cluster not have")) raise forms.ValidationError(_("You need set a admin user if cluster not have"))
return self.cleaned_data['admin_user'] return self.cleaned_data['admin_user']
def save(self, commit=True): def is_valid(self):
print(self.cleaned_data) print(self.data)
return super().save(commit=commit) return super().is_valid()
class AssetBulkUpdateForm(forms.ModelForm): class AssetBulkUpdateForm(forms.ModelForm):

View File

@ -32,25 +32,31 @@
<div class="hr-line-dashed"></div> <div class="hr-line-dashed"></div>
<h3>{% trans 'Labels' %}</h3> <h3>{% trans 'Labels' %}</h3>
<div class="form-group"> <div class="form-group {% if form.errors.labels %} has-error {% endif %}">
<label for="{{ form.labels.id_for_label }}" class="col-md-2 control-label">{% trans 'Labels' %}</label> <label for="{{ form.labels.id_for_label }}" class="col-md-2 control-label">{% trans 'Labels' %}</label>
<div class="col-md-9"> <div class="col-md-9">
<select name="labels" class="select2" data-placeholder="Select labels" style="width: 100%" multiple="" tabindex="4" id="{{ form.labels.id_for_label }}"> <select name="labels" class="select2 labels" data-placeholder="Select labels" style="width: 100%" multiple="" tabindex="4" id="{{ form.labels.id_for_label }}">
{% for name, labels in form.labels.field.queryset|group_labels %} {% for name, labels in form.labels.field.queryset|group_labels %}
<optgroup label="{{ name }}"> <optgroup label="{{ name }}">
{% for label in labels %} {% for label in labels %}
{% if label in form.labels.initial %} {% if label in form.labels.initial %}
<option value="{{ label.id }}" selected>{{ label.name }}:{{ label.value }}</option> <option value="{{ label.id }}" selected>{{ label.value }}</option>
{% else %} {% else %}
<option value="{{ label.id }}">{{ label.name }}:{{ label.value }}</option> <option value="{{ label.id }}">{{ label.value }}</option>
{% endif %} {% endif %}
{% endfor %} {% endfor %}
</optgroup> </optgroup>
{% endfor %} {% endfor %}
</select> </select>
{% if form.errors.labels %}
{% for e in form.errors.labels %}
<div class="help-block">{{ e }}</div>
{% endfor %}
{% endif %}
</div> </div>
</div> </div>
<div class="hr-line-dashed"></div> <div class="hr-line-dashed"></div>
<h3>{% trans 'Other' %}</h3> <h3>{% trans 'Other' %}</h3>
{% bootstrap_field form.comment layout="horizontal" %} {% bootstrap_field form.comment layout="horizontal" %}
@ -67,11 +73,20 @@
{% endblock %} {% endblock %}
{% block custom_foot_js %} {% block custom_foot_js %}
<script> <script>
$(document).ready(function () { function format(item) {
$('.select2').select2({ var group = item.element.parentElement.label;
allowClear: true return group + ':' + item.text;
}); }
})
</script> $(document).ready(function () {
$('.select2').select2({
allowClear: true
});
$(".labels").select2({
allowClear: true,
templateSelection: format
});
})
</script>
{% endblock %} {% endblock %}

View File

@ -23,6 +23,14 @@
{% block table_container %} {% block table_container %}
<div class="uc pull-left m-r-5"><a href="{% url "assets:asset-create" %}" class="btn btn-sm btn-primary"> {% trans "Create asset" %} </a></div> <div class="uc pull-left m-r-5"><a href="{% url "assets:asset-create" %}" class="btn btn-sm btn-primary"> {% trans "Create asset" %} </a></div>
<div class="btn-group" style="float: right">
<button data-toggle="dropdown" class="btn btn-default btn-sm dropdown-toggle">{% trans 'Label' %} <span class="caret"></span></button>
<ul class="dropdown-menu labels">
{% for label in labels %}
<li><a style="font-weight: bolder">{{ label.name }}:{{ label.value }}</a></li>
{% endfor %}
</ul>
</div>
<table class="table table-striped table-bordered table-hover " id="asset_list_table" > <table class="table table-striped table-bordered table-hover " id="asset_list_table" >
<thead> <thead>
<tr> <tr>
@ -114,6 +122,20 @@ function initTable() {
$(document).ready(function(){ $(document).ready(function(){
initTable(); initTable();
$(".select2").select2();
})
.on('click', '.labels li', function () {
var val = $(this).text();
{#var origin_val = $("#asset_list_table_filter input").val();#}
{#var new_val;#}
{#if (origin_val === "") {#}
{# new_val = val;#}
{# } else { #}
{# new_val = origin_val + " " + val;#}
{# } #}
$("#asset_list_table_filter input").val(val);
{#$('#asset_list_table').DataTable().search(val).draw();#}
jumpserver.table.search(val).draw();
}) })
.on('click', '.btn_export', function () { .on('click', '.btn_export', function () {
var $data_table = $('#asset_list_table').DataTable(); var $data_table = $('#asset_list_table').DataTable();

View File

@ -1,8 +1,13 @@
# ~*~ coding: utf-8 ~*~ # ~*~ coding: utf-8 ~*~
# #
from collections import defaultdict from collections import defaultdict
from functools import reduce
import operator
from django.db.models import Q
from common.utils import get_object_or_none from common.utils import get_object_or_none
from .models import Asset, SystemUser from .models import Asset, SystemUser, Label
def get_assets_by_id_list(id_list): def get_assets_by_id_list(id_list):
@ -27,3 +32,23 @@ def check_assets_have_system_user(assets, system_users):
if asset.cluster not in clusters: if asset.cluster not in clusters:
errors[asset].append(system_user) errors[asset].append(system_user)
return errors return errors
class LabelFilter:
def filter_queryset(self, queryset):
query_keys = self.request.query_params.keys()
all_label_keys = Label.objects.values_list('name', flat=True)
valid_keys = set(all_label_keys) & set(query_keys)
labels_query = {}
for key in valid_keys:
labels_query[key] = self.request.query_params.get(key)
conditions = []
for k, v in labels_query.items():
query = {'labels__name': k, 'labels__value': v}
conditions.append(query)
if conditions:
for kwargs in conditions:
queryset = queryset.filter(**kwargs)
return queryset

View File

@ -27,7 +27,7 @@ from common.mixins import JSONResponseMixin
from common.utils import get_object_or_none, get_logger, is_uuid from common.utils import get_object_or_none, get_logger, is_uuid
from common.const import create_success_msg, update_success_msg from common.const import create_success_msg, update_success_msg
from .. import forms from .. import forms
from ..models import Asset, AssetGroup, AdminUser, Cluster, SystemUser from ..models import Asset, AssetGroup, AdminUser, Cluster, SystemUser, Label
from ..hands import AdminUserRequiredMixin from ..hands import AdminUserRequiredMixin
@ -48,6 +48,7 @@ class AssetListView(AdminUserRequiredMixin, TemplateView):
'app': _('Assets'), 'app': _('Assets'),
'action': _('Asset list'), 'action': _('Asset list'),
'system_users': SystemUser.objects.all(), 'system_users': SystemUser.objects.all(),
'labels': Label.objects.all().order_by('name'),
} }
kwargs.update(context) kwargs.update(context)
return super().get_context_data(**kwargs) return super().get_context_data(**kwargs)
@ -72,12 +73,13 @@ class AssetCreateView(AdminUserRequiredMixin, SuccessMessageMixin, CreateView):
template_name = 'assets/asset_create.html' template_name = 'assets/asset_create.html'
success_url = reverse_lazy('assets:asset-list') success_url = reverse_lazy('assets:asset-list')
def form_valid(self, form): # def form_valid(self, form):
asset = form.save() # print("form valid")
asset.created_by = self.request.user.username or 'Admin' # asset = form.save()
asset.date_created = timezone.now() # asset.created_by = self.request.user.username or 'Admin'
asset.save() # asset.date_created = timezone.now()
return super().form_valid(form) # asset.save()
# return super().form_valid(form)
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = { context = {

View File

@ -338,4 +338,6 @@ div.dataTables_wrapper div.dataTables_filter {
.nav.nav-tabs li.active a { .nav.nav-tabs li.active a {
border: none; border: none;
} }

View File

@ -383,7 +383,22 @@ jumpserver.initServerSideDataTable = function (options) {
} }
if (data.search !== null) { if (data.search !== null) {
var search_val = data.search.value; var search_val = data.search.value;
data.search = search_val; var search_list = search_val.split(" ");
var search_attr = {};
var search_raw = [];
search_list.map(function (val, index) {
var kv = val.split(":");
if (kv.length === 2) {
search_attr[kv[0]] = kv[1]
} else {
search_raw.push(kv)
}
});
data.search = search_raw.join("");
$.each(search_attr, function (k, v) {
data[k] = v
})
} }
if (data.order !== null && data.order.length === 1) { if (data.order !== null && data.order.length === 1) {
var col = data.order[0].column; var col = data.order[0].column;
@ -446,6 +461,7 @@ jumpserver.initServerSideDataTable = function (options) {
} }
}); });
jumpserver.table = table;
return table; return table;
}; };