Merge branch 'og-work'

This commit is contained in:
Oliver Gorwits
2013-04-24 22:31:30 +01:00
23 changed files with 237 additions and 135 deletions

View File

@@ -1,17 +1,25 @@
2.007000_002 - 2.007000_002 -
* NOTE this version requires SNMP::Info 3.x
[NEW FEATURES] [NEW FEATURES]
* Finally we have a discover/refresh daemon job :) * Finally we have a discover/refresh daemon job :)
* Also... a Scheduler which removes need for crontab installation * Also... a Scheduler which removes need for crontab installation
* The netdisco-do script can run a one-off discover for a device * The netdisco-do script can run a one-off discover for a device
* Can select MAC Address display format on Node and Device Port search
[ENHANCEMENTS]
* SNMP connection now uses cached info if available
* Better handling of MIBs home location in deploy script
* Port filter in device port display is now highlighted green
* Navbar search is fuzzier
* Phone node icon is a little phone handset
[BUG FIXES] [BUG FIXES]
* Rename plugins developer doc to .pod * Rename plugins developer doc to .pod
* Update to latest Bootstrap and JQuery, and temp. fix #7326 in Bootstrap * Update to latest Bootstrap and JQuery, and temp. fix #7326 in Bootstrap
* Partial Name in Port search now working
2.007000_001 - 2013-03-17 2.007000_001 - 2013-03-17

View File

@@ -4,38 +4,38 @@ name 'App-Netdisco';
license 'bsd'; license 'bsd';
all_from 'lib/App/Netdisco.pm'; all_from 'lib/App/Netdisco.pm';
requires 'Algorithm::Cron' => 0; requires 'Algorithm::Cron' => 0.07;
requires 'App::cpanminus' => 0; requires 'App::cpanminus' => 1.6108;
requires 'App::local::lib::helper' => 0; requires 'App::local::lib::helper' => 0.07;
requires 'DBD::Pg' => 0; requires 'DBD::Pg' => 0;
requires 'DBD::SQLite' => 0; requires 'DBD::SQLite' => 1.37;
requires 'DBIx::Class' => 0; requires 'DBIx::Class' => 0.08210;
requires 'DBIx::Class::Helper::Row::SubClass' => 0; requires 'DBIx::Class::Helpers' => 2.016006;
requires 'Daemon::Control' => 0; requires 'Daemon::Control' => 0.001000;
requires 'Dancer' => 1.3098; requires 'Dancer' => 1.3112;
requires 'Dancer::Plugin::DBIC' => 0; requires 'Dancer::Plugin::DBIC' => 0.1802;
requires 'File::ShareDir' => 0; requires 'File::ShareDir' => 1.03;
requires 'HTML::Entities' => 0; requires 'HTML::Parser' => 3.70;
requires 'HTTP::Tiny' => 0; requires 'HTTP::Tiny' => 0.029;
requires 'JSON' => 0; requires 'JSON' => 0;
requires 'List::MoreUtils' => 0; requires 'List::MoreUtils' => 0.33;
requires 'Moo' => 0; requires 'Moo' => 1.001000;
requires 'MCE' => 1.405; requires 'MCE' => 1.408;
requires 'Net::DNS' => 0; requires 'Net::DNS' => 0.72;
requires 'Net::MAC' => 0; requires 'Net::MAC' => 2.103622;
requires 'NetAddr::IP' => '4.059'; requires 'NetAddr::IP' => 4.068;
requires 'Path::Class' => 0; requires 'Path::Class' => 0.32;
requires 'Plack' => 1.0006; requires 'Plack' => 1.0023;
requires 'Plack::Middleware::Expires' => 0; requires 'Plack::Middleware::Expires' => 0.03;
requires 'Role::Tiny' => 0; requires 'Role::Tiny' => 1.002005;
requires 'Socket6' => 0; requires 'Socket6' => 0.23;
requires 'Starman' => 0; requires 'Starman' => 0.3008;
requires 'SNMP::Info' => '3.01'; requires 'SNMP::Info' => 3.01;
requires 'SQL::Translator' => 0; requires 'SQL::Translator' => 0.11016;
requires 'Template' => 0; requires 'Template::Toolkit' => 2.24;
requires 'YAML' => 0; requires 'YAML' => 0.84;
requires 'namespace::clean' => 0; requires 'namespace::clean' => 0.24;
requires 'version' => 0.9901; requires 'version' => 0.9902;
install_share 'share'; install_share 'share';

