Merge branch 'master' of ssh://git.code.sf.net/p/netdisco/netdisco-ng
This commit is contained in:
		| @@ -6,7 +6,9 @@ use warnings; | ||||
|  | ||||
| use base 'DBIx::Class::Schema'; | ||||
|  | ||||
| __PACKAGE__->load_namespaces; | ||||
| __PACKAGE__->load_namespaces( | ||||
|     default_resultset_class => 'ResultSet', | ||||
| ); | ||||
|  | ||||
| our $VERSION = 31; # schema version used for upgrades, keep as integer | ||||
|  | ||||
|   | ||||
							
								
								
									
										45
									
								
								Netdisco/lib/App/Netdisco/DB/Result/Virtual/CidrIps.pm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								Netdisco/lib/App/Netdisco/DB/Result/Virtual/CidrIps.pm
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,45 @@ | ||||
| package App::Netdisco::DB::Result::Virtual::CidrIps; | ||||
|  | ||||
| use strict; | ||||
| use warnings; | ||||
|  | ||||
| use utf8; | ||||
| use base 'DBIx::Class::Core'; | ||||
|  | ||||
| __PACKAGE__->table_class('DBIx::Class::ResultSource::View'); | ||||
|  | ||||
| __PACKAGE__->table('cidr_ips'); | ||||
| __PACKAGE__->result_source_instance->is_virtual(1); | ||||
| __PACKAGE__->result_source_instance->view_definition(<<'ENDSQL'); | ||||
| SELECT host(network (cidr) + sub.int)::inet AS ip, NULL::text AS dns, | ||||
|   NULL::timestamp AS time_first, NULL::timestamp AS time_last, false::boolean AS active | ||||
| FROM | ||||
|   ( SELECT cidr, generate_series(1, broadcast(cidr) - (network(cidr)) - 1) AS int | ||||
| FROM ( | ||||
| SELECT CASE WHEN family(cidr) = 4 THEN cidr | ||||
|        ELSE '0.0.0.0/32'::inet | ||||
|        END AS cidr | ||||
| FROM ( SELECT ?::inet AS cidr) AS input) AS addr | ||||
| ) AS sub | ||||
| ENDSQL | ||||
|  | ||||
| __PACKAGE__->add_columns( | ||||
|   "ip", | ||||
|   { data_type => "inet", is_nullable => 0 }, | ||||
|   "dns", | ||||
|   { data_type => "text", is_nullable => 1 }, | ||||
|   "active", | ||||
|   { data_type => "boolean", is_nullable => 1 }, | ||||
|   "time_first", | ||||
|   { | ||||
|     data_type     => "timestamp", | ||||
|     is_nullable   => 1, | ||||
|   }, | ||||
|   "time_last", | ||||
|   { | ||||
|     data_type     => "timestamp", | ||||
|     is_nullable   => 1, | ||||
|   }, | ||||
| ); | ||||
|  | ||||
| 1; | ||||
							
								
								
									
										11
									
								
								Netdisco/lib/App/Netdisco/DB/ResultSet.pm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								Netdisco/lib/App/Netdisco/DB/ResultSet.pm
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | ||||
| package App::Netdisco::DB::ResultSet; | ||||
|  | ||||
| use strict; | ||||
| use warnings; | ||||
|  | ||||
| use base 'DBIx::Class::ResultSet'; | ||||
|  | ||||
| __PACKAGE__->load_components( | ||||
|     qw{Helper::ResultSet::SetOperations Helper::ResultSet::Shortcut}); | ||||
|  | ||||
| 1; | ||||
| @@ -1,5 +1,5 @@ | ||||
| package App::Netdisco::DB::ResultSet::Admin; | ||||
| use base 'DBIx::Class::ResultSet'; | ||||
| use base 'App::Netdisco::DB::ResultSet'; | ||||
|  | ||||
| use strict; | ||||
| use warnings FATAL => 'all'; | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| package App::Netdisco::DB::ResultSet::Device; | ||||
| use base 'DBIx::Class::ResultSet'; | ||||
| use base 'App::Netdisco::DB::ResultSet'; | ||||
|  | ||||
| use strict; | ||||
| use warnings FATAL => 'all'; | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| package App::Netdisco::DB::ResultSet::DevicePort; | ||||
| use base 'DBIx::Class::ResultSet'; | ||||
| use base 'App::Netdisco::DB::ResultSet'; | ||||
|  | ||||
| use strict; | ||||
| use warnings FATAL => 'all'; | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| package App::Netdisco::DB::ResultSet::Node; | ||||
| use base 'DBIx::Class::ResultSet'; | ||||
| use base 'App::Netdisco::DB::ResultSet'; | ||||
|  | ||||
| use strict; | ||||
| use warnings FATAL => 'all'; | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| package App::Netdisco::DB::ResultSet::NodeIp; | ||||
| use base 'DBIx::Class::ResultSet'; | ||||
| use base 'App::Netdisco::DB::ResultSet'; | ||||
|  | ||||
| use strict; | ||||
| use warnings FATAL => 'all'; | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| package App::Netdisco::DB::ResultSet::NodeWireless; | ||||
| use base 'DBIx::Class::ResultSet'; | ||||
| use base 'App::Netdisco::DB::ResultSet'; | ||||
|  | ||||
| use strict; | ||||
| use warnings FATAL => 'all'; | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| package App::Netdisco::DB::ResultSet::Subnet; | ||||
| use base 'DBIx::Class::ResultSet'; | ||||
| use base 'App::Netdisco::DB::ResultSet'; | ||||
|  | ||||
| use strict; | ||||
| use warnings FATAL => 'all'; | ||||
|   | ||||
| @@ -137,6 +137,10 @@ Port | ||||
|  | ||||
| =item * | ||||
|  | ||||
| IP | ||||
|  | ||||
| =item * | ||||
|  | ||||
| Node | ||||
|  | ||||
| =item * | ||||
|   | ||||
| @@ -16,7 +16,7 @@ set( | ||||
|   '_admin_tasks'  => {}, | ||||
|   '_reports_menu' => {}, | ||||
|   '_reports' => {}, | ||||
|   '_report_order' => [qw/Device Port Node VLAN Network Wireless/], | ||||
|   '_report_order' => [qw/Device Port IP Node VLAN Network Wireless/], | ||||
| ); | ||||
|  | ||||
| # this is what Dancer::Template::TemplateToolkit does by default | ||||
|   | ||||
							
								
								
									
										169
									
								
								Netdisco/lib/App/Netdisco/Web/Plugin/Report/IpInventory.pm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										169
									
								
								Netdisco/lib/App/Netdisco/Web/Plugin/Report/IpInventory.pm
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,169 @@ | ||||
| package App::Netdisco::Web::Plugin::Report::IpInventory; | ||||
|  | ||||
| use Dancer ':syntax'; | ||||
| use Dancer::Plugin::DBIC; | ||||
| use Dancer::Plugin::Auth::Extensible; | ||||
|  | ||||
| use App::Netdisco::Web::Plugin; | ||||
|  | ||||
| register_report( | ||||
|     {   category     => 'IP', | ||||
|         tag          => 'ipinventory', | ||||
|         label        => 'IP Inventory', | ||||
|         provides_csv => 1, | ||||
|     } | ||||
| ); | ||||
|  | ||||
| # Following two Perl Core 5.10+ | ||||
| use Time::Piece; | ||||
| use Time::Seconds; | ||||
|  | ||||
| hook 'before' => sub { | ||||
|  | ||||
|     return | ||||
|         unless ( request->path eq uri_for('/report/ipinventory')->path | ||||
|         or index( request->path, uri_for('/ajax/content/report/ipinventory')->path ) | ||||
|         == 0 ); | ||||
|  | ||||
|     my $start = Time::Piece->new - ONE_DAY * 29; | ||||
|  | ||||
|     params->{'limit'} ||= 256; | ||||
|     params->{'daterange'} | ||||
|         ||= $start->ymd . " to " . Time::Piece->new->ymd; | ||||
| }; | ||||
|  | ||||
| get '/ajax/content/report/ipinventory' => require_login sub { | ||||
|  | ||||
|     # Default to something simple with no results to prevent | ||||
|     # "Search failed!" error | ||||
|     my $subnet = param('subnet') || '0.0.0.0/32'; | ||||
|  | ||||
|     my $age    = param('age_on')     || '0'; | ||||
|     my $agenot = param('age_invert') || '0'; | ||||
|  | ||||
|     my ( $start, $end ) = param('daterange') =~ /(\d+-\d+-\d+)/gmx; | ||||
|  | ||||
|     my $limit = param('limit') || 256; | ||||
|     my $order = param('order') || 'IP'; | ||||
|     my $never = param('never') || '0'; | ||||
|  | ||||
|     # We need a reasonable limit to prevent a potential DoS, especially if | ||||
|     # 'never' is true.  TODO: Need better input validation, both JS and | ||||
|     # server-side to provide user feedback | ||||
|     $limit = 8192 if $limit > 8192; | ||||
|     $order = $order eq 'IP' ? \'ip ASC' : \'age DESC'; | ||||
|  | ||||
|     my $rs1 = schema('netdisco')->resultset('DeviceIp')->search( | ||||
|         undef, | ||||
|         {   join   => 'device', | ||||
|             select => [ | ||||
|                 'alias AS ip', | ||||
|                 'creation AS time_first', | ||||
|                 'device.last_discover AS time_last', | ||||
|                 'dns', | ||||
|                 \'true AS active', | ||||
|                 \'false AS node', | ||||
|                 \'age(device.last_discover) AS age' | ||||
|             ], | ||||
|             as => [qw( ip time_first time_last dns active node age)], | ||||
|         } | ||||
|     )->hri; | ||||
|  | ||||
|     my $rs2 = schema('netdisco')->resultset('NodeIp')->search( | ||||
|         undef, | ||||
|         {   columns   => [qw( ip time_first time_last dns active)], | ||||
|             '+select' => [ \'true AS node', \'age(time_last) AS age' ], | ||||
|             '+as'     => [ 'node', 'age' ], | ||||
|         } | ||||
|     )->hri; | ||||
|  | ||||
|     my $rs3 = schema('netdisco')->resultset('NodeNbt')->search( | ||||
|         undef, | ||||
|         {   columns   => [qw( ip time_first time_last )], | ||||
|             '+select' => [ | ||||
|                 'nbname AS dns', 'active', | ||||
|                 \'true AS node', \'age(time_last) AS age' | ||||
|             ], | ||||
|             '+as' => [ 'dns', 'active', 'node', 'age' ], | ||||
|         } | ||||
|     )->hri; | ||||
|  | ||||
|     my $rs_union = $rs1->union( [ $rs2, $rs3 ] ); | ||||
|  | ||||
|     if ( $never ) { | ||||
|         my $rs4 = schema('netdisco')->resultset('Virtual::CidrIps')->search( | ||||
|             undef, | ||||
|             {   bind => [ $subnet ], | ||||
|                 columns   => [qw( ip time_first time_last dns active)], | ||||
|                 '+select' => [ \'false AS node', \'age(time_last) AS age' ], | ||||
|                 '+as'     => [ 'node', 'age' ], | ||||
|             } | ||||
|         )->hri; | ||||
|  | ||||
|         $rs_union = $rs_union->union( [$rs4] ); | ||||
|     } | ||||
|  | ||||
|     my $rs_sub = $rs_union->search( | ||||
|         { ip => { '<<' => $subnet } }, | ||||
|         {   order_by => [qw( ip time_last )], | ||||
|             select   => [ | ||||
|                 \'DISTINCT ON (ip) ip', | ||||
|                 'dns', | ||||
|                 \'date_trunc(\'second\', time_last) AS time_last', | ||||
|                 \'date_trunc(\'second\', time_first) AS time_first', | ||||
|                 'active', | ||||
|                 'node', | ||||
|                 'age' | ||||
|             ], | ||||
|             as => [ | ||||
|                 'ip',     'dns',  'time_last', 'time_first', | ||||
|                 'active', 'node', 'age' | ||||
|             ], | ||||
|         } | ||||
|     )->as_query; | ||||
|  | ||||
|     my $rs; | ||||
|     if ( $age && $start && $end ) { | ||||
|         $start = $start . ' 00:00:00'; | ||||
|         $end   = $end . ' 23:59:59'; | ||||
|  | ||||
|         if ( $agenot ) { | ||||
|             $rs = $rs_union->search( | ||||
|                 {   -or => [ | ||||
|                         time_first => [ { '<', $start }, undef ], | ||||
|                         time_last => { '>', $end }, | ||||
|                     ] | ||||
|                 }, | ||||
|                 { from => { me => $rs_sub }, } | ||||
|             ); | ||||
|         } | ||||
|         else { | ||||
|             $rs = $rs_union->search( | ||||
|                 {   -and => [ | ||||
|                         time_first => { '>=', $start }, | ||||
|                         time_last  => { '<=', $end }, | ||||
|                     ] | ||||
|                 }, | ||||
|                 { from => { me => $rs_sub }, } | ||||
|             ); | ||||
|         } | ||||
|     } | ||||
|     else { | ||||
|         $rs = $rs_union->search( undef, { from => { me => $rs_sub }, } ); | ||||
|     } | ||||
|  | ||||
|     my @results = $rs->order_by($order)->limit($limit)->all; | ||||
|     return unless scalar @results; | ||||
|  | ||||
|     if ( request->is_ajax ) { | ||||
|         template 'ajax/report/ipinventory.tt', { results => \@results, }, | ||||
|             { layout => undef }; | ||||
|     } | ||||
|     else { | ||||
|         header( 'Content-Type' => 'text/comma-separated-values' ); | ||||
|         template 'ajax/report/ipinventory_csv.tt', { results => \@results, }, | ||||
|             { layout => undef }; | ||||
|     } | ||||
| }; | ||||
|  | ||||
| 1; | ||||
| @@ -55,4 +55,15 @@ ajax '/ajax/data/port/typeahead' => require_login sub { | ||||
|     to_json \@$results; | ||||
| }; | ||||
|  | ||||
| ajax '/ajax/data/subnet/typeahead' => require_login sub { | ||||
|     my $q = param('query') || param('term'); | ||||
|     $q = "$q\%" if $q !~ m/\%/; | ||||
|     my $nets = schema('netdisco')->resultset('Subnet')->search( | ||||
|            { 'me.net::text'  => { '-ilike' => $q }}, | ||||
|            { columns => ['net'] } ); | ||||
|  | ||||
|     content_type 'application/json'; | ||||
|     to_json [map {$_->net} $nets->all]; | ||||
| }; | ||||
|  | ||||
| true; | ||||
|   | ||||
| @@ -45,6 +45,7 @@ web_plugins: | ||||
|   - Report::DeviceByLocation | ||||
|   - Report::DevicePoeStatus | ||||
|   - Report::DuplexMismatch | ||||
|   - Report::IpInventory | ||||
|   - Report::NodeMultiIPs | ||||
|   - Report::PhonesDiscovered | ||||
|   - Report::SsidInventory | ||||
| @@ -56,6 +57,7 @@ web_plugins: | ||||
|   - AdminTask::Topology | ||||
|   - AdminTask::UserLog | ||||
|   - AdminTask::Users | ||||
|   - AdminTask::PortLog | ||||
|   - Search::Device | ||||
|   - Search::Node | ||||
|   - Search::VLAN | ||||
|   | ||||
							
								
								
									
										235
									
								
								Netdisco/share/public/css/daterangepicker-bs2.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										235
									
								
								Netdisco/share/public/css/daterangepicker-bs2.css
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,235 @@ | ||||
| /*! | ||||
|  * Stylesheet for the Date Range Picker, for use with Bootstrap 2.x | ||||
|  * | ||||
|  * Copyright 2013 Dan Grossman ( http://www.dangrossman.info ) | ||||
|  * Licensed under the Apache License v2.0 | ||||
|  * http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  * | ||||
|  * Built for http://www.improvely.com | ||||
|  */ | ||||
|  | ||||
| .daterangepicker.dropdown-menu { | ||||
|   max-width: none; | ||||
|   z-index: 3000; | ||||
| } | ||||
|  | ||||
| .daterangepicker.opensleft .ranges, .daterangepicker.opensleft .calendar { | ||||
|   float: left; | ||||
|   margin: 4px; | ||||
| } | ||||
|  | ||||
| .daterangepicker.opensright .ranges, .daterangepicker.opensright .calendar { | ||||
|   float: right; | ||||
|   margin: 4px; | ||||
| } | ||||
|  | ||||
| .daterangepicker .ranges { | ||||
|   width: 160px; | ||||
|   text-align: left; | ||||
| } | ||||
|  | ||||
| .daterangepicker .ranges .range_inputs>div { | ||||
|   float: left; | ||||
| } | ||||
|  | ||||
| .daterangepicker .ranges .range_inputs>div:nth-child(2) { | ||||
|   padding-left: 11px; | ||||
| } | ||||
|  | ||||
| .daterangepicker .calendar { | ||||
|   display: none; | ||||
|   max-width: 250px; | ||||
| } | ||||
|  | ||||
| .daterangepicker .calendar th, .daterangepicker .calendar td { | ||||
|   font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; | ||||
|   white-space: nowrap; | ||||
|   text-align: center; | ||||
| } | ||||
|  | ||||
| .daterangepicker .ranges label { | ||||
|   color: #333; | ||||
|   font-size: 11px; | ||||
|   margin-bottom: 2px; | ||||
|   text-transform: uppercase; | ||||
|   text-shadow: 1px 1px 0 #fff; | ||||
| } | ||||
|  | ||||
| .daterangepicker .ranges input { | ||||
|   font-size: 11px; | ||||
| } | ||||
|  | ||||
| .daterangepicker .ranges ul { | ||||
|   list-style: none; | ||||
|   margin: 0; | ||||
|   padding: 0; | ||||
| } | ||||
|  | ||||
| .daterangepicker .ranges li { | ||||
|   font-size: 13px; | ||||
|   background: #f5f5f5; | ||||
|   border: 1px solid #f5f5f5; | ||||
|   color: #08c; | ||||
|   padding: 3px 12px; | ||||
|   margin-bottom: 8px; | ||||
|   -webkit-border-radius: 5px; | ||||
|   -moz-border-radius: 5px; | ||||
|   border-radius: 5px; | ||||
|   cursor: pointer; | ||||
| } | ||||
|  | ||||
| .daterangepicker .ranges li.active, .daterangepicker .ranges li:hover { | ||||
|   background: #08c; | ||||
|   border: 1px solid #08c; | ||||
|   color: #fff; | ||||
| } | ||||
|  | ||||
| .daterangepicker .calendar-date { | ||||
|   border: 1px solid #ddd; | ||||
|   padding: 4px; | ||||
|   border-radius: 4px; | ||||
|   background: #fff; | ||||
| } | ||||
|  | ||||
| .daterangepicker .calendar-time { | ||||
|   text-align: center; | ||||
|   margin: 8px auto 0 auto; | ||||
|   line-height: 30px; | ||||
| } | ||||
|  | ||||
| .daterangepicker { | ||||
|   position: absolute; | ||||
|   background: #fff; | ||||
|   top: 100px; | ||||
|   left: 20px; | ||||
|   padding: 4px; | ||||
|   margin-top: 1px; | ||||
|   -webkit-border-radius: 4px; | ||||
|   -moz-border-radius: 4px; | ||||
|   border-radius: 4px; | ||||
| } | ||||
|  | ||||
| .daterangepicker.opensleft:before { | ||||
|   position: absolute; | ||||
|   top: -7px; | ||||
|   right: 9px; | ||||
|   display: inline-block; | ||||
|   border-right: 7px solid transparent; | ||||
|   border-bottom: 7px solid #ccc; | ||||
|   border-left: 7px solid transparent; | ||||
|   border-bottom-color: rgba(0, 0, 0, 0.2); | ||||
|   content: ''; | ||||
| } | ||||
|  | ||||
| .daterangepicker.opensleft:after { | ||||
|   position: absolute; | ||||
|   top: -6px; | ||||
|   right: 10px; | ||||
|   display: inline-block; | ||||
|   border-right: 6px solid transparent; | ||||
|   border-bottom: 6px solid #fff; | ||||
|   border-left: 6px solid transparent; | ||||
|   content: ''; | ||||
| } | ||||
|  | ||||
| .daterangepicker.opensright:before { | ||||
|   position: absolute; | ||||
|   top: -7px; | ||||
|   left: 9px; | ||||
|   display: inline-block; | ||||
|   border-right: 7px solid transparent; | ||||
|   border-bottom: 7px solid #ccc; | ||||
|   border-left: 7px solid transparent; | ||||
|   border-bottom-color: rgba(0, 0, 0, 0.2); | ||||
|   content: ''; | ||||
| } | ||||
|  | ||||
| .daterangepicker.opensright:after { | ||||
|   position: absolute; | ||||
|   top: -6px; | ||||
|   left: 10px; | ||||
|   display: inline-block; | ||||
|   border-right: 6px solid transparent; | ||||
|   border-bottom: 6px solid #fff; | ||||
|   border-left: 6px solid transparent; | ||||
|   content: ''; | ||||
| } | ||||
|  | ||||
| .daterangepicker table { | ||||
|   width: 100%; | ||||
|   margin: 0; | ||||
| } | ||||
|  | ||||
| .daterangepicker td, .daterangepicker th { | ||||
|   text-align: center; | ||||
|   width: 20px; | ||||
|   height: 20px; | ||||
|   -webkit-border-radius: 4px; | ||||
|   -moz-border-radius: 4px; | ||||
|   border-radius: 4px; | ||||
|   cursor: pointer; | ||||
|   white-space: nowrap; | ||||
| } | ||||
|  | ||||
| .daterangepicker td.off { | ||||
|   color: #999; | ||||
| } | ||||
|  | ||||
| .daterangepicker td.disabled { | ||||
|   color: #999; | ||||
| } | ||||
|  | ||||
| .daterangepicker td.available:hover, .daterangepicker th.available:hover { | ||||
|   background: #eee; | ||||
| } | ||||
|  | ||||
| .daterangepicker td.in-range { | ||||
|   background: #ebf4f8; | ||||
|   -webkit-border-radius: 0; | ||||
|   -moz-border-radius: 0; | ||||
|   border-radius: 0; | ||||
| } | ||||
|  | ||||
| .daterangepicker td.active, .daterangepicker td.active:hover { | ||||
|   background-color: #006dcc; | ||||
|   background-image: -moz-linear-gradient(top, #0088cc, #0044cc); | ||||
|   background-image: -ms-linear-gradient(top, #0088cc, #0044cc); | ||||
|   background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc)); | ||||
|   background-image: -webkit-linear-gradient(top, #0088cc, #0044cc); | ||||
|   background-image: -o-linear-gradient(top, #0088cc, #0044cc); | ||||
|   background-image: linear-gradient(top, #0088cc, #0044cc); | ||||
|   background-repeat: repeat-x; | ||||
|   filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0); | ||||
|   border-color: #0044cc #0044cc #002a80; | ||||
|   border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); | ||||
|   filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); | ||||
|   color: #fff; | ||||
|   text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); | ||||
| } | ||||
|  | ||||
| .daterangepicker td.week, .daterangepicker th.week { | ||||
|   font-size: 80%; | ||||
|   color: #ccc; | ||||
| } | ||||
|  | ||||
| .daterangepicker select.monthselect, .daterangepicker select.yearselect { | ||||
|   font-size: 12px; | ||||
|   padding: 1px; | ||||
|   height: auto; | ||||
|   margin: 0; | ||||
|   cursor: default; | ||||
| } | ||||
|  | ||||
| .daterangepicker select.monthselect { | ||||
|   margin-right: 2%; | ||||
|   width: 56%; | ||||
| } | ||||
|  | ||||
| .daterangepicker select.yearselect { | ||||
|   width: 40%; | ||||
| } | ||||
|  | ||||
| .daterangepicker select.hourselect, .daterangepicker select.minuteselect, .daterangepicker select.ampmselect { | ||||
|   width: 60px; | ||||
|   margin-bottom: 0; | ||||
| } | ||||
| @@ -495,6 +495,10 @@ td > form.nd_inline-form { | ||||
|   margin-left: 5px !important; | ||||
|   width: 152px; | ||||
| } | ||||
| .nd_sidebar-topinput { | ||||
|   margin-left: 5px !important; | ||||
|   width: 152px; | ||||
| } | ||||
|  | ||||
| /* set the day/mon/year drop-down width */ | ||||
| #nd_days-select { | ||||
| @@ -573,6 +577,10 @@ form .clearfix.success input { | ||||
|   padding-top: 3px !important; | ||||
| } | ||||
|  | ||||
| .nd_sidebar-legend { | ||||
|   margin-bottom: 9px; | ||||
| } | ||||
|  | ||||
| .nd_netmap-sidebar { | ||||
|   margin-top: 7px; | ||||
|   margin-left: -9px; | ||||
|   | ||||
							
								
								
									
										39
									
								
								Netdisco/share/views/ajax/report/ipinventory.tt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								Netdisco/share/views/ajax/report/ipinventory.tt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,39 @@ | ||||
| <table class="table table-bordered table-condensed table-striped nd_floatinghead"> | ||||
|   <thead> | ||||
|     <tr> | ||||
|       <th>Device</th> | ||||
|       <th class="nd_center-cell">DNS</th> | ||||
|       <th class="nd_center-cell">Last Used</th>       | ||||
|       <th class="nd_center-cell">First Discovered</th> | ||||
|     </tr> | ||||
|   </thead> | ||||
|   </tbody> | ||||
|     [% FOREACH row IN results %] | ||||
|     <tr> | ||||
|     [% IF row.time_last && row.node %] | ||||
|       <td><a href="[% search_node %]&q=[% row.ip | uri %]">[% row.ip | html_entity %]</a> | ||||
|         [% ' <i class="icon-book text-warning"></i> ' IF NOT row.active %] | ||||
|       </td> | ||||
|     [% ELSIF row.time_last %] | ||||
|       <td><a href="[% search_device %]&q=[% row.ip | uri %]">[% row.ip | html_entity %]</a> | ||||
|       </td> | ||||
|     [% ELSE %] | ||||
|       <td>[% row.ip | html_entity %]</td> | ||||
|     [% END %] | ||||
|       <td class="nd_center-cell">[% row.dns | html_entity %]</td> | ||||
|     [% IF row.age %] | ||||
|       [% age = row.age.replace('mon', 'month') %] | ||||
|       [% IF age.match('(day|month|year)') %] | ||||
|         [% age = age.remove('(-)?\d{2}:\d{2}.*$') %] | ||||
|       [% ELSE %] | ||||
|         [% age = age.replace('(\d{2}:\d{2}):\d{2}(\.\d*)$', '$1') %] | ||||
|       [% END %] | ||||
|     [% ELSE %] | ||||
|       [% age = 'Never' %] | ||||
|     [% END %] | ||||
|       <td class="nd_center-cell">[% age | html_entity %]</td> | ||||
|       <td class="nd_center-cell">[% row.time_first || 'Never' | html_entity %]</td> | ||||
|     </tr> | ||||
|     [% END %] | ||||
|   </tbody> | ||||
| </table> | ||||
							
								
								
									
										14
									
								
								Netdisco/share/views/ajax/report/ipinventory_csv.tt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								Netdisco/share/views/ajax/report/ipinventory_csv.tt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | ||||
| [% USE CSV %] | ||||
| [% CSV.dump([ 'Device' 'DNS' 'Time Last' 'Time First' ]) %] | ||||
|  | ||||
| [% FOREACH row IN results %] | ||||
|   [% mylist = [] %] | ||||
|   [% mylist.push(row.ip) %] | ||||
|   [% mylist.push(row.dns) %] | ||||
|   [% mylist.push(row.time_first) %] | ||||
|   [% mylist.push(row.time_last) %] | ||||
|   [% CSV.dump(mylist) %] | ||||
|  | ||||
| [% END %] | ||||
|  | ||||
|  | ||||
| @@ -128,6 +128,8 @@ | ||||
|  | ||||
|     // on page load, load the content for the active tab | ||||
|     [% IF params.tab %] | ||||
|     [% IF params.tab != 'ipinventory' %] | ||||
|     $('#[% params.tab %]_form').trigger("submit"); | ||||
|     [% END %] | ||||
|     [% END %] | ||||
|   }); | ||||
|   | ||||
							
								
								
									
										876
									
								
								Netdisco/share/views/js/daterangepicker.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										876
									
								
								Netdisco/share/views/js/daterangepicker.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,876 @@ | ||||
