mirror of
https://github.com/netbox-community/netbox.git
synced 2025-12-26 07:07:46 -06:00
Initial push to public repo
This commit is contained in:
224
netbox/project-static/css/base.css
Normal file
224
netbox/project-static/css/base.css
Normal file
@@ -0,0 +1,224 @@
|
||||
/* Layout */
|
||||
* {
|
||||
margin: 0;
|
||||
}
|
||||
html, body {
|
||||
height: 100%;
|
||||
}
|
||||
body {
|
||||
padding-top: 70px;
|
||||
}
|
||||
.container {
|
||||
width: 1340px;
|
||||
}
|
||||
.wrapper {
|
||||
min-height: 100%;
|
||||
height: auto !important;
|
||||
margin: 0 auto -61px; /* the bottom margin is the negative value of the footer's height */
|
||||
padding-bottom: 30px;
|
||||
}
|
||||
.footer, .push {
|
||||
height: 60px; /* .push must be the same height as .footer */
|
||||
}
|
||||
.footer {
|
||||
background-color: #f5f5f5;
|
||||
border-top: 1px solid #d0d0d0;
|
||||
}
|
||||
footer p {
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
/* Forms */
|
||||
label {
|
||||
font-weight: normal;
|
||||
}
|
||||
label.required {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* Tables */
|
||||
th.pk, td.pk {
|
||||
width: 30px;
|
||||
}
|
||||
|
||||
|
||||
/* Paginator */
|
||||
nav ul.pagination {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
|
||||
/* Racks */
|
||||
div.rack_header {
|
||||
margin-left: 36px;
|
||||
text-align: center;
|
||||
width: 200px;
|
||||
}
|
||||
ul.rack_legend {
|
||||
float: left;
|
||||
list-style-type: none;
|
||||
margin-right: 6px;
|
||||
padding: 0;
|
||||
width: 30px;
|
||||
}
|
||||
ul.rack_legend li {
|
||||
color: #c0c0c0;
|
||||
display: block;
|
||||
font-size: 10px;
|
||||
height: 20px;
|
||||
overflow: hidden;
|
||||
padding: 5px 0;
|
||||
text-align: right;
|
||||
}
|
||||
div.rack_frame {
|
||||
float: left;
|
||||
position: relative;
|
||||
}
|
||||
ul.rack {
|
||||
border: 2px solid #404040;
|
||||
float: left;
|
||||
list-style-type: none;
|
||||
padding: 0;
|
||||
position: absolute;
|
||||
width: 200px;
|
||||
}
|
||||
ul.rack li {
|
||||
display: block;
|
||||
font-size: 13px;
|
||||
height: 20px;
|
||||
overflow: hidden;
|
||||
text-align: center;
|
||||
}
|
||||
ul.rack_empty li {
|
||||
background-color: #f7f7f7;
|
||||
border-bottom: 1px solid #dddddd;
|
||||
height: 20px;
|
||||
}
|
||||
ul.rack li.empty:last-child {
|
||||
border-bottom: 0;
|
||||
}
|
||||
ul.rack_far_face {
|
||||
z-index: 100;
|
||||
}
|
||||
ul.rack_near_face {
|
||||
z-index: 200;
|
||||
}
|
||||
ul.rack li.h2u { height: 40px; }
|
||||
ul.rack li.h2u a, ul.rack li.h2u span { padding: 10px 0; }
|
||||
ul.rack li.h3u { height: 60px; }
|
||||
ul.rack li.h3u a, ul.rack li.h3u span { padding: 20px 0; }
|
||||
ul.rack li.h4u { height: 80px; }
|
||||
ul.rack li.h4u a, ul.rack li.h4u span { padding: 30px 0; }
|
||||
ul.rack li.h5u { height: 100px; }
|
||||
ul.rack li.h5u a, ul.rack li.h5u span { padding: 40px 0; }
|
||||
ul.rack li.h6u { height: 120px; }
|
||||
ul.rack li.h6u a, ul.rack li.h6u span { padding: 50px 0; }
|
||||
ul.rack li.h7u { height: 140px; }
|
||||
ul.rack li.h7u a, ul.rack li.h7u span { padding: 60px 0; }
|
||||
ul.rack li.h8u { height: 160px; }
|
||||
ul.rack li.h8u a, ul.rack li.h8u span { padding: 70px 0; }
|
||||
ul.rack li.h9u { height: 180px; }
|
||||
ul.rack li.h9u a, ul.rack li.h9u span { padding: 80px 0; }
|
||||
ul.rack li.h10u { height: 200px; }
|
||||
ul.rack li.h10u a, ul.rack li.h10u span { padding: 90px 0; }
|
||||
ul.rack li.h11u { height: 220px; }
|
||||
ul.rack li.h11u a, ul.rack li.h11u span { padding: 100px 0; }
|
||||
ul.rack li.h12u { height: 240px; }
|
||||
ul.rack li.h12u a, ul.rack li.h12u span { padding: 110px 0; }
|
||||
ul.rack li.h13u { height: 260px; }
|
||||
ul.rack li.h13u a, ul.rack li.h13u span { padding: 120px 0; }
|
||||
ul.rack li.h14u { height: 280px; }
|
||||
ul.rack li.h14u a, ul.rack li.h14u span { padding: 130px 0; }
|
||||
ul.rack li.h15u { height: 300px; }
|
||||
ul.rack li.h15u a, ul.rack li.h15u span { padding: 140px 0; }
|
||||
ul.rack li.h16u { height: 320px; }
|
||||
ul.rack li.h16u a, ul.rack li.h16u span { padding: 150px 0; }
|
||||
ul.rack li.occupied a {
|
||||
color: #ffffff;
|
||||
display: block;
|
||||
font-weight: bold;
|
||||
}
|
||||
ul.rack li.occupied a:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
ul.rack li.occupied span {
|
||||
display: block;
|
||||
}
|
||||
ul.rack_near_face li {
|
||||
border-bottom: 1px solid #e0e0e0;
|
||||
}
|
||||
ul.rack_near_face li.occupied {
|
||||
color: #474747;
|
||||
}
|
||||
ul.rack_far_face li.occupied {
|
||||
background: repeating-linear-gradient(
|
||||
45deg,
|
||||
#f7f7f7,
|
||||
#f7f7f7 7px,
|
||||
#f0f0f0 7px,
|
||||
#f0f0f0 14px
|
||||
);
|
||||
color: #303030;
|
||||
}
|
||||
ul.rack_far_face li.blocked {
|
||||
background: repeating-linear-gradient(
|
||||
45deg,
|
||||
#f7f7f7,
|
||||
#f7f7f7 7px,
|
||||
#ffc7c7 7px,
|
||||
#ffc7c7 14px
|
||||
);
|
||||
color: #303030;
|
||||
}
|
||||
ul.rack_near_face li.empty a {
|
||||
color: #0000ff;
|
||||
display: none;
|
||||
text-decoration: none;
|
||||
}
|
||||
ul.rack_near_face li.empty:hover {
|
||||
background-color: #ffffff;
|
||||
}
|
||||
ul.rack_near_face li.empty:hover a {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* Rack elevation colors (from http://flatuicolors.com) */
|
||||
.teal { background-color: #1abc9c; border-bottom: 1px solid #16a085; }
|
||||
.teal:hover { background-color: #16a085; }
|
||||
.green { background-color: #2ecc71; border-bottom: 1px solid #27ae60; }
|
||||
.green:hover { background-color: #27ae60; }
|
||||
.blue { background-color: #3498db; border-bottom: 1px solid #2980b9; }
|
||||
.blue:hover { background-color: #2980b9; }
|
||||
.purple { background-color: #9b59b6; border-bottom: 1px solid #8e44ad; }
|
||||
.purple:hover { background-color: #8e44ad; }
|
||||
.yellow { background-color: #f1c40f; border-bottom: 1px solid #f39c12; }
|
||||
.yellow:hover { background-color: #f39c12; }
|
||||
.orange { background-color: #e67e22; border-bottom: 1px solid #d35400; }
|
||||
.orange:hover { background-color: #d35400; }
|
||||
.red { background-color: #e74c3c; border-bottom: 1px solid #c0392b; }
|
||||
.red:hover { background-color: #c0392b; }
|
||||
.light_gray { background-color: #ecf0f1; border-bottom: 1px solid #bdc3c7; }
|
||||
.light_gray:hover { background-color: #bdc3c7; }
|
||||
.medium_gray { background-color: #95a5a6; border-bottom: 1px solid #7f8c8d; }
|
||||
.medium_gray:hover { background-color: #7f8c8d; }
|
||||
.dark_gray { background-color: #34495e; border-bottom: 1px solid #2c3e50; }
|
||||
.dark_gray:hover { background-color: #2c3e50; }
|
||||
|
||||
/* Misc */
|
||||
.panel table>thead>tr>th {
|
||||
border-bottom: 0;
|
||||
}
|
||||
ul.nav-tabs, ul.nav-pills {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.panel .list-group {
|
||||
max-height: 400px;
|
||||
overflow: auto;
|
||||
}
|
||||
/* Fix progress bar margin inside table cells */
|
||||
td .progress {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
textarea {
|
||||
font-family: Consolas, Lucida Console, monospace;
|
||||
}
|
||||
116
netbox/project-static/js/forms.js
Normal file
116
netbox/project-static/js/forms.js
Normal file
@@ -0,0 +1,116 @@
|
||||
$(document).ready(function() {
|
||||
|
||||
// "Select all" checkbox in a table header
|
||||
$('th input:checkbox').click(function (event) {
|
||||
$(this).parents('table').find('td input:checkbox').prop('checked', $(this).prop('checked'));
|
||||
});
|
||||
|
||||
// Helper select fields
|
||||
$('select.helper-parent').change(function () {
|
||||
|
||||
// Resolve child field by ID specified in parent
|
||||
var child_field = $('#id_' + $(this).attr('child'));
|
||||
|
||||
// Wipe out any existing options within the child field
|
||||
child_field.empty();
|
||||
child_field.append($("<option></option>").attr("value", "").text(""));
|
||||
|
||||
// If the parent has a value set, fetch a list of child options via the API and populate the child field with them
|
||||
if ($(this).val()) {
|
||||
|
||||
// Construct the API request URL
|
||||
var api_url = $(this).attr('child-source');
|
||||
var parent_accessor = $(this).attr('parent-accessor');
|
||||
if (parent_accessor) {
|
||||
api_url += '?' + parent_accessor + '=' + $(this).val();
|
||||
} else {
|
||||
api_url += '?' + $(this).attr('name') + '_id=' + $(this).val();
|
||||
}
|
||||
var api_url_extra = $(this).attr('child-filter');
|
||||
if (api_url_extra) {
|
||||
api_url += '&' + api_url_extra;
|
||||
}
|
||||
|
||||
var disabled_indicator = $(this).attr('disabled-indicator');
|
||||
var disabled_exempt = child_field.attr('exempt');
|
||||
var child_display = $(this).attr('child-display');
|
||||
if (!child_display) {
|
||||
child_display = 'name';
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
url: api_url,
|
||||
dataType: 'json',
|
||||
success: function (response, status) {
|
||||
console.log(response);
|
||||
$.each(response, function (index, choice) {
|
||||
var option = $("<option></option>").attr("value", choice.id).text(choice[child_display]);
|
||||
if (disabled_indicator && choice[disabled_indicator] && choice.id != disabled_exempt) {
|
||||
option.attr("disabled", "disabled")
|
||||
}
|
||||
child_field.append(option);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
// Trigger change event in case the child field is the parent of another field
|
||||
child_field.change();
|
||||
|
||||
});
|
||||
|
||||
// API select widget
|
||||
$('select[filter-for]').change(function () {
|
||||
|
||||
// Resolve child field by ID specified in parent
|
||||
var child_name = $(this).attr('filter-for');
|
||||
var child_field = $('#id_' + child_name);
|
||||
|
||||
// Wipe out any existing options within the child field
|
||||
child_field.empty();
|
||||
child_field.append($("<option></option>").attr("value", "").text(""));
|
||||
|
||||
if ($(this).val()) {
|
||||
|
||||
var api_url = child_field.attr('api-url');
|
||||
var disabled_indicator = child_field.attr('disabled-indicator');
|
||||
var initial_value = child_field.attr('initial');
|
||||
var display_field = child_field.attr('display-field') || 'name';
|
||||
|
||||
// Gather the values of all other filter fields for this child
|
||||
$("select[filter-for='" + child_name + "']").each(function() {
|
||||
var filter_field = $(this);
|
||||
if (filter_field.val()) {
|
||||
api_url = api_url.replace('{{' + filter_field.attr('name') + '}}', filter_field.val());
|
||||
} else {
|
||||
// Not all filters have been selected yet
|
||||
return false;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
// If all URL variables have been replaced, make the API call
|
||||
if (api_url.search('{{') < 0) {
|
||||
$.ajax({
|
||||
url: api_url,
|
||||
dataType: 'json',
|
||||
success: function (response, status) {
|
||||
$.each(response, function (index, choice) {
|
||||
var option = $("<option></option>").attr("value", choice.id).text(choice[display_field]);
|
||||
if (disabled_indicator && choice[disabled_indicator] && choice.id != initial_value) {
|
||||
option.attr("disabled", "disabled")
|
||||
}
|
||||
child_field.append(option);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Trigger change event in case the child field is the parent of another field
|
||||
child_field.change();
|
||||
|
||||
});
|
||||
});
|
||||
40
netbox/project-static/js/livesearch.js
Normal file
40
netbox/project-static/js/livesearch.js
Normal file
@@ -0,0 +1,40 @@
|
||||
$(document).ready(function() {
|
||||
var search_field = $('#id_livesearch');
|
||||
var search_key = search_field.attr('data-key');
|
||||
var label = search_field.attr('data-label');
|
||||
if (!label) {
|
||||
label = 'name';
|
||||
}
|
||||
|
||||
search_field.autocomplete({
|
||||
source: function(request, response) {
|
||||
$.ajax({
|
||||
type: 'GET',
|
||||
url: search_field.attr('data-source'),
|
||||
data: search_key + '=' + request.term,
|
||||
success: function(data) {
|
||||
var choices = [];
|
||||
$.each(data, function (index, choice) {
|
||||
choices.push({
|
||||
value: choice.id,
|
||||
label: choice[label]
|
||||
});
|
||||
});
|
||||
response(choices);
|
||||
}
|
||||
});
|
||||
},
|
||||
select: function(event, ui) {
|
||||
event.preventDefault();
|
||||
search_field.val(ui.item.label);
|
||||
var real_field = $('#id_' + search_field.attr('data-field'));
|
||||
real_field.empty();
|
||||
real_field.append($("<option></option>").attr('value', ui.item.value).text(ui.item.label));
|
||||
real_field.change();
|
||||
// If the field has a parent helper, reset the parent to no selection
|
||||
$('select[filter-for="' + real_field.attr('name') + '"]').val('');
|
||||
},
|
||||
minLength: 4,
|
||||
delay: 500
|
||||
});
|
||||
});
|
||||
96
netbox/project-static/js/secrets.js
Normal file
96
netbox/project-static/js/secrets.js
Normal file
@@ -0,0 +1,96 @@
|
||||
$(document).ready(function() {
|
||||
|
||||
// Unlocking a secret
|
||||
$('button.unlock-secret').click(function (event) {
|
||||
var secret_id = $(this).attr('secret-id');
|
||||
|
||||
// Retrieve from storage or prompt for private key
|
||||
var private_key = sessionStorage.getItem('private_key');
|
||||
if (!private_key) {
|
||||
$('#privkey_modal').modal('show');
|
||||
} else {
|
||||
unlock_secret(secret_id, private_key);
|
||||
$(this).hide();
|
||||
$(this).siblings('button.lock-secret').show();
|
||||
}
|
||||
});
|
||||
|
||||
// Locking a secret
|
||||
$('button.lock-secret').click(function (event) {
|
||||
var secret_id = $(this).attr('secret-id');
|
||||
$('#secret_' + secret_id).html('********');
|
||||
$(this).hide();
|
||||
$(this).siblings('button.unlock-secret').show();
|
||||
});
|
||||
|
||||
// Adding/editing a secret
|
||||
$('form.requires-private-key').submit(function(event) {
|
||||
var private_key = sessionStorage.getItem('private_key');
|
||||
if (private_key) {
|
||||
$('#id_private_key').val(private_key);
|
||||
} else {
|
||||
$('#privkey_modal').modal('show');
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
// Prompt the user to enter a private RSA key for decryption
|
||||
$('#submit_privkey').click(function() {
|
||||
var private_key = $('#user_privkey').val();
|
||||
sessionStorage.setItem('private_key', private_key);
|
||||
});
|
||||
|
||||
// Generate a new public/private key pair via the API
|
||||
$('#generate_keypair').click(function() {
|
||||
$('#new_keypair_modal').modal('show');
|
||||
$.ajax({
|
||||
url: '/api/secrets/generate-keys/',
|
||||
type: 'GET',
|
||||
dataType: 'json',
|
||||
success: function (response, status) {
|
||||
var public_key = response.public_key;
|
||||
var private_key = response.private_key;
|
||||
$('#new_pubkey').val(public_key);
|
||||
$('#new_privkey').val(private_key);
|
||||
},
|
||||
error: function (xhr, ajaxOptions, thrownError) {
|
||||
alert("There was an error generating a new key pair.");
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Enter a newly generated public key
|
||||
$('#use_new_pubkey').click(function() {
|
||||
var new_pubkey = $('#new_pubkey');
|
||||
if (new_pubkey.val()) {
|
||||
$('#id_public_key').val(new_pubkey.val());
|
||||
}
|
||||
});
|
||||
|
||||
// Retrieve a secret via the API
|
||||
function unlock_secret(secret_id, private_key) {
|
||||
var csrf_token = $('input[name=csrfmiddlewaretoken]').val();
|
||||
$.ajax({
|
||||
url: '/api/secrets/secrets/' + secret_id + '/decrypt/',
|
||||
type: 'POST',
|
||||
data: {
|
||||
private_key: private_key
|
||||
},
|
||||
dataType: 'json',
|
||||
beforeSend: function(xhr, settings) {
|
||||
xhr.setRequestHeader("X-CSRFToken", csrf_token);
|
||||
},
|
||||
success: function (response, status) {
|
||||
var secret_plaintext = response.plaintext;
|
||||
$('#secret_' + secret_id).html(secret_plaintext);
|
||||
return true;
|
||||
},
|
||||
error: function (xhr, ajaxOptions, thrownError) {
|
||||
if (xhr.status == 403) {
|
||||
alert("Decryption failed: " + xhr.statusText);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
Reference in New Issue
Block a user