View File

@@ -42,6 +42,7 @@ use Term::UI;
use Term::ReadLine; use Term::ReadLine;
use Archive::Extract; use Archive::Extract;
$Archive::Extract::PREFER_BIN = 1;
use HTTP::Tiny; use HTTP::Tiny;
use Try::Tiny; use Try::Tiny;
@@ -96,15 +97,27 @@ deploy_db() if $bool;
say ''; say '';
$bool = $term->ask_yn( $bool = $term->ask_yn(
prompt => 'Would you like to download and update vendor MAC prefixes (OUI data)?', default => 'n', prompt => 'Download and update vendor MAC prefixes (OUI data)?', default => 'n',
); );
deploy_oui() if $bool; deploy_oui() if $bool;
say ''; say '';
$bool = $term->ask_yn( my $default_mibhome = dir($home, 'netdisco-mibs');
prompt => 'Would you like to download and update MIB files?', default => 'n', if (setting('mibhome') and setting('mibhome') ne $default_mibhome) {
); my $mibhome = $term->get_reply(
deploy_mibs() if $bool; print_me => "MIB home options:",
prompt => "Download and update MIB files to...?",
choices => [setting('mibhome'), $default_mibhome, 'Skip this.'],
default => 'Skip this.',
);
deploy_mibs($mibhome) if $mibhome and $mibhome ne 'Skip this.';
}
else {
$bool = $term->ask_yn(
prompt => "Download and update MIB files?", default => 'n',
);
deploy_mibs($default_mibhome) if $bool;
}
sub deploy_db { sub deploy_db {
system 'netdisco-db-deploy'; system 'netdisco-db-deploy';
@@ -142,13 +155,15 @@ sub deploy_oui {
} }
sub deploy_mibs { sub deploy_mibs {
my $mibhome = dir(shift);
my $url = 'http://downloads.sourceforge.net/project/netdisco/netdisco-mibs/latest-snapshot/netdisco-mibs-snapshot.tar.gz'; my $url = 'http://downloads.sourceforge.net/project/netdisco/netdisco-mibs/latest-snapshot/netdisco-mibs-snapshot.tar.gz';
my $file = file($home, 'netdisco-mibs-snapshot.tar.gz'); my $file = file($home, 'netdisco-mibs-snapshot.tar.gz');
my $resp = HTTP::Tiny->new->mirror($url, $file); my $resp = HTTP::Tiny->new->mirror($url, $file);
if ($resp->{success}) { if ($resp->{success}) {
my $ae = Archive::Extract->new(archive => $file, type => 'tgz'); my $ae = Archive::Extract->new(archive => $file, type => 'tgz');
$ae->extract(to => $home); $ae->extract(to => $mibhome->parent->stringify);
unlink $file; unlink $file;
} }

View File

@@ -7,6 +7,8 @@ package App::Netdisco::DB::Result::Node;
use strict; use strict;
use warnings; use warnings;
use Net::MAC;
use base 'DBIx::Class::Core'; use base 'DBIx::Class::Core';
__PACKAGE__->table("node"); __PACKAGE__->table("node");
__PACKAGE__->add_columns( __PACKAGE__->add_columns(
@@ -134,4 +136,12 @@ between the date stamp and time stamp. That is:
sub time_last_stamp { return (shift)->get_column('time_last_stamp') } sub time_last_stamp { return (shift)->get_column('time_last_stamp') }
=head2 net_mac
Returns the C<mac> column instantiated into a L<Net::MAC> object.
=cut
sub net_mac { return Net::MAC->new(mac => (shift)->mac) }
1; 1;

View File

@@ -7,6 +7,8 @@ package App::Netdisco::DB::Result::NodeIp;
use strict; use strict;
use warnings; use warnings;
use Net::MAC;
use base 'DBIx::Class::Core'; use base 'DBIx::Class::Core';
__PACKAGE__->table("node_ip"); __PACKAGE__->table("node_ip");
__PACKAGE__->add_columns( __PACKAGE__->add_columns(
@@ -206,4 +208,12 @@ between the date stamp and time stamp. That is:
sub time_last_stamp { return (shift)->get_column('time_last_stamp') } sub time_last_stamp { return (shift)->get_column('time_last_stamp') }
=head2 net_mac
Returns the C<mac> column instantiated into a L<Net::MAC> object.
=cut
sub net_mac { return Net::MAC->new(mac => (shift)->mac) }
1; 1;

View File

@@ -147,7 +147,8 @@ sub _try_connect {
} }
sub _build_mibdirs { sub _build_mibdirs {
return map { dir(setting('mibhome'), $_) } my $home = (setting('mibhome') || $ENV{NETDISCO_HOME} || $ENV{HOME});
return map { dir($home, $_) }
@{ setting('mibdirs') || [] }; @{ setting('mibdirs') || [] };
} }

View File

@@ -51,6 +51,7 @@ hook 'before' => sub {
if (not param('tab') or param('tab') ne 'ports') { if (not param('tab') or param('tab') ne 'ports') {
params->{'age_num'} = 3; params->{'age_num'} = 3;
params->{'age_unit'} = 'months'; params->{'age_unit'} = 'months';
params->{'mac_format'} = 'IEEE';
} }
}; };
@@ -62,8 +63,13 @@ hook 'before_template' => sub {
tab => 'ports', tab => 'ports',
age_num => 3, age_num => 3,
age_unit => 'months', age_unit => 'months',
mac_format => 'IEEE',
}); });
# for Net::MAC method
$tokens->{mac_format_call} = 'as_'. params->{'mac_format'}
if params->{'mac_format'};
foreach my $col (@{ var('port_columns') }) { foreach my $col (@{ var('port_columns') }) {
next unless $col->{default} eq 'on'; next unless $col->{default} eq 'on';
$tokens->{device_ports}->query_param($col->{name}, 'checked'); $tokens->{device_ports}->query_param($col->{name}, 'checked');

View File

@@ -75,7 +75,7 @@ get '/search' => sub {
params->{'tab'} = 'vlan'; params->{'tab'} = 'vlan';
} }
else { else {
my $nd = $s->resultset('Device')->search_aliases($q); my $nd = $s->resultset('Device')->search_fuzzy($q);
if ($nd and $nd->count) { if ($nd and $nd->count) {
if ($nd->count == 1) { if ($nd->count == 1) {

View File

@@ -3,7 +3,7 @@
# Web app env-related settings should go to environments/$env.yml # Web app env-related settings should go to environments/$env.yml
# Your application's name # application's name
appname: "Netdisco" appname: "Netdisco"
# The default web layout to use for your application (located in # The default web layout to use for your application (located in
@@ -33,7 +33,7 @@ engines:
end_tag: '%]' end_tag: '%]'
PRE_CHOMP: 1 PRE_CHOMP: 1
# netdisco stuff (can be overidden in the environment .yml) # Netdisco stuff (can be overidden in the environment .yml)
web_plugins: web_plugins:
- Inventory - Inventory
@@ -55,7 +55,12 @@ snmpver: 2
snmpretries: 2 snmpretries: 2
snmptimeout: 1000000 snmptimeout: 1000000
mibhome: /usr/share/netdisco/mibs # If unset, Netdisco uses "NETDISCO_HOME/netdisco-mibs", assuming you're
# using the netdisco-deploy script to download MIBs there. Otherwise, set
# this, for example:
#
# mibhome: /usr/share/netdisco/mibs
mibdirs: mibdirs:
- cisco - cisco
- rfc - rfc

View File

@@ -37,7 +37,6 @@ plugins:
# local settings for Netdisco poller and port changes # local settings for Netdisco poller and port changes
mibhome: '/home/netdisco/netdisco-mibs'
mibdirs: mibdirs:
- cisco - cisco
- rfc - rfc

View File

@@ -39,7 +39,6 @@ no_auth: 1
# local settings for Netdisco poller and port changes # local settings for Netdisco poller and port changes
mibhome: '/home/netdisco/netdisco-mibs'
mibdirs: mibdirs:
- cisco - cisco
- rfc - rfc

View File

@@ -252,6 +252,19 @@ td {
width: 95px; width: 95px;
} }
/* set the MAC format drop-down width */
#nd_mac_format {
margin-top: 4px;
width: 154px;
}
/* set the MAC format drop-down width */
#nd_node_mac_format {
margin-left: -2px;
margin-top: 4px;
width: 165px;
}
/* sidebar submit button width and spacing from Node Props */ /* sidebar submit button width and spacing from Node Props */
.sidebar button { .sidebar button {
margin-top: 9px; margin-top: 9px;
@@ -266,13 +279,28 @@ td {
/* little icon inside of search input fields */ /* little icon inside of search input fields */
.field_clear_icon, .field_copy_icon { .field_clear_icon, .field_copy_icon {
position: absolute; position: absolute;
margin-left: 132px; margin-left: 140px;
margin-top: 5px;
z-index: 1; z-index: 1;
padding: 7px; padding: 0px;
cursor: pointer; cursor: pointer;
}
.field_copy_icon {
color: #999; color: #999;
} }
.field_clear_icon {
background-color: #A9DBA9;
color: #3A87AD;
}
/* for the ports form, but the positioning is slightly different */
#ports_form .field_clear_icon {
margin-left: 149px;
margin-top: 5px;
}
/* change highlighting for form fields which are being used in a search */ /* change highlighting for form fields which are being used in a search */
form .clearfix.success select { form .clearfix.success select {
background-color: #A9DBA9; background-color: #A9DBA9;
@@ -294,6 +322,11 @@ form .clearfix.success input {
margin-bottom: 1px; margin-bottom: 1px;
} }
.inputs-list i {
margin-right: 5px;
margin-left: 2px;
}
/* nudge content closer to the header labels in the sidebar */ /* nudge content closer to the header labels in the sidebar */
.inputs-list li:first-child { .inputs-list li:first-child {
padding-top: 3px !important; padding-top: 3px !important;

View File

@@ -135,7 +135,41 @@ if (window.History && window.History.enabled) {
}); });
} }
// if any field in Search Options has content, highlight in green
function device_form_state(e) {
if (e.prop('value') != "") {
e.parent(".clearfix").addClass('success');
if (e.parents('#device_form').length) {
$('#nq').css('text-decoration', 'line-through');
if (e.attr('type') == 'text') {
$('.field_copy_icon').hide();
}
}
var id = '#' + e.attr('name') + '_clear_btn';
$(id).show();
}
else {
e.parent(".clearfix").removeClass('success');
var id = '#' + e.attr('name') + '_clear_btn';
$(id).hide();
var num_empty = $.grep(form_inputs,
function(n,i) {return($(n).val() != "")}).length;
if (num_empty === 3) {
$('#nq').css('text-decoration', 'none');
$('.field_copy_icon').show();
}
}
}
$(document).ready(function() { $(document).ready(function() {
// sidebar form fields should change colour and have bin/copy icon
$('.field_copy_icon').hide();
$('.field_clear_icon').hide();
// activate typeahead on the main search box, for device names only // activate typeahead on the main search box, for device names only
$('#nq').typeahead({ $('#nq').typeahead({
source: function (query, process) { source: function (query, process) {

View File

@@ -196,7 +196,8 @@
[% FOREACH node IN row.$nodes %] [% FOREACH node IN row.$nodes %]
[% '<br/>' IF row.remote_ip OR NOT loop.first %] [% '<br/>' IF row.remote_ip OR NOT loop.first %]
[% '<span class="label label-warning">A</span> &nbsp;' IF NOT node.active %] [% '<span class="label label-warning">A</span> &nbsp;' IF NOT node.active %]
<a href="[% search_node %]&q=[% node.mac | uri %]">[% node.mac | html_entity %]</a> <a href="[% search_node %]&q=[% node.net_mac.$mac_format_call | uri %]">
[% node.net_mac.$mac_format_call | html_entity %]</a>
[% ' (' _ node.time_last_age _ ')' IF params.n_age %] [% ' (' _ node.time_last_age _ ')' IF params.n_age %]
[% IF params.n_ip %] [% IF params.n_ip %]
[% FOREACH ip IN node.ips %] [% FOREACH ip IN node.ips %]

View File

@@ -17,7 +17,8 @@
[% WHILE (row = macs.next) %] [% WHILE (row = macs.next) %]
<tr> <tr>
<td><a class="nd_linkcell" <td><a class="nd_linkcell"
href="[% search_node %]&q=[% row.mac | uri %]">[% row.mac | html_entity %]</a></td> href="[% search_node %]&q=[% row.net_mac.$mac_format_call | uri %]">
[% row.net_mac.$mac_format_call | html_entity %]</a></td>
[% IF params.vendor %] [% IF params.vendor %]
<td>[% row.oui.company | html_entity %]</td> <td>[% row.oui.company | html_entity %]</td>
[% END %] [% END %]

View File

@@ -20,7 +20,8 @@
<td> <td>
[% IF first_row %] [% IF first_row %]
<a class="nd_linkcell" <a class="nd_linkcell"
href="[% search_node %]&q=[% row.mac | uri %]">[% row.mac | html_entity %]</a> href="[% search_node %]&q=[% row.net_mac.$mac_format_call | uri %]">
[% row.net_mac.$mac_format_call | html_entity %]</a>
[% ELSE %] [% ELSE %]
&nbsp; &nbsp;
[% END %] [% END %]
@@ -51,7 +52,8 @@
<td> <td>
[% IF first_row %] [% IF first_row %]
<a class="nd_linkcell" <a class="nd_linkcell"
href="[% search_node %]&q=[% node.mac | uri %]">[% node.mac | html_entity %]</a> href="[% search_node %]&q=[% node.net_mac.$mac_format_call | uri %]">
[% node.net_mac.$mac_format_call | html_entity %]</a>
[% ELSE %] [% ELSE %]
&nbsp; &nbsp;
[% END %] [% END %]

View File

@@ -2,6 +2,10 @@
// ajax content is loaded // ajax content is loaded
var path = 'device'; var path = 'device';
// fields in the Device Search Options form (Device tab)
var form_inputs = $("#ports_form .clearfix input").not('[type="checkbox"]')
.add("#ports_form .clearfix select");
function inner_view_processing(tab) { function inner_view_processing(tab) {
// LT wanted the page title to reflect what's on the page :) // LT wanted the page title to reflect what's on the page :)
document.title = $('#nd_device_name').text() document.title = $('#nd_device_name').text()
@@ -95,6 +99,10 @@
} }
$(document).ready(function() { $(document).ready(function() {
// sidebar form fields should change colour and have bin/copy icon
form_inputs.each(function() {device_form_state($(this))});
form_inputs.change(function() {device_form_state($(this))});
// sidebar collapser events trigger change of up/down arrow // sidebar collapser events trigger change of up/down arrow
$('.collapse').on('show', function() { $('.collapse').on('show', function() {
$(this).siblings().find('.arrow-up-down') $(this).siblings().find('.arrow-up-down')
@@ -106,28 +114,12 @@
.toggleClass('icon-chevron-up icon-chevron-down'); .toggleClass('icon-chevron-up icon-chevron-down');
}); });
// show or hide sweeping brush icon when field has content // handler for bin icon in port filter box
var sweep = $('#ports_form').find("input[name=f]"); var portfilter = $('#ports_form').find("input[name=f]");
if (sweep.val() === "") {
$('.field_clear_icon').hide();
} else {
$('.field_clear_icon').show();
}
sweep.change(function() {
if ($(this).val() === "") {
$('.field_clear_icon').hide();
} else {
$('.field_clear_icon').show();
}
});
// handler for sweeping brush icon in port filter box
$('.field_clear_icon').click(function() { $('.field_clear_icon').click(function() {
sweep.val(''); portfilter.val('');
$('.field_clear_icon').hide();
$('#ports_form').trigger('submit'); $('#ports_form').trigger('submit');
device_form_state(portfilter); // will hide copy icons
}); });
// clickable device port names can simply resubmit AJAX rather than // clickable device port names can simply resubmit AJAX rather than
@@ -137,9 +129,10 @@
var port = $(this).text(); var port = $(this).text();
port = $.trim(port); port = $.trim(port);
sweep.val(port); portfilter.val(port);
$('.field_clear_icon').show(); $('.field_clear_icon').show();
$('#ports_form').trigger('submit'); $('#ports_form').trigger('submit');
device_form_state(portfilter); // will hide copy icons
}); });
}); });

View File

@@ -3,54 +3,20 @@
var path = 'search'; var path = 'search';
// fields in the Device Search Options form (Device tab) // fields in the Device Search Options form (Device tab)
var d_inputs = $("#device_form .clearfix input").not('[type="checkbox"]') var form_inputs = $("#device_form .clearfix input").not('[type="checkbox"]')
.add("#device_form .clearfix select"); .add("#device_form .clearfix select");
// if any field in Device Search Options has content, highlight in green
// and strikethrough the navbar search
function device_form_state(e) {
if (e.is('[value!=""]')) {
if (e.attr('type') == 'text') {
$('.field_copy_icon').hide();
}
e.parent(".clearfix").addClass('success');
$('#nq').css('text-decoration', 'line-through');
var id = '#' + e.attr('name') + '_clear_btn';
$(id).show();
}
else {
e.parent(".clearfix").removeClass('success');
var id = '#' + e.attr('name') + '_clear_btn';
$(id).hide();
if (! d_inputs.is('[value!=""]') ) {
$('#nq').css('text-decoration', 'none');
$('.field_copy_icon').show();
}
}
}
// this is called by do_search to support local code // this is called by do_search to support local code
// here, when tab changes need to strike/unstrike the navbar search // here, when tab changes need to strike/unstrike the navbar search
function inner_view_processing(tab) { function inner_view_processing(tab) {
if (tab == 'device') {
d_inputs.each(function() {device_form_state($(this))});
}
else {
$('#nq').css('text-decoration', 'none');
}
} }
// on load, check initial Device Search Options form state, // on load, check initial Device Search Options form state,
// and on each change to the form fields // and on each change to the form fields
$(document).ready(function() { $(document).ready(function() {
$('.field_copy_icon').hide(); // sidebar form fields should change colour and have bin/copy icon
$('.field_clear_icon').hide(); form_inputs.each(function() {device_form_state($(this))});
form_inputs.change(function() {device_form_state($(this))});
d_inputs.each(function() {device_form_state($(this))});
d_inputs.change(function() {device_form_state($(this))});
// handler for copy icon in search option // handler for copy icon in search option
$('.field_copy_icon').click(function() { $('.field_copy_icon').click(function() {
@@ -65,6 +31,6 @@
var name = $(this).data('btn-for'); var name = $(this).data('btn-for');
var input = $('#device_form [name=' + name + ']'); var input = $('#device_form [name=' + name + ']');
input.val(''); input.val('');
device_form_state(input); device_form_state(input); // will hide copy icons
}); });
}); });

View File

@@ -12,6 +12,7 @@
<![endif]--> <![endif]-->
<script type="text/javascript" src="[% uri_base %]/javascripts/jquery-latest.min.js"></script> <script type="text/javascript" src="[% uri_base %]/javascripts/jquery-latest.min.js"></script>
<!-- <script type="text/javascript" src="http://code.jquery.com/jquery-migrate-1.1.1.js"></script> -->
<script type="text/javascript" src="[% uri_base %]/javascripts/jquery-history.js"></script> <script type="text/javascript" src="[% uri_base %]/javascripts/jquery-history.js"></script>
<script type="text/javascript" src="[% uri_base %]/javascripts/jquery-deserialize.js"></script> <script type="text/javascript" src="[% uri_base %]/javascripts/jquery-deserialize.js"></script>
<script type="text/javascript" src="[% uri_base %]/javascripts/bootstrap.min.js"></script> <script type="text/javascript" src="[% uri_base %]/javascripts/bootstrap.min.js"></script>

View File

@@ -1,9 +1,9 @@
<input name="q" value="[% params.q | html_entity %]" type="hidden"/> <input name="q" value="[% params.q | html_entity %]" type="hidden"/>
<div class="clearfix"> <div class="clearfix">
<a class="field_clear_icon" href="#" <i class="field_clear_icon icon-trash icon-large"
rel="tooltip" data-placement="top" data-offset="3" data-title="Show all Ports"> rel="tooltip" data-placement="bottom" data-offset="3" data-title="Show all Ports"
<img src="[% uri_base %]/images/tango_sweep.png"/></a> id="f_clear_btn" data-btn-for="port"></i>
<input id="nd_port_query" placeholder="Port, Name or VLAN" <input id="nd_port_query" placeholder="Port, Name or VLAN"
name="f" value="[% params.f | html_entity %]" type="text" name="f" value="[% params.f | html_entity %]" type="text"
rel="tooltip" data-placement="left" data-offset="5" data-title="Filter by Port, Name or VLAN"/> rel="tooltip" data-placement="left" data-offset="5" data-title="Filter by Port, Name or VLAN"/>
@@ -28,7 +28,7 @@
<span class="label label-info">B</span>&nbsp; Blocking <span class="label label-info">B</span>&nbsp; Blocking
</li> </li>
<li> <li>
<span class="label">P</span>&nbsp; IP Phone <i class="icon-phone icon-large"></i>&nbsp; IP Phone
</li> </li>
<li> <li>
<span class="label label-important">N</span>&nbsp; Neighbor Inacessible <span class="label label-important">N</span>&nbsp; Neighbor Inacessible
@@ -76,15 +76,7 @@
<div id="nd_portprops" class="collapse"> <div id="nd_portprops" class="collapse">
<ul class="inputs-list unstyled"> <ul class="inputs-list unstyled">
<li> <li>
<label class="checkbox"> <em>Mark as Free if Down for:</em><br/>
<input type="checkbox" id="free"
name="free"[% ' checked="checked"' IF params.free %]/>
Only Show Free Ports
</label>
</li>
<li>
<span rel="tooltip" data-placement="left"
data-offset="5" data-title="Free if Down for this period of time">
<select id="nd_days_select" name="age_num"> <select id="nd_days_select" name="age_num">
[% FOREACH count IN [1..32] %] [% FOREACH count IN [1..32] %]
<option[% ' selected="selected"' IF params.age_num == count %]>[% count %]</option> <option[% ' selected="selected"' IF params.age_num == count %]>[% count %]</option>
@@ -95,7 +87,13 @@
<option[% ' selected="selected"' IF params.age_unit == unit %]>[% unit %]</option> <option[% ' selected="selected"' IF params.age_unit == unit %]>[% unit %]</option>
[% END %] [% END %]
</select> </select>
</span> </li>
<li>
<label class="checkbox">
<input type="checkbox" id="free"
name="free"[% ' checked="checked"' IF params.free %]/>
Only show Free Ports
</label>
</li> </li>
</ul> </ul>
</div> </div>
@@ -107,6 +105,14 @@
</label></span> </label></span>
<div id="nd_nodeprops" class="collapse"> <div id="nd_nodeprops" class="collapse">
<ul class="inputs-list unstyled"> <ul class="inputs-list unstyled">
<li>
<em>MAC address format:</em><br/>
<select id="nd_mac_format" name="mac_format">
[% FOREACH format IN [ 'IEEE', 'Cisco', 'Microsoft', 'Sun' ] %]
<option[% ' selected="selected"' IF params.mac_format == format %]>[% format %]</option>
[% END %]
</select>
</li>
[% FOREACH item IN vars.connected_properties %] [% FOREACH item IN vars.connected_properties %]
<li> <li>
<label class="checkbox"> <label class="checkbox">

View File

@@ -31,11 +31,19 @@
</div> </div>
<div class="clearfix input-prepend"> <div class="clearfix input-prepend">
<label class="add-on"> <label class="add-on">
<input type="checkbox" id="partial" <input type="checkbox" id="node_partial"
name="partial"[% ' checked="checked"' IF params.partial %]/> name="partial"[% ' checked="checked"' IF params.partial %]/>
</label> </label>
<label class="nd_checkboxlabel" for="partial"> <label class="nd_checkboxlabel" for="node_partial">
<span class="nd_searchcheckbox uneditable-input">Partial Name</span> <span class="nd_searchcheckbox uneditable-input">Partial Name</span>
</label> </label>
</div> </div>
<div class="clearfix">
<em>MAC address format:</em><br/>
<select id="nd_node_mac_format" name="mac_format">
[% FOREACH format IN [ 'IEEE', 'Cisco', 'Microsoft', 'Sun' ] %]
<option[% ' selected="selected"' IF params.mac_format == format %]>[% format %]</option>
[% END %]
</select>
</div>
<button id="[% tab.id %]_submit" type="submit" class="btn btn-info">Search Again</button> <button id="[% tab.id %]_submit" type="submit" class="btn btn-info">Search Again</button>

View File

@@ -3,10 +3,10 @@
<input name="q" value="[% params.q | html_entity %]" type="hidden"/> <input name="q" value="[% params.q | html_entity %]" type="hidden"/>
<div class="clearfix input-prepend"> <div class="clearfix input-prepend">
<label class="add-on"> <label class="add-on">
<input type="checkbox" id="partial" <input type="checkbox" id="port_partial"
name="partial"[% ' checked="checked"' IF params.partial %]/> name="partial"[% ' checked="checked"' IF params.partial %]/>
</label> </label>
<label class="nd_checkboxlabel" for="partial"> <label class="nd_checkboxlabel" for="port_partial">
<span class="nd_searchcheckbox uneditable-input">Partial Name</span> <span class="nd_searchcheckbox uneditable-input">Partial Name</span>
</label> </label>
</div> </div>

16
TODO
View File

@@ -1,23 +1,27 @@
** in no particular order... **
** names by tasks indicate who's "taken" them **
FRONTEND FRONTEND
======== ========
* UI for topo DB table editing * UI for topo DB table editing
- drop topo file support and use DB only - drop topo file support and use DB only
* Port/Name/VLAN box should be green when filled
* Choice of MAC address formats * Choice of MAC address formats
* Empty inventory should trigger request to discover * No devices - trigger first discover splash page
* (jeneric) device module tab * (jeneric) device module tab
DAEMON DAEMON
====== ======
* macsuck/arpnip
CORE CORE
==== ====
* pseudo-device support * pseudo-device support
* VRF support * VRF support
DOCS
====
* Scheduler
* Discover/Refresh jobs
* netdisco-do