Merge branch 'master' of ssh://git.code.sf.net/p/netdisco/netdisco-ng

This commit is contained in:
Oliver Gorwits
2015-01-03 09:59:40 +00:00
29 changed files with 274 additions and 50 deletions

View File

@@ -1,5 +1,10 @@
2.029015 2.029015
[NEW FEATURES]
* [#4] Allow comment on device port in the log, for any user
* [#18] Inventory by Model by OS Report
[ENHANCEMENTS] [ENHANCEMENTS]
* Request net-snmp-devel on Fedora/Red-Hat builds * Request net-snmp-devel on Fedora/Red-Hat builds
@@ -10,6 +15,9 @@
* Fix for node search on some formats of IPv6 addr being seen as MAC * Fix for node search on some formats of IPv6 addr being seen as MAC
* [#190] Ignore entries in the discover form that don't look like IP/hostname * [#190] Ignore entries in the discover form that don't look like IP/hostname
* Delete all job queue entries (regardless of status) when deleting device
* [#15] Undiscovered Neighbor report JOIN fixed, and updated to include
the ports where Macsuck saw the MAC address of a known Device
2.029014 - 2014-11-19 2.029014 - 2014-11-19

View File

@@ -201,6 +201,7 @@ lib/App/Netdisco/Web/Plugin/Report/DeviceDnsMismatch.pm
lib/App/Netdisco/Web/Plugin/Report/DevicePoeStatus.pm lib/App/Netdisco/Web/Plugin/Report/DevicePoeStatus.pm
lib/App/Netdisco/Web/Plugin/Report/DuplexMismatch.pm lib/App/Netdisco/Web/Plugin/Report/DuplexMismatch.pm
lib/App/Netdisco/Web/Plugin/Report/HalfDuplex.pm lib/App/Netdisco/Web/Plugin/Report/HalfDuplex.pm
lib/App/Netdisco/Web/Plugin/Report/InventoryByModelByOS.pm
lib/App/Netdisco/Web/Plugin/Report/IpInventory.pm lib/App/Netdisco/Web/Plugin/Report/IpInventory.pm
lib/App/Netdisco/Web/Plugin/Report/ModuleInventory.pm lib/App/Netdisco/Web/Plugin/Report/ModuleInventory.pm
lib/App/Netdisco/Web/Plugin/Report/Netbios.pm lib/App/Netdisco/Web/Plugin/Report/Netbios.pm
@@ -341,6 +342,7 @@ share/views/ajax/report/generic_report.tt
share/views/ajax/report/generic_report_csv.tt share/views/ajax/report/generic_report_csv.tt
share/views/ajax/report/halfduplex.tt share/views/ajax/report/halfduplex.tt
share/views/ajax/report/halfduplex_csv.tt share/views/ajax/report/halfduplex_csv.tt
share/views/ajax/report/inventorybymodelbyos.tt
share/views/ajax/report/ipinventory.tt share/views/ajax/report/ipinventory.tt
share/views/ajax/report/ipinventory_csv.tt share/views/ajax/report/ipinventory_csv.tt
share/views/ajax/report/moduleinventory.tt share/views/ajax/report/moduleinventory.tt

View File

@@ -7,11 +7,11 @@ build_requires:
ExtUtils::MakeMaker: 6.59 ExtUtils::MakeMaker: 6.59
Test::More: 0.88 Test::More: 0.88
configure_requires: configure_requires:
DBIx::Class: 0.082801 DBIx::Class: '0.082801'
ExtUtils::MakeMaker: 6.59 ExtUtils::MakeMaker: 6.59
distribution_type: module distribution_type: module
dynamic_config: 1 dynamic_config: 1
generated_by: 'Module::Install version 1.06' generated_by: 'Module::Install version 1.12'
license: bsd license: bsd
meta-spec: meta-spec:
url: http://module-build.sourceforge.net/META-spec-v1.4.html url: http://module-build.sourceforge.net/META-spec-v1.4.html
@@ -39,7 +39,7 @@ requires:
DBIx::Class: 0.08281 DBIx::Class: 0.08281
DBIx::Class::Helpers: 2.024 DBIx::Class::Helpers: 2.024
Daemon::Control: 0.001006 Daemon::Control: 0.001006
Dancer: 1.3132 Dancer: '1.3132'
Dancer::Plugin::Auth::Extensible: 0.3 Dancer::Plugin::Auth::Extensible: 0.3
Dancer::Plugin::DBIC: 0.2001 Dancer::Plugin::DBIC: 0.2001
Dancer::Plugin::Passphrase: 2.0.1 Dancer::Plugin::Passphrase: 2.0.1
@@ -68,7 +68,7 @@ requires:
Plack::Middleware::ReverseProxy: 0.15 Plack::Middleware::ReverseProxy: 0.15
Role::Tiny: 1.002005 Role::Tiny: 1.002005
SNMP::Info: 3.18 SNMP::Info: 3.18
SQL::Translator: 0.11018 SQL::Translator: '0.11018'
Sereal: 0 Sereal: 0
Socket6: 0.23 Socket6: 0.23
Starman: 0.4008 Starman: 0.4008
@@ -91,4 +91,4 @@ resources:
homepage: http://netdisco.org/ homepage: http://netdisco.org/
license: http://opensource.org/licenses/bsd-license.php license: http://opensource.org/licenses/bsd-license.php
repository: git://git.code.sf.net/p/netdisco/netdisco-ng repository: git://git.code.sf.net/p/netdisco/netdisco-ng
version: 2.029014 version: '2.029014'

View File

@@ -17,7 +17,7 @@ package Module::Install;
# 3. The ./inc/ version of Module::Install loads # 3. The ./inc/ version of Module::Install loads
# } # }
use 5.005; use 5.006;
use strict 'vars'; use strict 'vars';
use Cwd (); use Cwd ();
use File::Find (); use File::Find ();
@@ -31,7 +31,7 @@ BEGIN {
# This is not enforced yet, but will be some time in the next few # This is not enforced yet, but will be some time in the next few
# releases once we can make sure it won't clash with custom # releases once we can make sure it won't clash with custom
# Module::Install extensions. # Module::Install extensions.
$VERSION = '1.06'; $VERSION = '1.12';
# Storage for the pseudo-singleton # Storage for the pseudo-singleton
$MAIN = undef; $MAIN = undef;
@@ -156,10 +156,10 @@ END_DIE
sub autoload { sub autoload {
my $self = shift; my $self = shift;
my $who = $self->_caller; my $who = $self->_caller;
my $cwd = Cwd::cwd(); my $cwd = Cwd::getcwd();
my $sym = "${who}::AUTOLOAD"; my $sym = "${who}::AUTOLOAD";
$sym->{$cwd} = sub { $sym->{$cwd} = sub {
my $pwd = Cwd::cwd(); my $pwd = Cwd::getcwd();
if ( my $code = $sym->{$pwd} ) { if ( my $code = $sym->{$pwd} ) {
# Delegate back to parent dirs # Delegate back to parent dirs
goto &$code unless $cwd eq $pwd; goto &$code unless $cwd eq $pwd;
@@ -239,7 +239,7 @@ sub new {
# ignore the prefix on extension modules built from top level. # ignore the prefix on extension modules built from top level.
my $base_path = Cwd::abs_path($FindBin::Bin); my $base_path = Cwd::abs_path($FindBin::Bin);
unless ( Cwd::abs_path(Cwd::cwd()) eq $base_path ) { unless ( Cwd::abs_path(Cwd::getcwd()) eq $base_path ) {
delete $args{prefix}; delete $args{prefix};
} }
return $args{_self} if $args{_self}; return $args{_self} if $args{_self};
@@ -338,7 +338,7 @@ sub find_extensions {
if ( $subpath eq lc($subpath) || $subpath eq uc($subpath) ) { if ( $subpath eq lc($subpath) || $subpath eq uc($subpath) ) {
my $content = Module::Install::_read($subpath . '.pm'); my $content = Module::Install::_read($subpath . '.pm');
my $in_pod = 0; my $in_pod = 0;
foreach ( split //, $content ) { foreach ( split /\n/, $content ) {
$in_pod = 1 if /^=\w/; $in_pod = 1 if /^=\w/;
$in_pod = 0 if /^=cut/; $in_pod = 0 if /^=cut/;
next if ($in_pod || /^=cut/); # skip pod text next if ($in_pod || /^=cut/); # skip pod text
@@ -434,7 +434,7 @@ END_OLD
# _version is for processing module versions (eg, 1.03_05) not # _version is for processing module versions (eg, 1.03_05) not
# Perl versions (eg, 5.8.1). # Perl versions (eg, 5.8.1).
sub _version ($) { sub _version {
my $s = shift || 0; my $s = shift || 0;
my $d =()= $s =~ /(\.)/g; my $d =()= $s =~ /(\.)/g;
if ( $d >= 2 ) { if ( $d >= 2 ) {
@@ -450,12 +450,12 @@ sub _version ($) {
return $l + 0; return $l + 0;
} }
sub _cmp ($$) { sub _cmp {
_version($_[1]) <=> _version($_[2]); _version($_[1]) <=> _version($_[2]);
} }
# Cloned from Params::Util::_CLASS # Cloned from Params::Util::_CLASS
sub _CLASS ($) { sub _CLASS {
( (
defined $_[0] defined $_[0]
and and

View File

@@ -4,7 +4,7 @@ package Module::Install::Base;
use strict 'vars'; use strict 'vars';
use vars qw{$VERSION}; use vars qw{$VERSION};
BEGIN { BEGIN {
$VERSION = '1.06'; $VERSION = '1.12';
} }
# Suspend handler for "redefined" warnings # Suspend handler for "redefined" warnings

View File

@@ -8,7 +8,7 @@ use Module::Install::Base ();
use vars qw{$VERSION @ISA $ISCORE}; use vars qw{$VERSION @ISA $ISCORE};
BEGIN { BEGIN {
$VERSION = '1.06'; $VERSION = '1.12';
@ISA = 'Module::Install::Base'; @ISA = 'Module::Install::Base';
$ISCORE = 1; $ISCORE = 1;
} }

View File

@@ -6,7 +6,7 @@ use Module::Install::Base ();
use vars qw{$VERSION @ISA $ISCORE}; use vars qw{$VERSION @ISA $ISCORE};
BEGIN { BEGIN {
$VERSION = '1.06'; $VERSION = '1.12';
@ISA = 'Module::Install::Base'; @ISA = 'Module::Install::Base';
$ISCORE = 1; $ISCORE = 1;
} }

View File

@@ -8,7 +8,7 @@ use Fcntl qw/:flock :seek/;
use vars qw{$VERSION @ISA $ISCORE}; use vars qw{$VERSION @ISA $ISCORE};
BEGIN { BEGIN {
$VERSION = '1.06'; $VERSION = '1.12';
@ISA = 'Module::Install::Base'; @ISA = 'Module::Install::Base';
$ISCORE = 1; $ISCORE = 1;
} }
@@ -133,7 +133,7 @@ sub makemaker_args {
return $args; return $args;
} }
# For mm args that take multiple space-seperated args, # For mm args that take multiple space-separated args,
# append an argument to the current list. # append an argument to the current list.
sub makemaker_append { sub makemaker_append {
my $self = shift; my $self = shift;

View File

@@ -6,7 +6,7 @@ use Module::Install::Base ();
use vars qw{$VERSION @ISA $ISCORE}; use vars qw{$VERSION @ISA $ISCORE};
BEGIN { BEGIN {
$VERSION = '1.06'; $VERSION = '1.12';
@ISA = 'Module::Install::Base'; @ISA = 'Module::Install::Base';
$ISCORE = 1; $ISCORE = 1;
} }
@@ -347,7 +347,7 @@ sub name_from {
^ \s* ^ \s*
package \s* package \s*
([\w:]+) ([\w:]+)
\s* ; [\s|;]*
/ixms /ixms
) { ) {
my ($name, $module_name) = ($1, $1); my ($name, $module_name) = ($1, $1);
@@ -705,7 +705,7 @@ sub _write_mymeta_data {
my @yaml = Parse::CPAN::Meta::LoadFile('META.yml'); my @yaml = Parse::CPAN::Meta::LoadFile('META.yml');
my $meta = $yaml[0]; my $meta = $yaml[0];
# Overwrite the non-configure dependency hashs # Overwrite the non-configure dependency hashes
delete $meta->{requires}; delete $meta->{requires};
delete $meta->{build_requires}; delete $meta->{build_requires};
delete $meta->{recommends}; delete $meta->{recommends};

View File

@@ -6,7 +6,7 @@ use Module::Install::Base ();
use vars qw{$VERSION @ISA $ISCORE}; use vars qw{$VERSION @ISA $ISCORE};
BEGIN { BEGIN {
$VERSION = '1.06'; $VERSION = '1.12';
@ISA = 'Module::Install::Base'; @ISA = 'Module::Install::Base';
$ISCORE = 1; $ISCORE = 1;
} }

View File

@@ -8,7 +8,7 @@ use ExtUtils::Manifest ();
use vars qw{$VERSION @ISA $ISCORE}; use vars qw{$VERSION @ISA $ISCORE};
BEGIN { BEGIN {
$VERSION = '1.06'; $VERSION = '1.12';
@ISA = 'Module::Install::Base'; @ISA = 'Module::Install::Base';
$ISCORE = 1; $ISCORE = 1;
} }

View File

@@ -6,7 +6,7 @@ use Module::Install::Base ();
use vars qw{$VERSION @ISA $ISCORE}; use vars qw{$VERSION @ISA $ISCORE};
BEGIN { BEGIN {
$VERSION = '1.06'; $VERSION = '1.12';
@ISA = 'Module::Install::Base'; @ISA = 'Module::Install::Base';
$ISCORE = 1; $ISCORE = 1;
} }

View File

@@ -6,7 +6,7 @@ use Module::Install::Base ();
use vars qw{$VERSION @ISA $ISCORE}; use vars qw{$VERSION @ISA $ISCORE};
BEGIN { BEGIN {
$VERSION = '1.06'; $VERSION = '1.12';
@ISA = qw{Module::Install::Base}; @ISA = qw{Module::Install::Base};
$ISCORE = 1; $ISCORE = 1;
} }

View File

@@ -160,6 +160,16 @@ __PACKAGE__->has_many( active_nodes_with_age => 'App::Netdisco::DB::Result::Virt
cascade_copy => 0, cascade_update => 0, cascade_delete => 0 }, cascade_copy => 0, cascade_update => 0, cascade_delete => 0 },
); );
=head2 logs
Returns the set of C<device_port_log> entries associated with this Port.
=cut
__PACKAGE__->has_many( logs => 'App::Netdisco::DB::Result::DevicePortLog',
{ 'foreign.ip' => 'self.ip', 'foreign.port' => 'self.port' },
);
=head2 power =head2 power
Returns a row from the C<device_port_power> table if one refers to this Returns a row from the C<device_port_power> table if one refers to this
@@ -345,4 +355,16 @@ Returns the C<mac> column instantiated into a L<NetAddr::MAC> object.
sub net_mac { return NetAddr::MAC->new(mac => (shift)->mac) } sub net_mac { return NetAddr::MAC->new(mac => (shift)->mac) }
=head2 last_comment
Returns the most recent comment from the logs for this device port.
=cut
sub last_comment {
my $row = (shift)->logs->search(undef,
{ order_by => { -desc => 'creation' }, rows => 1 })->first;
return ($row ? $row->log : '');
}
1; 1;

View File

@@ -22,14 +22,17 @@ __PACKAGE__->result_source_instance->view_definition(<<'ENDSQL');
a.log, a.log,
a.finished a.finished
FROM device_port p FROM device_port p
JOIN device d ON d.ip = p.ip JOIN device d
JOIN ADMIN a ON p.remote_ip = a.device ON d.ip = p.ip
WHERE p.remote_ip NOT IN LEFT JOIN admin a
(SELECT ALIAS ON (p.remote_ip = a.device AND a.action = 'discover')
FROM device_ip) WHERE
AND a.action = 'discover' (p.remote_ip NOT IN (SELECT alias FROM device_ip))
ORDER BY p.remote_ip, OR
a.finished DESC ((p.remote_ip IS NULL) AND p.is_uplink)
ORDER BY
p.remote_ip ASC,
a.finished DESC
ENDSQL ENDSQL
__PACKAGE__->add_columns( __PACKAGE__->add_columns(

View File

@@ -594,7 +594,6 @@ sub delete {
$schema->resultset('Admin')->search({ $schema->resultset('Admin')->search({
device => { '-in' => $devices->as_query }, device => { '-in' => $devices->as_query },
action => { '-like' => 'queued%' },
})->delete; })->delete;
$schema->resultset('Topology')->search({ $schema->resultset('Topology')->search({

View File

@@ -157,6 +157,7 @@ sub delete {
DevicePortVlan DevicePortVlan
DevicePortWireless DevicePortWireless
DevicePortSsid DevicePortSsid
DevicePortLog
/) { /) {
$schema->resultset($set)->search( $schema->resultset($set)->search(
{ ip => { '-in' => $ports->as_query }}, { ip => { '-in' => $ports->as_query }},

View File

@@ -14,6 +14,7 @@ hook 'before' => sub {
my @default_port_columns_right = ( my @default_port_columns_right = (
{ name => 'c_descr', label => 'Description', default => '' }, { name => 'c_descr', label => 'Description', default => '' },
{ name => 'c_comment', label => 'Last Comment', default => '' },
{ name => 'c_type', label => 'Type', default => '' }, { name => 'c_type', label => 'Type', default => '' },
{ name => 'c_duplex', label => 'Duplex', default => '' }, { name => 'c_duplex', label => 'Duplex', default => '' },
{ name => 'c_lastchange', label => 'Last Change', default => '' }, { name => 'c_lastchange', label => 'Last Change', default => '' },

View File

@@ -0,0 +1,30 @@
package App::Netdisco::Web::Plugin::Report::InventoryByModelByOS;
use Dancer ':syntax';
use Dancer::Plugin::DBIC;
use Dancer::Plugin::Auth::Extensible;
use App::Netdisco::Web::Plugin;
register_report(
{ category => 'Device',
tag => 'inventorybymodelbyos',
label => 'Inventory by Model by OS',
provides_csv => 0,
}
);
get '/ajax/content/report/inventorybymodelbyos' => require_login sub {
my @results = schema('netdisco')->resultset('Device')->search(undef, {
columns => [qw/vendor model os os_ver/],
select => [ { count => 'os_ver' } ],
as => [qw/ os_ver_count /],
group_by => [qw/ vendor model os os_ver /],
order_by => ['vendor', 'model', { -desc => 'count' }, 'os_ver'],
})->hri->all;
template 'ajax/report/inventorybymodelbyos.tt', { results => \@results, },
{ layout => undef };
};
1;

View File

@@ -14,6 +14,32 @@ register_report({
hidden => true, hidden => true,
}); });
sub _sanity_ok {
return 0 unless
param('ip') =~ m/^[[:print:]]+$/
and param('port') =~ m/^[[:print:]]+$/
and param('log') =~ m/^[[:print:]]+$/;
return 1;
}
ajax '/ajax/control/report/portlog/add' => require_login sub {
send_error('Bad Request', 400) unless _sanity_ok();
schema('netdisco')->txn_do(sub {
my $user = schema('netdisco')->resultset('DevicePortLog')
->create({
ip => param('ip'),
port => param('port'),
reason => 'other',
log => param('log'),
username => session('logged_in_user'),
userip => request->remote_address,
action => 'comment',
});
});
};
ajax '/ajax/content/report/portlog' => require_role port_control => sub { ajax '/ajax/content/report/portlog' => require_role port_control => sub {
my $device = param('q'); my $device = param('q');
my $port = param('f'); my $port = param('f');

View File

@@ -46,6 +46,7 @@ web_plugins:
- Report::HalfDuplex - Report::HalfDuplex
- Report::DeviceAddrNoDNS - Report::DeviceAddrNoDNS
- Report::DeviceByLocation - Report::DeviceByLocation
- Report::InventoryByModelByOS
- Report::DeviceDnsMismatch - Report::DeviceDnsMismatch
- Report::DevicePoeStatus - Report::DevicePoeStatus
- Report::DuplexMismatch - Report::DuplexMismatch

View File

@@ -1,7 +1,7 @@
<table id="data-table" class="table table-striped table-bordered" width="100%" cellspacing="0"> <table id="data-table" class="table table-striped table-bordered" width="100%" cellspacing="0">
<thead> <thead>
<tr> <tr>
<th>Device Location Triggering<br>Last Discovery Attempt</th> <th>Observing Device</th>
<th>Undiscovered Neighbor</th> <th>Undiscovered Neighbor</th>
<th class="nd_center-cell">Last Discovery Attempt</th> <th class="nd_center-cell">Last Discovery Attempt</th>
<th class="nd_center-cell">Last Discovery Log</th> <th class="nd_center-cell">Last Discovery Log</th>
@@ -12,11 +12,18 @@
<tr> <tr>
<td><a href="[% device_ports %]&q=[% row.ip | uri %]&f=[% row.port | uri %]"> <td><a href="[% device_ports %]&q=[% row.ip | uri %]&f=[% row.port | uri %]">
[% row.dns || row.name || row.ip | html_entity %] ( [% row.port | html_entity %] ) </a></td> [% row.dns || row.name || row.ip | html_entity %] ( [% row.port | html_entity %] ) </a></td>
<td><a href="[% search_node %]&q=[% row.remote_ip | uri %]"> <td>
[% row.remote_ip | html_entity %]</a> [% IF row.remote_ip %]
([% row.remote_port | html_entity %]) <a href="[% search_node %]&q=[% row.remote_ip | uri %]">
[% ' id: '_ row.remote_id IF row.remote_id %] [% row.remote_ip | html_entity %]
[% ' type: '_ row.remote_type IF row.remote_type %]</td> </a> ([% row.remote_port | html_entity %])
[% '<br />' IF row.remote_id or row.remote_type %]
[% ' id: '_ row.remote_id IF row.remote_id %]
[% ' type: '_ row.remote_type IF row.remote_type %]
[% ELSE %]
Known Device's MAC Address seen on this Port during Macsuck
[% END %]
</td>
<td class="nd_center-cell">[% row.finished | html_entity %]</td> <td class="nd_center-cell">[% row.finished | html_entity %]</td>
<td class="nd_center-cell">[% row.log | html_entity %]</td> <td class="nd_center-cell">[% row.log | html_entity %]</td>
</tr> </tr>

View File

@@ -1,5 +1,5 @@
[% USE CSV -%] [% USE CSV -%]
[% CSV.dump([ 'Device Triggering Last Discovery Attempt' 'Device Port' [% CSV.dump([ 'Observing Device' 'Device Port'
'Remote IP' 'Remote Port' 'Remote ID' 'Remote Type' 'Remote IP' 'Remote Port' 'Remote ID' 'Remote Type'
'Last Discovery Attempt' 'Discovery Log']) %] 'Last Discovery Attempt' 'Discovery Log']) %]

View File

@@ -82,6 +82,10 @@
rel="tooltip" data-placement="top" data-offset="3" rel="tooltip" data-placement="top" data-offset="3"
data-animation="" data-title="Enable Port"></i> data-animation="" data-title="Enable Port"></i>
</span> </span>
[% END %]
[% ELSE %]
<td nowrap class="nd_editable-cell"
data-order="[% row.port | html_entity %]" data-filter="[% row.port | html_entity %]">
[% END %] [% END %]
<a class="nd_log-icon" <a class="nd_log-icon"
href="[% uri_for('/report/portlog') %]?q=[% device.ip | uri %]&f=[% row.port | uri %]"> href="[% uri_for('/report/portlog') %]?q=[% device.ip | uri %]&f=[% row.port | uri %]">
@@ -89,9 +93,6 @@
rel="tooltip" data-placement="top" data-offset="3" rel="tooltip" data-placement="top" data-offset="3"
data-animation="" data-title="View Port Log"></i> data-animation="" data-title="View Port Log"></i>
</a> </a>
[% ELSE %]
<td nowrap data-order="[% row.port | html_entity %]" data-filter="[% row.port | html_entity %]">
[% END %]
<a class="nd_this-port-only nd_port-only-first" href="[% uri_for('/device', <a class="nd_this-port-only nd_port-only-first" href="[% uri_for('/device',
self_options) %]&q=[% params.q | uri %]&f=[% row.port | uri %]&prefer=port"> self_options) %]&q=[% params.q | uri %]&f=[% row.port | uri %]&prefer=port">
[% IF row.is_master %] [% IF row.is_master %]
@@ -121,6 +122,10 @@
<td nowrap>[% row.descr | html_entity %]</td> <td nowrap>[% row.descr | html_entity %]</td>
[% END %] [% END %]
[% IF params.c_comment %]
<td nowrap>[% row.last_comment | html_entity %]</td>
[% END %]
[% IF params.c_type %] [% IF params.c_type %]
<td>[% row.type | html_entity %]</td> <td>[% row.type | html_entity %]</td>
[% END %] [% END %]

View File

@@ -61,6 +61,10 @@
[% myport.push(row.descr) %] [% myport.push(row.descr) %]
[% END %] [% END %]
[% IF params.c_comment %]
[% myport.push(row.last_comment) %]
[% END %]
[% IF params.c_type %] [% IF params.c_type %]
[% myport.push(row.type) %] [% myport.push(row.type) %]
[% END %] [% END %]

View File

@@ -0,0 +1,71 @@
<table id="nsbi-data-table" class="table table-bordered table-hover" width="100%" cellspacing="0">
<thead>
<tr>
<th>Model</th>
<th>Operating System Version</th>
<th>Count</th>
</tr>
</thead>
</tbody>
[% FOREACH row IN results %]
<tr>
<td>
<a href="[% search_device %]&q=[% row.model | uri %]&vendor=[% row.vendor | uri %]&model=[% row.model | uri %]">
[% row.vendor.ucfirst | html_entity %]&nbsp;[% row.model | html_entity %]</a>
[% IF row.os %] running &quot;[% row.os | html_entity %]&quot;[% END %]
</td>
<td>
<a class="nd_linkcell"
href="[% search_device %]&q=[% row.os_ver | uri %]&vendor=[% row.vendor | uri %]&model=[% row.model | uri %]&os=[% row.os | uri %]&os_ver=[% row.os_ver | uri %]&matchall=on">
[% row.os_ver | html_entity %]</a>
</td>
<td>[% row.os_ver_count | html_entity %]</td>
</tr>
[% END %]
</tbody>
</table>
<style>
tr.group,
tr.group:hover {
background-color: #ddd !important;
}
</style>
<script>
$(document).ready(function() {
var table = $('#nsbi-data-table').DataTable({
"columnDefs": [
{ "visible": false, "targets": 0 }
],
sort: false,
"drawCallback": function ( settings ) {
var api = this.api();
var rows = api.rows( {page:'current'} ).nodes();
var last=null;
api.column(0, {page:'current'} ).data().each( function ( group, i ) {
if ( last !== group ) {
$(rows).eq( i ).before(
'<tr class="group"><td colspan="2">'+group+'</td></tr>'
);
last = group;
}
} );
},
[% INCLUDE 'ajax/datatabledefaults.tt' -%]
} );
// Order by the grouping
$('#nsbi-data-table tbody').on( 'click', 'tr.group', function () {
var currentOrder = table.order()[0];
if ( currentOrder[0] === 0 && currentOrder[1] === 'asc' ) {
table.order( [ 0, 'desc' ] ).draw();
}
else {
table.order( [ 0, 'asc' ] ).draw();
}
} );
} );
</script>

View File

@@ -4,8 +4,8 @@
[% FOREACH row IN results %] [% FOREACH row IN results %]
[% mylist = [] %] [% mylist = [] %]
[% mylist.push(row.ip) %] [% mylist.push(row.ip) %]
[% mylist.push(row.mac) %]
[% mylist.push(row.dns) %] [% mylist.push(row.dns) %]
[% mylist.push(row.time_first) %]
[% mylist.push(row.time_last) %] [% mylist.push(row.time_last) %]
[% CSV.dump(mylist) %] [% CSV.dump(mylist) %]

View File

@@ -1,6 +1,3 @@
[% IF results.count == 0 %]
<div class="span2 alert alert-info">This port's log is empty.</div>
[% ELSE %]
<table id="data-table" class="table table-bordered table-condensed table-striped" width="100%" cellspacing="0"> <table id="data-table" class="table table-bordered table-condensed table-striped" width="100%" cellspacing="0">
<thead> <thead>
<tr> <tr>
@@ -10,9 +7,24 @@
<th class="nd_center-cell">Action</th> <th class="nd_center-cell">Action</th>
<th class="nd_center-cell">Reason</th> <th class="nd_center-cell">Reason</th>
<th class="nd_center-cell">Log</th> <th class="nd_center-cell">Log</th>
<th class="nd_center-cell">Action</th>
</tr> </tr>
</thead> </thead>
</tbody> </tbody>
<tr>
<td class="nd_center-cell">-</td>
<td class="nd_center-cell">[% session.logged_in_user | html_entity %]</td>
<td class="nd_center-cell">-</td>
<td class="nd_center-cell">comment</td>
<td class="nd_center-cell">Other</td>
<td class="nd_center-cell"><input data-form="add" class="span4" name="log" type="text" placeholder="Add comment..."></td>
<input data-form="add" name="ip" type="hidden" value="[% params.q | html_entity %]">
<input data-form="add" name="port" type="hidden" value="[% params.f | html_entity %]">
<td class="nd_center-cell">
<button class="btn btn-small nd_adminbutton" name="add" type="submit"><i class="icon-plus-sign"></i> Add</button>
</td>
</tr>
[% WHILE (row = results.next) %] [% WHILE (row = results.next) %]
<tr> <tr>
<td class="nd_center-cell">[% row.creation_stamp | html_entity %]</td> <td class="nd_center-cell">[% row.creation_stamp | html_entity %]</td>
@@ -21,15 +33,16 @@
<td class="nd_center-cell">[% row.action | html_entity %]</td> <td class="nd_center-cell">[% row.action | html_entity %]</td>
<td class="nd_center-cell">[% settings.port_control_reasons.item(row.reason) || row.reason | html_entity %]</td> <td class="nd_center-cell">[% settings.port_control_reasons.item(row.reason) || row.reason | html_entity %]</td>
<td class="nd_center-cell">[% row.log || '-' | html_entity %]</td> <td class="nd_center-cell">[% row.log || '-' | html_entity %]</td>
<td class="nd_center-cell"></td>
</tr> </tr>
[% END %] [% END %]
</tbody> </tbody>
</table> </table>
[% END %]
<script> <script>
$(document).ready(function() { $(document).ready(function() {
$('#data-table').dataTable({ $('#data-table').dataTable({
sort: false,
[% INCLUDE 'ajax/datatabledefaults.tt' -%] [% INCLUDE 'ajax/datatabledefaults.tt' -%]
} ); } );
} ); } );

View File

@@ -52,4 +52,35 @@
,delay: 150 ,delay: 150
,minLength: 3 ,minLength: 3
}); });
// dynamically bind to all forms in the table
$('.content').on('click', '.nd_adminbutton', function(event) {
// stop form from submitting normally
event.preventDefault();
// what purpose - add/update/del
var mode = $(this).attr('name');
// submit the query and put results into the tab pane
$.ajax({
type: 'POST'
,async: true
,dataType: 'html'
,url: uri_base + '/ajax/control/report/' + tab + '/' + mode
,data: $(this).closest('tr').find('input[data-form="' + mode + '"]').serializeArray()
,beforeSend: function() {
$(target).html(
'<div class="span2 alert">Request submitted...</div>'
);
}
,success: function() {
$('#' + tab + '_form').trigger('submit');
}
// skip any error reporting for now
// TODO: fix sanity_ok in Netdisco Web
,error: function() {
$('#' + tab + '_form').trigger('submit');
}
});
});
}); });