| /** | ||||
| * @version: 1.2 | ||||
| * @author: Dan Grossman http://www.dangrossman.info/ | ||||
| * @date: 2013-07-25 | ||||
| * @copyright: Copyright (c) 2012-2013 Dan Grossman. All rights reserved. | ||||
| * @license: Licensed under Apache License v2.0. See http://www.apache.org/licenses/LICENSE-2.0 | ||||
| * @website: http://www.improvely.com/ | ||||
| */ | ||||
| !function ($) { | ||||
|  | ||||
|     var DateRangePicker = function (element, options, cb) { | ||||
|         var hasOptions = typeof options == 'object'; | ||||
|         var localeObject; | ||||
|  | ||||
|         //option defaults | ||||
|  | ||||
|         this.startDate = moment().startOf('day'); | ||||
|         this.endDate = moment().startOf('day'); | ||||
|         this.minDate = false; | ||||
|         this.maxDate = false; | ||||
|         this.dateLimit = false; | ||||
|  | ||||
|         this.showDropdowns = false; | ||||
|         this.showWeekNumbers = false; | ||||
|         this.timePicker = false; | ||||
|         this.timePickerIncrement = 30; | ||||
|         this.timePicker12Hour = true; | ||||
|         this.ranges = {}; | ||||
|         this.opens = 'right'; | ||||
|  | ||||
|         this.buttonClasses = ['btn', 'btn-small']; | ||||
|         this.applyClass = 'btn-success'; | ||||
|         this.cancelClass = 'btn-default'; | ||||
|  | ||||
|         this.format = 'MM/DD/YYYY'; | ||||
|         this.separator = ' - '; | ||||
|  | ||||
|         this.locale = { | ||||
|             applyLabel: 'Apply', | ||||
|             cancelLabel: 'Cancel', | ||||
|             fromLabel: 'From', | ||||
|             toLabel: 'To', | ||||
|             weekLabel: 'W', | ||||
|             customRangeLabel: 'Custom Range', | ||||
|             daysOfWeek: moment()._lang._weekdaysMin.slice(), | ||||
|             monthNames: moment()._lang._monthsShort.slice(), | ||||
|             firstDay: 0 | ||||
|         }; | ||||
|  | ||||
|         this.cb = function () { }; | ||||
|  | ||||
|         // by default, the daterangepicker element is placed at the bottom of HTML body | ||||
|         this.parentEl = 'body'; | ||||
|  | ||||
|         //element that triggered the date range picker | ||||
|         this.element = $(element); | ||||
|  | ||||
|         if (this.element.hasClass('pull-right')) | ||||
|             this.opens = 'left'; | ||||
|  | ||||
|         if (this.element.is('input')) { | ||||
|             this.element.on({ | ||||
|                 click: $.proxy(this.show, this), | ||||
|                 focus: $.proxy(this.show, this) | ||||
|             }); | ||||
|         } else { | ||||
|             this.element.on('click', $.proxy(this.show, this)); | ||||
|         } | ||||
|  | ||||
|         localeObject = this.locale; | ||||
|  | ||||
|         if (hasOptions) { | ||||
|             if (typeof options.locale == 'object') { | ||||
|                 $.each(localeObject, function (property, value) { | ||||
|                     localeObject[property] = options.locale[property] || value; | ||||
|                 }); | ||||
|             } | ||||
|  | ||||
|             if (options.applyClass) { | ||||
|                 this.applyClass = options.applyClass; | ||||
|             } | ||||
|  | ||||
|             if (options.cancelClass) { | ||||
|                 this.cancelClass = options.cancelClass; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         var DRPTemplate = '<div class="daterangepicker dropdown-menu">' + | ||||
|                 '<div class="calendar left"></div>' + | ||||
|                 '<div class="calendar right"></div>' + | ||||
|                 '<div class="ranges">' + | ||||
|                   '<div class="range_inputs">' + | ||||
|                     '<div class="daterangepicker_start_input" style="float: left">' + | ||||
|                       '<label for="daterangepicker_start">' + this.locale.fromLabel + '</label>' + | ||||
|                       '<input class="input-mini" type="text" name="daterangepicker_start" value="" disabled="disabled" />' + | ||||
|                     '</div>' + | ||||
|                     '<div class="daterangepicker_end_input" style="float: left; padding-left: 11px">' + | ||||
|                       '<label for="daterangepicker_end">' + this.locale.toLabel + '</label>' + | ||||
|                       '<input class="input-mini" type="text" name="daterangepicker_end" value="" disabled="disabled" />' + | ||||
|                     '</div>' + | ||||
|                     '<button class="' + this.applyClass + ' applyBtn" disabled="disabled">' + this.locale.applyLabel + '</button> ' + | ||||
|                     '<button class="' + this.cancelClass + ' cancelBtn">' + this.locale.cancelLabel + '</button>' + | ||||
|                   '</div>' + | ||||
|                 '</div>' + | ||||
|               '</div>'; | ||||
|  | ||||
|         this.parentEl = (hasOptions && options.parentEl && $(options.parentEl)) || $(this.parentEl); | ||||
|         //the date range picker | ||||
|         this.container = $(DRPTemplate).appendTo(this.parentEl); | ||||
|  | ||||
|         if (hasOptions) { | ||||
|  | ||||
|             if (typeof options.format == 'string') | ||||
|                 this.format = options.format; | ||||
|  | ||||
|             if (typeof options.separator == 'string') | ||||
|                 this.separator = options.separator; | ||||
|  | ||||
|             if (typeof options.startDate == 'string') | ||||
|                 this.startDate = moment(options.startDate, this.format); | ||||
|  | ||||
|             if (typeof options.endDate == 'string') | ||||
|                 this.endDate = moment(options.endDate, this.format); | ||||
|  | ||||
|             if (typeof options.minDate == 'string') | ||||
|                 this.minDate = moment(options.minDate, this.format); | ||||
|  | ||||
|             if (typeof options.maxDate == 'string') | ||||
|                 this.maxDate = moment(options.maxDate, this.format); | ||||
|  | ||||
|             if (typeof options.startDate == 'object') | ||||
|                 this.startDate = moment(options.startDate); | ||||
|  | ||||
|             if (typeof options.endDate == 'object') | ||||
|                 this.endDate = moment(options.endDate); | ||||
|  | ||||
|             if (typeof options.minDate == 'object') | ||||
|                 this.minDate = moment(options.minDate); | ||||
|  | ||||
|             if (typeof options.maxDate == 'object') | ||||
|                 this.maxDate = moment(options.maxDate); | ||||
|  | ||||
|             if (typeof options.ranges == 'object') { | ||||
|                 for (var range in options.ranges) { | ||||
|  | ||||
|                     var start = moment(options.ranges[range][0]); | ||||
|                     var end = moment(options.ranges[range][1]); | ||||
|  | ||||
|                     // If we have a min/max date set, bound this range | ||||
|                     // to it, but only if it would otherwise fall | ||||
|                     // outside of the min/max. | ||||
|                     if (this.minDate && start.isBefore(this.minDate)) | ||||
|                         start = moment(this.minDate); | ||||
|  | ||||
|                     if (this.maxDate && end.isAfter(this.maxDate)) | ||||
|                         end = moment(this.maxDate); | ||||
|  | ||||
|                     // If the end of the range is before the minimum (if min is set) OR | ||||
|                     // the start of the range is after the max (also if set) don't display this | ||||
|                     // range option. | ||||
|                     if ((this.minDate && end.isBefore(this.minDate)) || (this.maxDate && start.isAfter(this.maxDate))) { | ||||
|                         continue; | ||||
|                     } | ||||
|  | ||||
|                     this.ranges[range] = [start, end]; | ||||
|                 } | ||||
|  | ||||
|                 var list = '<ul>'; | ||||
|                 for (var range in this.ranges) { | ||||
|                     list += '<li>' + range + '</li>'; | ||||
|                 } | ||||
|                 list += '<li>' + this.locale.customRangeLabel + '</li>'; | ||||
|                 list += '</ul>'; | ||||
|                 this.container.find('.ranges').prepend(list); | ||||
|             } | ||||
|  | ||||
|             if (typeof options.dateLimit == 'object') | ||||
|                 this.dateLimit = options.dateLimit; | ||||
|  | ||||
|             // update day names order to firstDay | ||||
|             if (typeof options.locale == 'object') { | ||||
|  | ||||
|                 if (typeof options.locale.daysOfWeek == 'object') { | ||||
|  | ||||
|                     // Create a copy of daysOfWeek to avoid modification of original | ||||
|                     // options object for reusability in multiple daterangepicker instances | ||||
|                     this.locale.daysOfWeek = options.locale.daysOfWeek.slice(); | ||||
|                 } | ||||
|  | ||||
|                 if (typeof options.locale.firstDay == 'number') { | ||||
|                     this.locale.firstDay = options.locale.firstDay; | ||||
|                     var iterator = options.locale.firstDay; | ||||
|                     while (iterator > 0) { | ||||
|                         this.locale.daysOfWeek.push(this.locale.daysOfWeek.shift()); | ||||
|                         iterator--; | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             if (typeof options.opens == 'string') | ||||
|                 this.opens = options.opens; | ||||
|  | ||||
|             if (typeof options.showWeekNumbers == 'boolean') { | ||||
|                 this.showWeekNumbers = options.showWeekNumbers; | ||||
|             } | ||||
|  | ||||
|             if (typeof options.buttonClasses == 'string') { | ||||
|                 this.buttonClasses = [options.buttonClasses]; | ||||
|             } | ||||
|  | ||||
|             if (typeof options.buttonClasses == 'object') { | ||||
|                 this.buttonClasses = options.buttonClasses; | ||||
|             } | ||||
|  | ||||
|             if (typeof options.showDropdowns == 'boolean') { | ||||
|                 this.showDropdowns = options.showDropdowns; | ||||
|             } | ||||
|  | ||||
|             if (typeof options.timePicker == 'boolean') { | ||||
|                 this.timePicker = options.timePicker; | ||||
|             } | ||||
|  | ||||
|             if (typeof options.timePickerIncrement == 'number') { | ||||
|                 this.timePickerIncrement = options.timePickerIncrement; | ||||
|             } | ||||
|  | ||||
|             if (typeof options.timePicker12Hour == 'boolean') { | ||||
|                 this.timePicker12Hour = options.timePicker12Hour; | ||||
|             } | ||||
|  | ||||
|         } | ||||
|  | ||||
|         if (!this.timePicker) { | ||||
|             this.startDate = this.startDate.startOf('day'); | ||||
|             this.endDate = this.endDate.startOf('day'); | ||||
|         } | ||||
|  | ||||
|         //apply CSS classes to buttons | ||||
|         var c = this.container; | ||||
|         $.each(this.buttonClasses, function (idx, val) { | ||||
|             c.find('button').addClass(val); | ||||
|         }); | ||||
|  | ||||
|         if (this.opens == 'right') { | ||||
|             //swap calendar positions | ||||
|             var left = this.container.find('.calendar.left'); | ||||
|             var right = this.container.find('.calendar.right'); | ||||
|             left.removeClass('left').addClass('right'); | ||||
|             right.removeClass('right').addClass('left'); | ||||
|         } | ||||
|  | ||||
|         if (typeof options == 'undefined' || typeof options.ranges == 'undefined') { | ||||
|             this.container.find('.calendar').show(); | ||||
|             this.move(); | ||||
|         } | ||||
|  | ||||
|         if (typeof cb == 'function') | ||||
|             this.cb = cb; | ||||
|  | ||||
|         this.container.addClass('opens' + this.opens); | ||||
|  | ||||
|         //try parse date if in text input | ||||
|         if (!hasOptions || (typeof options.startDate == 'undefined' && typeof options.endDate == 'undefined')) { | ||||
|             if ($(this.element).is('input[type=text]')) { | ||||
|                 var val = $(this.element).val(); | ||||
|                 var split = val.split(this.separator); | ||||
|                 var start, end; | ||||
|                 if (split.length == 2) { | ||||
|                     start = moment(split[0], this.format); | ||||
|                     end = moment(split[1], this.format); | ||||
|                 } | ||||
|                 if (start != null && end != null) { | ||||
|                     this.startDate = start; | ||||
|                     this.endDate = end; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         //state | ||||
|         this.oldStartDate = this.startDate.clone(); | ||||
|         this.oldEndDate = this.endDate.clone(); | ||||
|  | ||||
|         this.leftCalendar = { | ||||
|             month: moment([this.startDate.year(), this.startDate.month(), 1, this.startDate.hour(), this.startDate.minute()]), | ||||
|             calendar: [] | ||||
|         }; | ||||
|  | ||||
|         this.rightCalendar = { | ||||
|             month: moment([this.endDate.year(), this.endDate.month(), 1, this.endDate.hour(), this.endDate.minute()]), | ||||
|             calendar: [] | ||||
|         }; | ||||
|  | ||||
|         //event listeners | ||||
|         this.container.on('mousedown', $.proxy(this.mousedown, this)); | ||||
|  | ||||
|         this.container.find('.calendar') | ||||
|             .on('click', '.prev', $.proxy(this.clickPrev, this)) | ||||
|             .on('click', '.next', $.proxy(this.clickNext, this)) | ||||
|             .on('click', 'td.available', $.proxy(this.clickDate, this)) | ||||
|             .on('mouseenter', 'td.available', $.proxy(this.enterDate, this)) | ||||
|             .on('mouseleave', 'td.available', $.proxy(this.updateFormInputs, this)) | ||||
|             .on('change', 'select.yearselect', $.proxy(this.updateMonthYear, this)) | ||||
|             .on('change', 'select.monthselect', $.proxy(this.updateMonthYear, this)) | ||||
|             .on('change', 'select.hourselect,select.minuteselect,select.ampmselect', $.proxy(this.updateTime, this)); | ||||
|  | ||||
|         this.container.find('.ranges') | ||||
|             .on('click', 'button.applyBtn', $.proxy(this.clickApply, this)) | ||||
|             .on('click', 'button.cancelBtn', $.proxy(this.clickCancel, this)) | ||||
|             .on('click', '.daterangepicker_start_input,.daterangepicker_end_input', $.proxy(this.showCalendars, this)) | ||||
|             .on('click', 'li', $.proxy(this.clickRange, this)) | ||||
|             .on('mouseenter', 'li', $.proxy(this.enterRange, this)) | ||||
|             .on('mouseleave', 'li', $.proxy(this.updateFormInputs, this)); | ||||
|  | ||||
|         this.element.on('keyup', $.proxy(this.updateFromControl, this)); | ||||
|  | ||||
|         this.updateView(); | ||||
|         this.updateCalendars(); | ||||
|  | ||||
|     }; | ||||
|  | ||||
|     DateRangePicker.prototype = { | ||||
|  | ||||
|         constructor: DateRangePicker, | ||||
|  | ||||
|         mousedown: function (e) { | ||||
|             e.stopPropagation(); | ||||
|         }, | ||||
|  | ||||
|         updateView: function () { | ||||
|             this.leftCalendar.month.month(this.startDate.month()).year(this.startDate.year()); | ||||
|             this.rightCalendar.month.month(this.endDate.month()).year(this.endDate.year()); | ||||
|             this.updateFormInputs(); | ||||
|         }, | ||||
|  | ||||
|         updateFormInputs: function () { | ||||
|             this.container.find('input[name=daterangepicker_start]').val(this.startDate.format(this.format)); | ||||
|             this.container.find('input[name=daterangepicker_end]').val(this.endDate.format(this.format)); | ||||
|  | ||||
|             if (this.startDate.isSame(this.endDate) || this.startDate.isBefore(this.endDate)) { | ||||
|                 this.container.find('button.applyBtn').removeAttr('disabled'); | ||||
|             } else { | ||||
|                 this.container.find('button.applyBtn').attr('disabled', 'disabled'); | ||||
|             } | ||||
|         }, | ||||
|  | ||||
|         updateFromControl: function () { | ||||
|             if (!this.element.is('input')) return; | ||||
|             if (!this.element.val().length) return; | ||||
|  | ||||
|             var dateString = this.element.val().split(this.separator); | ||||
|             var start = moment(dateString[0], this.format); | ||||
|             var end = moment(dateString[1], this.format); | ||||
|  | ||||
|             if (start == null || end == null) return; | ||||
|             if (end.isBefore(start)) return; | ||||
|  | ||||
|             this.oldStartDate = this.startDate.clone(); | ||||
|             this.oldEndDate = this.endDate.clone(); | ||||
|  | ||||
|             this.startDate = start; | ||||
|             this.endDate = end; | ||||
|  | ||||
|             if (!this.startDate.isSame(this.oldStartDate) || !this.endDate.isSame(this.oldEndDate)) | ||||
|                 this.notify(); | ||||
|  | ||||
|             this.updateCalendars(); | ||||
|         }, | ||||
|  | ||||
|         notify: function () { | ||||
|             this.updateView(); | ||||
|             this.cb(this.startDate, this.endDate); | ||||
|         }, | ||||
|  | ||||
|         move: function () { | ||||
|             var parentOffset = { | ||||
|                 top: this.parentEl.offset().top - (this.parentEl.is('body') ? 0 : this.parentEl.scrollTop()), | ||||
|                 left: this.parentEl.offset().left - (this.parentEl.is('body') ? 0 : this.parentEl.scrollLeft()) | ||||
|             }; | ||||
|             if (this.opens == 'left') { | ||||
|                 this.container.css({ | ||||
|                     top: this.element.offset().top + this.element.outerHeight() - parentOffset.top, | ||||
|                     right: $(window).width() - this.element.offset().left - this.element.outerWidth() - parentOffset.left, | ||||
|                     left: 'auto' | ||||
|                 }); | ||||
|                 if (this.container.offset().left < 0) { | ||||
|                     this.container.css({ | ||||
|                         right: 'auto', | ||||
|                         left: 9 | ||||
|                     }); | ||||
|                 } | ||||
|             } else { | ||||
|                 this.container.css({ | ||||
|                     top: this.element.offset().top + this.element.outerHeight() - parentOffset.top, | ||||
|                     left: this.element.offset().left - parentOffset.left, | ||||
|                     right: 'auto' | ||||
|                 }); | ||||
|                 if (this.container.offset().left + this.container.outerWidth() > $(window).width()) { | ||||
|                     this.container.css({ | ||||
|                         left: 'auto', | ||||
|                         right: 0 | ||||
|                     }); | ||||
|                 } | ||||
|             } | ||||
|         }, | ||||
|  | ||||
|         show: function (e) { | ||||
|             this.container.show(); | ||||
|             this.move(); | ||||
|  | ||||
|             if (e) { | ||||
|                 e.stopPropagation(); | ||||
|                 e.preventDefault(); | ||||
|             } | ||||
|  | ||||
|             $(document).on('mousedown', $.proxy(this.hide, this)); | ||||
|             this.element.trigger('shown', {target: e.target, picker: this}); | ||||
|         }, | ||||
|  | ||||
|         hide: function (e) { | ||||
|             this.container.hide(); | ||||
|  | ||||
|             if (!this.startDate.isSame(this.oldStartDate) || !this.endDate.isSame(this.oldEndDate)) | ||||
|                 this.notify(); | ||||
|  | ||||
|             this.oldStartDate = this.startDate.clone(); | ||||
|             this.oldEndDate = this.endDate.clone(); | ||||
|  | ||||
|             $(document).off('mousedown', this.hide); | ||||
|             this.element.trigger('hidden', { picker: this }); | ||||
|         }, | ||||
|  | ||||
|         enterRange: function (e) { | ||||
|             var label = e.target.innerHTML; | ||||
|             if (label == this.locale.customRangeLabel) { | ||||
|                 this.updateView(); | ||||
|             } else { | ||||
|                 var dates = this.ranges[label]; | ||||
|                 this.container.find('input[name=daterangepicker_start]').val(dates[0].format(this.format)); | ||||
|                 this.container.find('input[name=daterangepicker_end]').val(dates[1].format(this.format)); | ||||
|             } | ||||
|         }, | ||||
|  | ||||
|         showCalendars: function() { | ||||
|             this.container.find('.calendar').show(); | ||||
|             this.move(); | ||||
|         }, | ||||
|  | ||||
|         updateInputText: function() { | ||||
|             if (this.element.is('input')) | ||||
|                 this.element.val(this.startDate.format(this.format) + this.separator + this.endDate.format(this.format)); | ||||
|         }, | ||||
|  | ||||
|         clickRange: function (e) { | ||||
|             var label = e.target.innerHTML; | ||||
|             if (label == this.locale.customRangeLabel) { | ||||
|                 this.showCalendars(); | ||||
|             } else { | ||||
|                 var dates = this.ranges[label]; | ||||
|  | ||||
|                 this.startDate = dates[0]; | ||||
|                 this.endDate = dates[1]; | ||||
|  | ||||
|                 if (!this.timePicker) { | ||||
|                     this.startDate.startOf('day'); | ||||
|                     this.endDate.startOf('day'); | ||||
|                 } | ||||
|  | ||||
|                 this.leftCalendar.month.month(this.startDate.month()).year(this.startDate.year()).hour(this.startDate.hour()).minute(this.startDate.minute()); | ||||
|                 this.rightCalendar.month.month(this.endDate.month()).year(this.endDate.year()).hour(this.endDate.hour()).minute(this.endDate.minute()); | ||||
|                 this.updateCalendars(); | ||||
|  | ||||
|                 this.updateInputText(); | ||||
|  | ||||
|                 this.container.find('.calendar').hide(); | ||||
|                 this.hide(); | ||||
|             } | ||||
|         }, | ||||
|  | ||||
|         clickPrev: function (e) { | ||||
|             var cal = $(e.target).parents('.calendar'); | ||||
|             if (cal.hasClass('left')) { | ||||
|                 this.leftCalendar.month.subtract('month', 1); | ||||
|             } else { | ||||
|                 this.rightCalendar.month.subtract('month', 1); | ||||
|             } | ||||
|             this.updateCalendars(); | ||||
|         }, | ||||
|  | ||||
|         clickNext: function (e) { | ||||
|             var cal = $(e.target).parents('.calendar'); | ||||
|             if (cal.hasClass('left')) { | ||||
|                 this.leftCalendar.month.add('month', 1); | ||||
|             } else { | ||||
|                 this.rightCalendar.month.add('month', 1); | ||||
|             } | ||||
|             this.updateCalendars(); | ||||
|         }, | ||||
|  | ||||
|         enterDate: function (e) { | ||||
|  | ||||
|             var title = $(e.target).attr('data-title'); | ||||
|             var row = title.substr(1, 1); | ||||
|             var col = title.substr(3, 1); | ||||
|             var cal = $(e.target).parents('.calendar'); | ||||
|  | ||||
|             if (cal.hasClass('left')) { | ||||
|                 this.container.find('input[name=daterangepicker_start]').val(this.leftCalendar.calendar[row][col].format(this.format)); | ||||
|             } else { | ||||
|                 this.container.find('input[name=daterangepicker_end]').val(this.rightCalendar.calendar[row][col].format(this.format)); | ||||
|             } | ||||
|  | ||||
|         }, | ||||
|  | ||||
|         clickDate: function (e) { | ||||
|             var title = $(e.target).attr('data-title'); | ||||
|             var row = title.substr(1, 1); | ||||
|             var col = title.substr(3, 1); | ||||
|             var cal = $(e.target).parents('.calendar'); | ||||
|  | ||||
|             if (cal.hasClass('left')) { | ||||
|                 var startDate = this.leftCalendar.calendar[row][col]; | ||||
|                 var endDate = this.endDate; | ||||
|                 if (typeof this.dateLimit == 'object') { | ||||
|                     var maxDate = moment(startDate).add(this.dateLimit).startOf('day'); | ||||
|                     if (endDate.isAfter(maxDate)) { | ||||
|                         endDate = maxDate; | ||||
|                     } | ||||
|                 } | ||||
|             } else { | ||||
|                 var startDate = this.startDate; | ||||
|                 var endDate = this.rightCalendar.calendar[row][col]; | ||||
|                 if (typeof this.dateLimit == 'object') { | ||||
|                     var minDate = moment(endDate).subtract(this.dateLimit).startOf('day'); | ||||
|                     if (startDate.isBefore(minDate)) { | ||||
|                         startDate = minDate; | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             cal.find('td').removeClass('active'); | ||||
|  | ||||
|             if (startDate.isSame(endDate) || startDate.isBefore(endDate)) { | ||||
|                 $(e.target).addClass('active'); | ||||
|                 this.startDate = startDate; | ||||
|                 this.endDate = endDate; | ||||
|             } else if (startDate.isAfter(endDate)) { | ||||
|                 $(e.target).addClass('active'); | ||||
|                 this.startDate = startDate; | ||||
|                 this.endDate = moment(startDate).add('day', 1).startOf('day'); | ||||
|             } | ||||
|  | ||||
|             this.leftCalendar.month.month(this.startDate.month()).year(this.startDate.year()); | ||||
|             this.rightCalendar.month.month(this.endDate.month()).year(this.endDate.year()); | ||||
|             this.updateCalendars(); | ||||
|         }, | ||||
|  | ||||
|         clickApply: function (e) { | ||||
|             this.updateInputText(); | ||||
|             this.hide(); | ||||
|         }, | ||||
|  | ||||
|         clickCancel: function (e) { | ||||
|             this.startDate = this.oldStartDate; | ||||
|             this.endDate = this.oldEndDate; | ||||
|             this.updateView(); | ||||
|             this.updateCalendars(); | ||||
|             this.hide(); | ||||
|         }, | ||||
|  | ||||
|         updateMonthYear: function (e) { | ||||
|  | ||||
|             var isLeft = $(e.target).closest('.calendar').hasClass('left'); | ||||
|             var cal = this.container.find('.calendar.left'); | ||||
|             if (!isLeft) | ||||
|                 cal = this.container.find('.calendar.right'); | ||||
|  | ||||
|             // Month must be Number for new moment versions | ||||
|             var month = parseInt(cal.find('.monthselect').val(), 10); | ||||
|             var year = cal.find('.yearselect').val(); | ||||
|  | ||||
|             if (isLeft) { | ||||
|                 this.leftCalendar.month.month(month).year(year); | ||||
|             } else { | ||||
|                 this.rightCalendar.month.month(month).year(year); | ||||
|             } | ||||
|  | ||||
|             this.updateCalendars(); | ||||
|  | ||||
|         }, | ||||
|  | ||||
|         updateTime: function(e) { | ||||
|  | ||||
|             var isLeft = $(e.target).closest('.calendar').hasClass('left'); | ||||
|             var cal = this.container.find('.calendar.left'); | ||||
|             if (!isLeft) | ||||
|                 cal = this.container.find('.calendar.right'); | ||||
|  | ||||
|             var hour = parseInt(cal.find('.hourselect').val()); | ||||
|             var minute = parseInt(cal.find('.minuteselect').val()); | ||||
|  | ||||
|             if (this.timePicker12Hour) { | ||||
|                 var ampm = cal.find('.ampmselect').val(); | ||||
|                 if (ampm == 'PM' && hour < 12) | ||||
|                     hour += 12; | ||||
|                 if (ampm == 'AM' && hour == 12) | ||||
|                     hour = 0; | ||||
|             } | ||||
|  | ||||
|             if (isLeft) { | ||||
|                 var start = this.startDate.clone(); | ||||
|                 start.hour(hour); | ||||
|                 start.minute(minute); | ||||
|                 this.startDate = start; | ||||
|                 this.leftCalendar.month.hour(hour).minute(minute); | ||||
|             } else { | ||||
|                 var end = this.endDate.clone(); | ||||
|                 end.hour(hour); | ||||
|                 end.minute(minute); | ||||
|                 this.endDate = end; | ||||
|                 this.rightCalendar.month.hour(hour).minute(minute); | ||||
|             } | ||||
|  | ||||
|             this.updateCalendars(); | ||||
|  | ||||
|         }, | ||||
|  | ||||
|         updateCalendars: function () { | ||||
|             this.leftCalendar.calendar = this.buildCalendar(this.leftCalendar.month.month(), this.leftCalendar.month.year(), this.leftCalendar.month.hour(), this.leftCalendar.month.minute(), 'left'); | ||||
|             this.rightCalendar.calendar = this.buildCalendar(this.rightCalendar.month.month(), this.rightCalendar.month.year(), this.rightCalendar.month.hour(), this.rightCalendar.month.minute(), 'right'); | ||||
|             this.container.find('.calendar.left').html(this.renderCalendar(this.leftCalendar.calendar, this.startDate, this.minDate, this.maxDate)); | ||||
|             this.container.find('.calendar.right').html(this.renderCalendar(this.rightCalendar.calendar, this.endDate, this.startDate, this.maxDate)); | ||||
|  | ||||
|             this.container.find('.ranges li').removeClass('active'); | ||||
|             var customRange = true; | ||||
|             var i = 0; | ||||
|             for (var range in this.ranges) { | ||||
|                 if (this.timePicker) { | ||||
|                     if (this.startDate.isSame(this.ranges[range][0]) && this.endDate.isSame(this.ranges[range][1])) { | ||||
|                         customRange = false; | ||||
|                         this.container.find('.ranges li:eq(' + i + ')').addClass('active'); | ||||
|                     } | ||||
|                 } else { | ||||
|                     //ignore times when comparing dates if time picker is not enabled | ||||
|                     if (this.startDate.format('YYYY-MM-DD') == this.ranges[range][0].format('YYYY-MM-DD') && this.endDate.format('YYYY-MM-DD') == this.ranges[range][1].format('YYYY-MM-DD')) { | ||||
|                         customRange = false; | ||||
|                         this.container.find('.ranges li:eq(' + i + ')').addClass('active'); | ||||
|                     } | ||||
|                 } | ||||
|                 i++; | ||||
|             } | ||||
|             if (customRange) | ||||
|                 this.container.find('.ranges li:last').addClass('active'); | ||||
|         }, | ||||
|  | ||||
|         buildCalendar: function (month, year, hour, minute, side) { | ||||
|  | ||||
|             var firstDay = moment([year, month, 1]); | ||||
|             var lastMonth = moment(firstDay).subtract('month', 1).month(); | ||||
|             var lastYear = moment(firstDay).subtract('month', 1).year(); | ||||
|  | ||||
|             var daysInLastMonth = moment([lastYear, lastMonth]).daysInMonth(); | ||||
|  | ||||
|             var dayOfWeek = firstDay.day(); | ||||
|  | ||||
|             //initialize a 6 rows x 7 columns array for the calendar | ||||
|             var calendar = []; | ||||
|             for (var i = 0; i < 6; i++) { | ||||
|                 calendar[i] = []; | ||||
|             } | ||||
|  | ||||
|             //populate the calendar with date objects | ||||
|             var startDay = daysInLastMonth - dayOfWeek + this.locale.firstDay + 1; | ||||
|             if (startDay > daysInLastMonth) | ||||
|                 startDay -= 7; | ||||
|  | ||||
|             if (dayOfWeek == this.locale.firstDay) | ||||
|                 startDay = daysInLastMonth - 6; | ||||
|  | ||||
|             var curDate = moment([lastYear, lastMonth, startDay, 12, minute]); | ||||
|             for (var i = 0, col = 0, row = 0; i < 42; i++, col++, curDate = moment(curDate).add('hour', 24)) { | ||||
|                 if (i > 0 && col % 7 == 0) { | ||||
|                     col = 0; | ||||
|                     row++; | ||||
|                 } | ||||
|                 calendar[row][col] = curDate.clone().hour(hour); | ||||
|                 curDate.hour(12); | ||||
|             } | ||||
|  | ||||
|             return calendar; | ||||
|  | ||||
|         }, | ||||
|  | ||||
|         renderDropdowns: function (selected, minDate, maxDate) { | ||||
|             var currentMonth = selected.month(); | ||||
|             var monthHtml = '<select class="monthselect">'; | ||||
|             var inMinYear = false; | ||||
|             var inMaxYear = false; | ||||
|  | ||||
|             for (var m = 0; m < 12; m++) { | ||||
|                 if ((!inMinYear || m >= minDate.month()) && (!inMaxYear || m <= maxDate.month())) { | ||||
|                     monthHtml += "<option value='" + m + "'" + | ||||
|                         (m === currentMonth ? " selected='selected'" : "") + | ||||
|                         ">" + this.locale.monthNames[m] + "</option>"; | ||||
|                 } | ||||
|             } | ||||
|             monthHtml += "</select>"; | ||||
|  | ||||
|             var currentYear = selected.year(); | ||||
|             var maxYear = (maxDate && maxDate.year()) || (currentYear + 5); | ||||
|             var minYear = (minDate && minDate.year()) || (currentYear - 50); | ||||
|             var yearHtml = '<select class="yearselect">'; | ||||
|  | ||||
|             for (var y = minYear; y <= maxYear; y++) { | ||||
|                 yearHtml += '<option value="' + y + '"' + | ||||
|                     (y === currentYear ? ' selected="selected"' : '') + | ||||
|                     '>' + y + '</option>'; | ||||
|             } | ||||
|  | ||||
|             yearHtml += '</select>'; | ||||
|  | ||||
|             return monthHtml + yearHtml; | ||||
|         }, | ||||
|  | ||||
|         renderCalendar: function (calendar, selected, minDate, maxDate) { | ||||
|  | ||||
|             var html = '<div class="calendar-date">'; | ||||
|             html += '<table class="table-condensed">'; | ||||
|             html += '<thead>'; | ||||
|             html += '<tr>'; | ||||
|  | ||||
|             // add empty cell for week number | ||||
|             if (this.showWeekNumbers) | ||||
|                 html += '<th></th>'; | ||||
|  | ||||
|             if (!minDate || minDate.isBefore(calendar[1][1])) { | ||||
|                 html += '<th class="prev available"><i class="icon-arrow-left glyphicon glyphicon-arrow-left"></i></th>'; | ||||
|             } else { | ||||
|                 html += '<th></th>'; | ||||
|             } | ||||
|  | ||||
|             var dateHtml = this.locale.monthNames[calendar[1][1].month()] + calendar[1][1].format(" YYYY"); | ||||
|  | ||||
|             if (this.showDropdowns) { | ||||
|                 dateHtml = this.renderDropdowns(calendar[1][1], minDate, maxDate); | ||||
|             } | ||||
|  | ||||
|             html += '<th colspan="5" style="width: auto">' + dateHtml + '</th>'; | ||||
|             if (!maxDate || maxDate.isAfter(calendar[1][1])) { | ||||
|                 html += '<th class="next available"><i class="icon-arrow-right glyphicon glyphicon-arrow-right"></i></th>'; | ||||
|             } else { | ||||
|                 html += '<th></th>'; | ||||
|             } | ||||
|  | ||||
|             html += '</tr>'; | ||||
|             html += '<tr>'; | ||||
|  | ||||
|             // add week number label | ||||
|             if (this.showWeekNumbers) | ||||
|                 html += '<th class="week">' + this.locale.weekLabel + '</th>'; | ||||
|  | ||||
|             $.each(this.locale.daysOfWeek, function (index, dayOfWeek) { | ||||
|                 html += '<th>' + dayOfWeek + '</th>'; | ||||
|             }); | ||||
|  | ||||
|             html += '</tr>'; | ||||
|             html += '</thead>'; | ||||
|             html += '<tbody>'; | ||||
|  | ||||
|             for (var row = 0; row < 6; row++) { | ||||
|                 html += '<tr>'; | ||||
|  | ||||
|                 // add week number | ||||
|                 if (this.showWeekNumbers) | ||||
|                     html += '<td class="week">' + calendar[row][0].week() + '</td>'; | ||||
|  | ||||
|                 for (var col = 0; col < 7; col++) { | ||||
|                     var cname = 'available '; | ||||
|                     cname += (calendar[row][col].month() == calendar[1][1].month()) ? '' : 'off'; | ||||
|  | ||||
|                     if ((minDate && calendar[row][col].isBefore(minDate)) || (maxDate && calendar[row][col].isAfter(maxDate))) { | ||||
|                         cname = ' off disabled '; | ||||
|                     } else if (calendar[row][col].format('YYYY-MM-DD') == selected.format('YYYY-MM-DD')) { | ||||
|                         cname += ' active '; | ||||
|                         if (calendar[row][col].format('YYYY-MM-DD') == this.startDate.format('YYYY-MM-DD')) { | ||||
|                             cname += ' start-date '; | ||||
|                         } | ||||
|                         if (calendar[row][col].format('YYYY-MM-DD') == this.endDate.format('YYYY-MM-DD')) { | ||||
|                             cname += ' end-date '; | ||||
|                         } | ||||
|                     } else if (calendar[row][col] >= this.startDate && calendar[row][col] <= this.endDate) { | ||||
|                         cname += ' in-range '; | ||||
|                         if (calendar[row][col].isSame(this.startDate)) { cname += ' start-date '; } | ||||
|                         if (calendar[row][col].isSame(this.endDate)) { cname += ' end-date '; } | ||||
|                     } | ||||
|  | ||||
|                     var title = 'r' + row + 'c' + col; | ||||
|                     html += '<td class="' + cname.replace(/\s+/g, ' ').replace(/^\s?(.*?)\s?$/, '$1') + '" data-title="' + title + '">' + calendar[row][col].date() + '</td>'; | ||||
|                 } | ||||
|                 html += '</tr>'; | ||||
|             } | ||||
|  | ||||
|             html += '</tbody>'; | ||||
|             html += '</table>'; | ||||
|             html += '</div>'; | ||||
|  | ||||
|             if (this.timePicker) { | ||||
|  | ||||
|                 html += '<div class="calendar-time">'; | ||||
|                 html += '<select class="hourselect">'; | ||||
|                 var start = 0; | ||||
|                 var end = 23; | ||||
|                 var selected_hour = selected.hour(); | ||||
|                 if (this.timePicker12Hour) { | ||||
|                     start = 1; | ||||
|                     end = 12; | ||||
|                     if (selected_hour >= 12) | ||||
|                         selected_hour -= 12; | ||||
|                     if (selected_hour == 0) | ||||
|                         selected_hour = 12; | ||||
|                 } | ||||
|  | ||||
|                 for (var i = start; i <= end; i++) { | ||||
|                     if (i == selected_hour) { | ||||
|                         html += '<option value="' + i + '" selected="selected">' + i + '</option>'; | ||||
|                     } else { | ||||
|                         html += '<option value="' + i + '">' + i + '</option>'; | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 html += '</select> : '; | ||||
|  | ||||
|                 html += '<select class="minuteselect">'; | ||||
|  | ||||
|                 for (var i = 0; i < 60; i += this.timePickerIncrement) { | ||||
|                     var num = i; | ||||
|                     if (num < 10) | ||||
|                         num = '0' + num; | ||||
|                     if (i == selected.minute()) { | ||||
|                         html += '<option value="' + i + '" selected="selected">' + num + '</option>'; | ||||
|                     } else { | ||||
|                         html += '<option value="' + i + '">' + num + '</option>'; | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 html += '</select> '; | ||||
|  | ||||
|                 if (this.timePicker12Hour) { | ||||
|                     html += '<select class="ampmselect">'; | ||||
|                     if (selected.hour() >= 12) { | ||||
|                         html += '<option value="AM">AM</option><option value="PM" selected="selected">PM</option>'; | ||||
|                     } else { | ||||
|                         html += '<option value="AM" selected="selected">AM</option><option value="PM">PM</option>'; | ||||
|                     } | ||||
|                     html += '</select>'; | ||||
|                 } | ||||
|  | ||||
|                 html += '</div>'; | ||||
|  | ||||
|             } | ||||
|  | ||||
|             return html; | ||||
|  | ||||
|         } | ||||
|  | ||||
|     }; | ||||
|  | ||||
|     $.fn.daterangepicker = function (options, cb) { | ||||
|         this.each(function () { | ||||
|             var el = $(this); | ||||
|             if (!el.data('daterangepicker')) | ||||
|                 el.data('daterangepicker', new DateRangePicker(el, options, cb)); | ||||
|         }); | ||||
|         return this; | ||||
|     }; | ||||
|  | ||||
| }(window.jQuery); | ||||
							
								
								
									
										6
									
								
								Netdisco/share/views/js/moment.min.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								Netdisco/share/views/js/moment.min.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| @@ -2,14 +2,59 @@ | ||||
|   // ajax content is loaded | ||||
|   var path = 'report'; | ||||
|  | ||||
|   // fields in the IP Inventory Report form | ||||
|   var form_inputs = $(".nd_colored-input"); | ||||
|  | ||||
|   // this is called by do_search to support local code | ||||
|   // here, when tab changes need to strike/unstrike the navbar search | ||||
|   function inner_view_processing(tab) { } | ||||
|   function inner_view_processing(tab) { | ||||
|  | ||||
|     // activate modals, tooltips and popovers | ||||
|     $('.nd_modal').modal({show: false}); | ||||
|     $("[rel=tooltip]").tooltip({live: true}); | ||||
|     $("[rel=popover]").popover({live: true}); | ||||
|   } | ||||
|  | ||||
|   // on load, check initial Device Search Options form state, | ||||
|   // and on each change to the form fields | ||||
|   $(document).ready(function() { | ||||
|     var tab = '[% report.tag %]' | ||||
|     var target = '#' + tab + '_pane'; | ||||
|   }); | ||||
|  | ||||
|     // sidebar form fields should change colour and have trash icon | ||||
|     form_inputs.each(function() {device_form_state($(this))}); | ||||
|     form_inputs.change(function() {device_form_state($(this))}); | ||||
|  | ||||
|     $('#nd_ipinventory-subnet').on('input', function(event) { | ||||
|       if ($(this).val().indexOf(':') != -1) { | ||||
|         $('#never').attr('disabled', 'disabled'); | ||||
|       } | ||||
|       else { | ||||
|         $('#never').removeAttr('disabled'); | ||||
|       } | ||||
|     }); | ||||
|  | ||||
|     // activate typeahead on prefix/subnet box | ||||
|     $('#nd_ipinventory-subnet').typeahead({ | ||||
|       source: function (query, process) { | ||||
|         return $.get( uri_base + '/ajax/data/subnet/typeahead', { query: query }, function (data) { | ||||
|           return process(data); | ||||
|         }); | ||||
|       } | ||||
|       ,matcher: function () { return true; } // trust backend | ||||
|       ,delay: 250 | ||||
|       ,minLength: 3 | ||||
|     }); | ||||
|  | ||||
|     // change color of daterange input when activated | ||||
|     $('#age_on').change(function() { | ||||
|       if ($(this).is(':checked')) { | ||||
|         $('#daterange').parent('.clearfix').addClass('success'); | ||||
|       } | ||||
|       else { | ||||
|         $('#daterange').parent('.clearfix').removeClass('success'); | ||||
|       } | ||||
|     }); | ||||
|     // fire the event to set success class correctly on page load | ||||
|     $('#age_on').change(); | ||||
|   }); | ||||
|   | ||||
| @@ -45,6 +45,7 @@ | ||||
|   <link rel="stylesheet" href="[% uri_base %]/css/toastr.css"/> | ||||
|   <link rel="stylesheet" href="[% uri_base %]/css/netdisco.css"/> | ||||
|   <link rel="stylesheet" href="[% uri_base %]/css/bootstrap-tree.css"/> | ||||
|   <link rel="stylesheet" href="[% uri_base %]/css/daterangepicker-bs2.css"/> | ||||
|   <link rel="stylesheet" href="[% uri_base %]/css/nd_print.css" media="print"/> | ||||
|  | ||||
|   [% FOREACH add_css IN settings._additional_css %] | ||||
|   | ||||
							
								
								
									
										98
									
								
								Netdisco/share/views/sidebar/report/ipinventory.tt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										98
									
								
								Netdisco/share/views/sidebar/report/ipinventory.tt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,98 @@ | ||||
|  | ||||
|             <div class="clearfix"> | ||||
|               <input id="nd_ipinventory-subnet" class="nd_sidebar-topinput nd_colored-input" | ||||
|                 placeholder="CIDR Prefix/Subnet" required="required" | ||||
|                 name="subnet" value="[% params.subnet | html_entity %]" type="text" autocomplete="off" | ||||
|                 rel="tooltip" data-placement="left" data-offset="5" data-title="Prefix/Subnet in CIDR Format"/> | ||||
|             </div> | ||||
|  | ||||
|             <fieldset> | ||||
|               <legend class="nd_sidebar-legend"> | ||||
|                 <label class="checkbox"> | ||||
|                   <input type="checkbox" id="age_on" name="age_on" | ||||
|                     [% 'checked="checked"' UNLESS (params.exists('age_on') AND params.age_on == '') %]/> | ||||
|                   <em><strong>Age Filter</strong></em> | ||||
|                 </label> | ||||
|               </legend> | ||||
|               <div class="clearfix"> | ||||
|                 <ul class="unstyled"> | ||||
|                   <li> | ||||
|                     <div class="clearfix input-prepend"> | ||||
|                       <label class="add-on"> | ||||
|                       <input type="checkbox" id="age_invert" | ||||
|                         name="age_invert"[% ' checked="checked"' IF params.age_invert %]/> | ||||
|                       </label> | ||||
|                       <label class="nd_checkboxlabel" for="age_invert"> | ||||
|                         <span class="nd_searchcheckbox uneditable-input">Not</span> | ||||
|                       </label> | ||||
|                     </div> | ||||
|                   </li> | ||||
|                 </ul> | ||||
|                 <em class="muted">Seen within the date range:</em><br/> | ||||
|                 <input class="nd_side-input" id="daterange" | ||||
|                   type="text" name="daterange" value="[% params.daterange | html_entity %]"/> | ||||
|             </fieldset> | ||||
|  | ||||
|             <fieldset> | ||||
|               <legend class="nd_sidebar-legend"> | ||||
|                 <label><em><strong>Options</strong></em></label> | ||||
|               </legend> | ||||
|               <div class="clearfix"> | ||||
|                 <ul class="unstyled"> | ||||
|                   <li> | ||||
|                     <em class="muted">Limit:</em><br/> | ||||
|                     <select id="nd_mac-format" class="nd_side-select" name="limit"> | ||||
|                       [% FOREACH size IN [ '32', '64', '128', '256', '1024', '2048', '4096', '8192' ] %] | ||||
|                       <option[% ' selected="selected"' IF params.limit == size %]>[% size %]</option> | ||||
|                       [% END %] | ||||
|                     </select> | ||||
|                   </li> | ||||
|                   <li> | ||||
|                     <em class="muted">Order By:</em><br/> | ||||
|                     <select id="nd_mac-format" class="nd_side-select" name="order"> | ||||
|                       [% FOREACH item IN [ 'IP', 'Age' ] %] | ||||
|                       <option[% ' selected="selected"' IF params.order == item %]>[% item %]</option> | ||||
|                       [% END %] | ||||
|                     </select> | ||||
|                   </li> | ||||
|                 </ul> | ||||
|                 <div class="clearfix input-prepend" | ||||
|                     rel="tooltip" data-placement="left" data-offset="5" data-title="Applies to IPv4 Only"> | ||||
|                   <label class="add-on"> | ||||
|                   <input type="checkbox" id="never" | ||||
|                     name="never"[% ' checked="checked"' IF params.never %]/> | ||||
|                   </label> | ||||
|                   <label class="nd_checkboxlabel" for="never"> | ||||
|                     <span class="nd_searchcheckbox uneditable-input">List IP's Never Seen</span> | ||||
|                   </label> | ||||
|                 </div> | ||||
|               </div> | ||||
|             </fieldset> | ||||
|  | ||||
|             <button id="[% tab.id %]_submit" type="submit" class="btn btn-info"> | ||||
|              <i class="icon-search icon-large pull-left nd_navbar-icon"></i> Search IPs</button> | ||||
|  | ||||
| <script type = "text/javascript"> | ||||
| [%+ INCLUDE 'js/daterangepicker.js' -%] | ||||
| [%+ INCLUDE 'js/moment.min.js' -%] | ||||
| $('#daterange').daterangepicker({ | ||||
|             ranges: { | ||||
|                         'Today': [moment(), moment()], | ||||
|                         'Yesterday': [moment().subtract('days', 1), moment().subtract('days', 1)], | ||||
|                         'Last 7 Days': [moment().subtract('days', 6), moment()], | ||||
|                         'Last 30 Days': [moment().subtract('days', 29), moment()], | ||||
|                         'This Month': [moment().startOf('month'), moment().endOf('month')], | ||||
|                         'Last Month': [moment().subtract('month', 1).startOf('month'), moment().subtract('month', 1).endOf('month')] | ||||
|             }, | ||||
|             startDate: moment().subtract('days', 29), | ||||
|             endDate: moment(), | ||||
|             minDate: '2004-01-01', | ||||
|             showDropdowns: true, | ||||
|             timePicker: false, | ||||
|             opens: 'left', | ||||
|             format: 'YYYY-MM-DD', | ||||
|             separator: ' to ', | ||||
| }, function(start, end) { | ||||
|             $('#daterange span').html(start.format('MMM D, YYYY') + ' - ' + end.format('MMM D, YYYY')); | ||||
| }); | ||||
| </script> | ||||
		Reference in New Issue
	
	Block a user