mirror of https://github.com/jumpserver/jumpserver
557 lines
19 KiB
HTML
557 lines
19 KiB
HTML
{% extends 'base.html' %}
|
|
{% load static %}
|
|
{% load i18n %}
|
|
|
|
{% block custom_head_css_js %}
|
|
<link href="{% static 'css/plugins/ztree/awesomeStyle/awesome.css' %}" rel="stylesheet">
|
|
<script type="text/javascript" src="{% static 'js/plugins/ztree/jquery.ztree.all.min.js' %}"></script>
|
|
<script src="{% static 'js/jquery.form.min.js' %}"></script>
|
|
<style type="text/css">
|
|
div#rMenu {
|
|
position:absolute;
|
|
visibility:hidden;
|
|
text-align: left;
|
|
top: 100%;
|
|
left: 0;
|
|
z-index: 1000;
|
|
float: left;
|
|
padding: 5px 0;
|
|
margin: 2px 0 0;
|
|
list-style: none;
|
|
background-clip: padding-box;
|
|
}
|
|
div#rMenu li{
|
|
margin: 1px 0;
|
|
cursor: pointer;
|
|
{#list-style: none outside none;#}
|
|
}
|
|
.dropdown a:hover {
|
|
background-color: #f1f1f1
|
|
}
|
|
</style>
|
|
|
|
{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="wrapper wrapper-content">
|
|
<div class="row">
|
|
<div class="col-lg-3" id="split-left">
|
|
<div class="ibox float-e-margins">
|
|
<div class="ibox-content mailbox-content" style="padding-top: 0">
|
|
<div class="file-manager ">
|
|
<div id="assetTree" class="ztree">
|
|
</div>
|
|
|
|
<div class="clearfix"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-lg-9 animated fadeInRight" id="split-right">
|
|
<div class="tree-toggle">
|
|
<div class="btn btn-sm btn-primary tree-toggle-btn" onclick="toggle()">
|
|
<i class="fa fa-angle-left fa-x" id="toggle-icon"></i>
|
|
</div>
|
|
</div>
|
|
<div class="mail-box-header">
|
|
<div class="uc pull-left m-r-5"><a class="btn btn-sm btn-primary btn-create-asset"> {% trans "Create asset" %} </a></div>
|
|
<div class="html5buttons">
|
|
<div class="dt-buttons btn-group">
|
|
<a class="btn btn-default btn_import" data-toggle="modal" data-target="#asset_import_modal" tabindex="0">
|
|
<span>{% trans "Import" %}</span>
|
|
</a>
|
|
<a class="btn btn-default btn_export" tabindex="0">
|
|
<span>{% trans "Export" %}</span>
|
|
</a>
|
|
</div>
|
|
</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" style="width: 100%">
|
|
<thead>
|
|
<tr>
|
|
<th class="text-center"><input type="checkbox" class="ipt_check_all"></th>
|
|
<th class="text-center">{% trans 'Hostname' %}</th>
|
|
<th class="text-center">{% trans 'IP' %}</th>
|
|
<th class="text-center">{% trans 'Hardware' %}</th>
|
|
<th class="text-center">{% trans 'Active' %}</th>
|
|
<th class="text-center">{% trans 'Reachable' %}</th>
|
|
<th class="text-center">{% trans 'Action' %}</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
</tbody>
|
|
</table>
|
|
<div id="actions" class="hide">
|
|
<div class="input-group">
|
|
<select class="form-control m-b" style="width: auto" id="slct_bulk_update">
|
|
<option value="delete">{% trans 'Delete selected' %}</option>
|
|
<option value="update">{% trans 'Update selected' %}</option>
|
|
<option value="remove">{% trans 'Remove from this node' %}</option>
|
|
<option value="deactive">{% trans 'Deactive selected' %}</option>
|
|
<option value="active">{% trans 'Active selected' %}</option>
|
|
</select>
|
|
<div class="input-group-btn pull-left" style="padding-left: 5px;">
|
|
<button id='btn_bulk_update' style="height: 32px;" class="btn btn-sm btn-primary">
|
|
{% trans 'Submit' %}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div id="rMenu">
|
|
<ul class="dropdown-menu">
|
|
<li id="menu_asset_create" class="btn-create-asset" tabindex="-1"><a>{% trans 'Create asset' %}</a></li>
|
|
<li id="menu_asset_add" class="btn-add-asset" data-toggle="modal" data-target="#asset_list_modal" tabindex="0"><a>{% trans 'Add asset' %}</a></li>
|
|
<li class="divider"></li>
|
|
<li id="m_create" tabindex="-1" onclick="addTreeNode();"><a>{% trans 'Add node' %}</a></li>
|
|
<li id="m_del" tabindex="-1" onclick="editTreeNode();"><a>{% trans 'Rename node' %}</a></li>
|
|
<li class="divider"></li>
|
|
<li id="m_del" tabindex="-1" onclick="removeTreeNode();"><a>{% trans 'Delete node' %}</a></li>
|
|
</ul>
|
|
</div>
|
|
|
|
{% include 'assets/_asset_import_modal.html' %}
|
|
{% include 'assets/_asset_list_modal.html' %}
|
|
{% endblock %}
|
|
|
|
{% block custom_foot_js %}
|
|
<script>
|
|
var zTree, rMenu, asset_table, show = 0;
|
|
function initTable() {
|
|
var options = {
|
|
ele: $('#asset_list_table'),
|
|
columnDefs: [
|
|
{targets: 1, createdCell: function (td, cellData, rowData) {
|
|
{% url 'assets:asset-detail' pk=DEFAULT_PK as the_url %}
|
|
var detail_btn = '<a href="{{ the_url }}">' + cellData + '</a>';
|
|
$(td).html(detail_btn.replace('{{ DEFAULT_PK }}', rowData.id));
|
|
}},
|
|
{targets: 3, createdCell: function (td, cellData, rowData) {
|
|
$(td).html(rowData.hardware_info)
|
|
}},
|
|
{targets: 4, createdCell: function (td, cellData) {
|
|
if (!cellData) {
|
|
$(td).html('<i class="fa fa-times text-danger"></i>')
|
|
} else {
|
|
$(td).html('<i class="fa fa-check text-navy"></i>')
|
|
}
|
|
}},
|
|
{targets: 5, createdCell: function (td, cellData) {
|
|
if (cellData === 'Unknown'){
|
|
$(td).html('<i class="fa fa-circle text-warning"></i>')
|
|
} else if (!cellData) {
|
|
$(td).html('<i class="fa fa-circle text-danger"></i>')
|
|
} else {
|
|
$(td).html('<i class="fa fa-circle text-navy"></i>')
|
|
}
|
|
}},
|
|
{targets: 6, createdCell: function (td, cellData, rowData) {
|
|
var update_btn = '<a href="{% url "assets:asset-update" pk=DEFAULT_PK %}" class="btn btn-xs btn-info">{% trans "Update" %}</a>'.replace("{{ DEFAULT_PK }}", cellData);
|
|
var del_btn = '<a class="btn btn-xs btn-danger m-l-xs btn_asset_delete" data-uid="{{ DEFAULT_PK }}">{% trans "Delete" %}</a>'.replace('{{ DEFAULT_PK }}', cellData);
|
|
$(td).html(update_btn + del_btn)
|
|
}}
|
|
],
|
|
ajax_url: '{% url "api-assets:asset-list" %}',
|
|
columns: [
|
|
{data: "id"}, {data: "hostname" }, {data: "ip" },
|
|
{data: "cpu_cores"}, {data: "is_active", orderable: false },
|
|
{data: "is_connective", orderable: false}, {data: "id", orderable: false }
|
|
],
|
|
op_html: $('#actions').html()
|
|
};
|
|
asset_table = jumpserver.initServerSideDataTable(options);
|
|
return asset_table
|
|
}
|
|
|
|
|
|
function addTreeNode() {
|
|
hideRMenu();
|
|
var parentNode = zTree.getSelectedNodes()[0];
|
|
if (!parentNode){
|
|
return
|
|
}
|
|
var url = "{% url 'api-assets:node-children' pk=DEFAULT_PK %}".replace("{{ DEFAULT_PK }}", parentNode.id );
|
|
$.post(url, {}, function (data, status){
|
|
if (status === "success") {
|
|
var newNode = {
|
|
name: data["value"],
|
|
id: data["id"],
|
|
pId: parentNode.id
|
|
};
|
|
newNode.checked = zTree.getSelectedNodes()[0].checked;
|
|
zTree.addNodes(parentNode, 0, newNode);
|
|
} else {
|
|
alert("{% trans 'Create node failed' %}")
|
|
}
|
|
});
|
|
}
|
|
|
|
function removeTreeNode() {
|
|
hideRMenu();
|
|
var current_node = zTree.getSelectedNodes()[0];
|
|
if (!current_node){
|
|
return
|
|
}
|
|
|
|
if (current_node.children && current_node.children.length > 0) {
|
|
alert("{% trans 'Have child node, cancel' %}")
|
|
} else {
|
|
var url = "{% url 'api-assets:node-detail' pk=DEFAULT_PK %}".replace("{{ DEFAULT_PK }}", current_node.id );
|
|
$.ajax({
|
|
url: url,
|
|
method: "DELETE",
|
|
success: function () {
|
|
zTree.removeNode(current_node);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
function editTreeNode() {
|
|
hideRMenu();
|
|
var current_node = zTree.getSelectedNodes()[0];
|
|
if (!current_node){
|
|
return
|
|
}
|
|
zTree.editName(current_node);
|
|
}
|
|
|
|
|
|
function OnRightClick(event, treeId, treeNode) {
|
|
if (!treeNode && event.target.tagName.toLowerCase() !== "button" && $(event.target).parents("a").length === 0) {
|
|
zTree.cancelSelectedNode();
|
|
showRMenu("root", event.clientX, event.clientY);
|
|
} else if (treeNode && !treeNode.noR) {
|
|
zTree.selectNode(treeNode);
|
|
showRMenu("node", event.clientX, event.clientY);
|
|
}
|
|
}
|
|
|
|
function showRMenu(type, x, y) {
|
|
$("#rMenu ul").show();
|
|
{#if (type === "root") {#}
|
|
{# return#}
|
|
{# } else {#}
|
|
{# $("#m_del").show();#}
|
|
{# $("#m_check").show();#}
|
|
{# $("#m_unCheck").show();#}
|
|
{# }#}
|
|
x -= 220;
|
|
rMenu.css({"top":y+"px", "left":x+"px", "visibility":"visible"});
|
|
|
|
$("body").bind("mousedown", onBodyMouseDown);
|
|
}
|
|
|
|
function beforeClick(treeId, treeNode, clickFlag) {
|
|
return true;
|
|
}
|
|
|
|
function hideRMenu() {
|
|
if (rMenu) rMenu.css({"visibility": "hidden"});
|
|
$("body").unbind("mousedown", onBodyMouseDown);
|
|
}
|
|
|
|
function onBodyMouseDown(event){
|
|
if (!(event.target.id === "rMenu" || $(event.target).parents("#rMenu").length>0)) {
|
|
rMenu.css({"visibility" : "hidden"});
|
|
}
|
|
}
|
|
|
|
|
|
function onRename(event, treeId, treeNode, isCancel){
|
|
var url = "{% url 'api-assets:node-detail' pk=DEFAULT_PK %}".replace("{{ DEFAULT_PK }}", treeNode.id);
|
|
var data = {"value": treeNode.name};
|
|
if (isCancel){
|
|
return
|
|
}
|
|
APIUpdateAttr({
|
|
url: url,
|
|
body: JSON.stringify(data),
|
|
method: "PATCH"
|
|
})
|
|
}
|
|
|
|
function onSelected(event, treeNode) {
|
|
var url = asset_table.ajax.url();
|
|
url = setUrlParam(url, "node_id", treeNode.id);
|
|
setCookie('node_selected', treeNode.id);
|
|
asset_table.ajax.url(url);
|
|
asset_table.ajax.reload();
|
|
}
|
|
|
|
function selectQueryNode() {
|
|
var query_node_id = $.getUrlParam("node");
|
|
var cookie_node_id = getCookie('node_selected');
|
|
var node;
|
|
var node_id;
|
|
|
|
if (query_node_id !== null) {
|
|
node_id = query_node_id
|
|
} else if (cookie_node_id !== null) {
|
|
node_id = cookie_node_id;
|
|
}
|
|
|
|
node = zTree.getNodesByParam("id", node_id, null);
|
|
if (node){
|
|
zTree.selectNode(node[0]);
|
|
}
|
|
}
|
|
|
|
function initTree() {
|
|
var setting = {
|
|
view: {
|
|
dblClickExpand: false,
|
|
showLine: true
|
|
},
|
|
data: {
|
|
simpleData: {
|
|
enable: true
|
|
}
|
|
},
|
|
callback: {
|
|
onRightClick: OnRightClick,
|
|
beforeClick: beforeClick,
|
|
onRename: onRename,
|
|
onSelected: onSelected
|
|
}
|
|
};
|
|
|
|
var zNodes = [];
|
|
$.get("{% url 'api-assets:node-list' %}", function(data, status){
|
|
$.each(data, function (index, value) {
|
|
value["pId"] = value["parent"];
|
|
{#if (value["key"] === "0") {#}
|
|
value["open"] = true;
|
|
{# }#}
|
|
value["name"] = value["value"] + ' (' + value['assets_amount'] + ')'
|
|
});
|
|
zNodes = data;
|
|
$.fn.zTree.init($("#assetTree"), setting, zNodes);
|
|
zTree = $.fn.zTree.getZTreeObj("assetTree");
|
|
rMenu = $("#rMenu");
|
|
selectQueryNode();
|
|
});
|
|
}
|
|
|
|
function toggle() {
|
|
if (show === 0) {
|
|
$("#split-left").hide(500, function () {
|
|
$("#split-right").attr("class", "col-lg-12");
|
|
$("#toggle-icon").attr("class", "fa fa-angle-right fa-x");
|
|
show = 1;
|
|
});
|
|
} else {
|
|
$("#split-right").attr("class", "col-lg-9");
|
|
$("#toggle-icon").attr("class", "fa fa-angle-left fa-x");
|
|
$("#split-left").show(500);
|
|
show = 0;
|
|
}
|
|
}
|
|
|
|
$(document).ready(function(){
|
|
initTable();
|
|
initTree();
|
|
})
|
|
.on('click', '.labels li', function () {
|
|
var val = $(this).text();
|
|
$("#asset_list_table_filter input").val(val);
|
|
asset_table.search(val).draw();
|
|
})
|
|
.on('click', '.btn_export', function () {
|
|
var $data_table = $('#asset_list_table').DataTable();
|
|
var rows = $data_table.rows('.selected').data();
|
|
var assets = [];
|
|
$.each(rows, function (index, obj) {
|
|
assets.push(obj.id)
|
|
});
|
|
$.ajax({
|
|
url: "{% url "assets:asset-export" %}",
|
|
method: 'POST',
|
|
data: JSON.stringify({assets_id: assets}),
|
|
dataType: "json",
|
|
success: function (data, textStatus) {
|
|
window.open(data.redirect)
|
|
},
|
|
error: function () {
|
|
toastr.error('Export failed');
|
|
}
|
|
})
|
|
})
|
|
.on('click', '#btn_asset_import', function () {
|
|
var $form = $('#fm_asset_import');
|
|
$form.find('.help-block').remove();
|
|
function success (data) {
|
|
if (data.valid === false) {
|
|
$('<span />', {class: 'help-block text-danger'}).html(data.msg).insertAfter($('#id_assets'));
|
|
} else {
|
|
$('#id_created').html(data.created_info);
|
|
$('#id_created_detail').html(data.created.join(', '));
|
|
$('#id_updated').html(data.updated_info);
|
|
$('#id_updated_detail').html(data.updated.join(', '));
|
|
$('#id_failed').html(data.failed_info);
|
|
$('#id_failed_detail').html(data.failed.join(', '));
|
|
var $data_table = $('#asset_list_table').DataTable();
|
|
$data_table.ajax.reload();
|
|
}
|
|
}
|
|
$form.ajaxSubmit({success: success});
|
|
})
|
|
.on('click', '.btn-create-asset', function () {
|
|
var url = "{% url 'assets:asset-create' %}";
|
|
var nodes = zTree.getSelectedNodes();
|
|
var current_node;
|
|
if (nodes && nodes.length ===1 ){
|
|
current_node = nodes[0];
|
|
url += "?node_id=" + current_node.id;
|
|
}
|
|
window.open(url);
|
|
})
|
|
.on('click', '.btn_asset_delete', function () {
|
|
var $this = $(this);
|
|
var $data_table = $("#asset_list_table").DataTable();
|
|
var name = $(this).closest("tr").find(":nth-child(2)").children('a').html();
|
|
var uid = $this.data('uid');
|
|
var the_url = '{% url "api-assets:asset-detail" pk=DEFAULT_PK %}'.replace("{{ DEFAULT_PK }}", uid);
|
|
objectDelete($this, name, the_url);
|
|
setTimeout( function () {
|
|
$data_table.ajax.reload();
|
|
}, 3000);
|
|
})
|
|
.on('click', '#btn_bulk_update', function () {
|
|
var action = $('#slct_bulk_update').val();
|
|
var $data_table = $('#asset_list_table').DataTable();
|
|
var id_list = [];
|
|
$data_table.rows({selected: true}).every(function(){
|
|
id_list.push(this.data().id);
|
|
});
|
|
if (id_list.length === 0) {
|
|
return false;
|
|
}
|
|
var the_url = "{% url 'api-assets:asset-list' %}";
|
|
|
|
function doDeactive() {
|
|
var data = [];
|
|
$.each(id_list, function(index, object_id) {
|
|
var obj = {"pk": object_id, "is_active": false};
|
|
data.push(obj);
|
|
});
|
|
function success() {
|
|
asset_table.ajax.reload()
|
|
}
|
|
APIUpdateAttr({
|
|
url: the_url,
|
|
method: 'PATCH',
|
|
body: JSON.stringify(data),
|
|
success: success
|
|
});
|
|
}
|
|
function doActive() {
|
|
var data = [];
|
|
$.each(id_list, function(index, object_id) {
|
|
var obj = {"pk": object_id, "is_active": true};
|
|
data.push(obj);
|
|
});
|
|
function success() {
|
|
asset_table.ajax.reload()
|
|
}
|
|
APIUpdateAttr({
|
|
url: the_url,
|
|
method: 'PATCH',
|
|
body: JSON.stringify(data),
|
|
success: success
|
|
});
|
|
}
|
|
function doDelete() {
|
|
swal({
|
|
title: "{% trans 'Are you sure?' %}",
|
|
text: "{% trans 'This will delete the selected assets !!!' %}",
|
|
type: "warning",
|
|
showCancelButton: true,
|
|
confirmButtonColor: "#DD6B55",
|
|
confirmButtonText: "{% trans 'Confirm' %}",
|
|
closeOnConfirm: false
|
|
}, function() {
|
|
var success = function() {
|
|
var msg = "{% trans 'Asset Deleted.' %}";
|
|
swal("{% trans 'Asset Delete' %}", msg, "success");
|
|
$('#asset_list_table').DataTable().ajax.reload();
|
|
};
|
|
var fail = function() {
|
|
var msg = "{% trans 'Asset Deleting failed.' %}";
|
|
swal("{% trans 'Asset Delete' %}", msg, "error");
|
|
};
|
|
var url_delete = the_url + '?id__in=' + JSON.stringify(id_list);
|
|
APIUpdateAttr({
|
|
url: url_delete,
|
|
method: 'DELETE',
|
|
success: success,
|
|
error: fail
|
|
});
|
|
$data_table.ajax.reload();
|
|
jumpserver.checked = false;
|
|
});
|
|
}
|
|
function doUpdate() {
|
|
var id_list_string = id_list.join(',');
|
|
var url = "{% url 'assets:asset-bulk-update' %}?assets_id=" + id_list_string;
|
|
location.href = url
|
|
}
|
|
|
|
function doRemove() {
|
|
var current_node;
|
|
var nodes = zTree.getSelectedNodes();
|
|
if (nodes && nodes.length === 1) {
|
|
current_node = nodes[0]
|
|
} else {
|
|
return
|
|
}
|
|
|
|
var data = {
|
|
'assets': id_list
|
|
};
|
|
|
|
var success = function () {
|
|
asset_table.ajax.reload()
|
|
};
|
|
|
|
APIUpdateAttr({
|
|
'url': '/api/assets/v1/nodes/' + current_node.id + '/assets/remove/',
|
|
'method': 'PUT',
|
|
'body': JSON.stringify(data),
|
|
'success': success
|
|
})
|
|
}
|
|
switch(action) {
|
|
case 'deactive':
|
|
doDeactive();
|
|
break;
|
|
case 'delete':
|
|
doDelete();
|
|
break;
|
|
case 'update':
|
|
doUpdate();
|
|
break;
|
|
case 'active':
|
|
doActive();
|
|
break;
|
|
case 'remove':
|
|
doRemove();
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
});
|
|
</script>
|
|
|
|
{% endblock %} |