From ce604ca20bc450ddb5d28d697bbb3d8ff275c629 Mon Sep 17 00:00:00 2001 From: Oliver Gorwits Date: Fri, 20 Sep 2013 20:15:32 +0100 Subject: [PATCH] CSV download support via provides_csv plugin attr Squashed commit of the following: commit e44f203f475761ab86d06d501687fef036d295d5 Author: Oliver Gorwits Date: Fri Sep 20 20:00:46 2013 +0100 also set filename on csv download link commit 26b47d12964b3756aae89bde0a7377206d536fab Author: Oliver Gorwits Date: Fri Sep 20 19:56:38 2013 +0100 conditionally show csv icon for device and search tabs commit 119d2c672d9c7688f55497308c070d35fecda36a Author: Oliver Gorwits Date: Fri Sep 20 19:48:24 2013 +0100 tweak look of csv icon commit 89816892be4193e24db3c870b485c68a16bf432a Author: Oliver Gorwits Date: Fri Sep 20 19:38:31 2013 +0100 enable csv icon link rewrite for all pages commit ac2976940203f3c7eeda71c5086e85930845a0c3 Author: Oliver Gorwits Date: Fri Sep 20 19:28:49 2013 +0100 use single route handler for ajax and csv response commit 4b6f89635d3940822e877d593e64f290ac446642 Author: Oliver Gorwits Date: Fri Sep 20 18:59:08 2013 +0100 no need for separate csv link template commit 1021329e1c1dcfb21e5e5bc58b2545e215c07fc1 Author: Oliver Gorwits Date: Fri Sep 20 18:57:20 2013 +0100 display download as csv icon conditionally commit ce57cdba6997b0b66d447ddb864ecf5374ab4d55 Author: Oliver Gorwits Date: Fri Sep 20 09:23:57 2013 +0100 Based on jeneric's CSV download templates; - try to reduce code duplication by using same route handler for ajax and csv, using request->is_ajax to switch the template, and set content-type - use new HTML5 "download" attribute on links so content-disposition header is no longer necessary - download CSV icon is placed on all tables (per report/device/serach section) - update download CSV link using javascript just before table content is fetched - this is necessary to make sure updated sidebar query params are included The idea here is to allow us to support CSV download in the pages which display tables by only doing the following: - (existing routes:) replace "ajax" with "get" route handler - add logic to switch template in handler, based on request->is_ajax - write _csv.tt version of the template, to spit out CSV file content This makes it much easier for new devs to write reports supporting CSV, I think? commit d3553d2623389e2d1b1bfdcc7a4199082cc8522a Author: Eric A. Miller Date: Thu Sep 19 22:30:27 2013 -0400 add csv download to duplex mismatch, half duplex, and port utilization reports commit 5d4df72a244b1defc8963a420ba619229cf92fc1 Author: Eric A. Miller Date: Wed Sep 18 23:50:27 2013 -0400 add csv download to ap channel distribution report commit 0824d7936a091d64d1bf7ddb386d1f05278c69ba Author: Eric A. Miller Date: Wed Sep 18 23:42:53 2013 -0400 need Template::Plugin::CSV for csv output commit bb1f842d920c5960ea76e503a0696c6cd6691906 Author: Eric A. Miller Date: Wed Sep 18 23:35:28 2013 -0400 add csv download option to device addresses commit 99ada1132cefba88d5dd5cbf4b3255edd9a71820 Author: Eric A. Miller Date: Wed Sep 18 23:32:57 2013 -0400 add csv download option to device, port, and vlan search pages --- Netdisco/Makefile.PL | 1 + .../Netdisco/Web/Plugin/Device/Addresses.pm | 25 +++++++++------- .../Web/Plugin/Report/ApChannelDist.pm | 17 +++++++---- .../Web/Plugin/Report/DuplexMismatch.pm | 28 ++++++++++------- .../Netdisco/Web/Plugin/Report/HalfDuplex.pm | 18 +++++++---- .../Web/Plugin/Report/PortUtilization.pm | 28 ++++++++++------- .../App/Netdisco/Web/Plugin/Search/Device.pm | 22 +++++++++----- .../App/Netdisco/Web/Plugin/Search/Port.pm | 18 ++++++----- .../App/Netdisco/Web/Plugin/Search/VLAN.pm | 28 ++++++++++------- Netdisco/share/public/css/netdisco.css | 9 ++++++ Netdisco/share/views/admintask.tt | 6 ++++ .../share/views/ajax/device/addresses_csv.tt | 11 +++++++ .../views/ajax/report/apchanneldist_csv.tt | 10 +++++++ .../views/ajax/report/duplexmismatch_csv.tt | 13 ++++++++ .../share/views/ajax/report/halfduplex_csv.tt | 12 ++++++++ .../views/ajax/report/portutilization_csv.tt | 12 ++++++++ .../share/views/ajax/search/device_csv.tt | 12 ++++++++ Netdisco/share/views/ajax/search/port_csv.tt | 12 ++++++++ Netdisco/share/views/ajax/search/vlan_csv.tt | 12 ++++++++ Netdisco/share/views/device.tt | 7 ++++- Netdisco/share/views/js/common.js | 30 +++++++++++++++++-- Netdisco/share/views/report.tt | 7 +++++ Netdisco/share/views/search.tt | 5 ++++ 23 files changed, 271 insertions(+), 72 deletions(-) create mode 100644 Netdisco/share/views/ajax/device/addresses_csv.tt create mode 100644 Netdisco/share/views/ajax/report/apchanneldist_csv.tt create mode 100644 Netdisco/share/views/ajax/report/duplexmismatch_csv.tt create mode 100644 Netdisco/share/views/ajax/report/halfduplex_csv.tt create mode 100644 Netdisco/share/views/ajax/report/portutilization_csv.tt create mode 100644 Netdisco/share/views/ajax/search/device_csv.tt create mode 100644 Netdisco/share/views/ajax/search/port_csv.tt create mode 100644 Netdisco/share/views/ajax/search/vlan_csv.tt diff --git a/Netdisco/Makefile.PL b/Netdisco/Makefile.PL index a311a872..3e2d8440 100644 --- a/Netdisco/Makefile.PL +++ b/Netdisco/Makefile.PL @@ -36,6 +36,7 @@ requires 'Starman' => 0.3008; requires 'SNMP::Info' => 3.05; requires 'SQL::Translator' => 0.11016; requires 'Template' => 2.24; +requires 'Template::Plugin::CSV' => 0.04; requires 'URL::Encode' => 0.01; requires 'YAML' => 0.84; requires 'YAML::XS' => 0.41; diff --git a/Netdisco/lib/App/Netdisco/Web/Plugin/Device/Addresses.pm b/Netdisco/lib/App/Netdisco/Web/Plugin/Device/Addresses.pm index 8fc175d2..e9b26dde 100644 --- a/Netdisco/lib/App/Netdisco/Web/Plugin/Device/Addresses.pm +++ b/Netdisco/lib/App/Netdisco/Web/Plugin/Device/Addresses.pm @@ -1,28 +1,33 @@ package App::Netdisco::Web::Plugin::Device::Addresses; use Dancer ':syntax'; -use Dancer::Plugin::Ajax; use Dancer::Plugin::DBIC; use Dancer::Plugin::Auth::Extensible; use App::Netdisco::Web::Plugin; -register_device_tab({ tag => 'addresses', label => 'Addresses' }); +register_device_tab( { tag => 'addresses', label => 'Addresses', provides_csv => 1 } ); # device interface addresses -ajax '/ajax/content/device/addresses' => require_login sub { +get '/ajax/content/device/addresses' => require_login sub { my $q = param('q'); - my $device = schema('netdisco')->resultset('Device') - ->search_for_device($q) or send_error('Bad device', 400); + my $device + = schema('netdisco')->resultset('Device')->search_for_device($q) + or send_error( 'Bad device', 400 ); - my $set = $device->device_ips->search({}, {order_by => 'alias'}); + my $set = $device->device_ips->search( {}, { order_by => 'alias' } ); return unless $set->count; - content_type('text/html'); - template 'ajax/device/addresses.tt', { - results => $set, - }, { layout => undef }; + if (request->is_ajax) { + template 'ajax/device/addresses.tt', { results => $set, }, + { layout => undef }; + } + else { + header( 'Content-Type' => 'text/comma-separated-values' ); + template 'ajax/device/addresses_csv.tt', { results => $set, }, + { layout => undef }; + } }; true; diff --git a/Netdisco/lib/App/Netdisco/Web/Plugin/Report/ApChannelDist.pm b/Netdisco/lib/App/Netdisco/Web/Plugin/Report/ApChannelDist.pm index 98e5d21b..8bdf8c07 100644 --- a/Netdisco/lib/App/Netdisco/Web/Plugin/Report/ApChannelDist.pm +++ b/Netdisco/lib/App/Netdisco/Web/Plugin/Report/ApChannelDist.pm @@ -1,7 +1,6 @@ package App::Netdisco::Web::Plugin::Report::ApChannelDist; use Dancer ':syntax'; -use Dancer::Plugin::Ajax; use Dancer::Plugin::DBIC; use Dancer::Plugin::Auth::Extensible; @@ -11,10 +10,11 @@ register_report( { category => 'Wireless', tag => 'apchanneldist', label => 'Access Point Channel Distribution', + provides_csv => 1, } ); -ajax '/ajax/content/report/apchanneldist' => require_login sub { +get '/ajax/content/report/apchanneldist' => require_login sub { my $set = schema('netdisco')->resultset('DevicePortWireless')->search( { channel => { '!=', '0' } }, { select => [ 'channel', { count => 'channel' } ], @@ -23,12 +23,17 @@ ajax '/ajax/content/report/apchanneldist' => require_login sub { order_by => { -desc => [qw/count/] }, }, ); - return unless $set->count; - content_type('text/html'); - template 'ajax/report/apchanneldist.tt', { results => $set, }, - { layout => undef }; + if (request->is_ajax) { + template 'ajax/report/apchanneldist.tt', { results => $set, }, + { layout => undef }; + } + else { + header( 'Content-Type' => 'text/comma-separated-values' ); + template 'ajax/report/apchanneldist_csv.tt', { results => $set, }, + { layout => undef }; + } }; true; diff --git a/Netdisco/lib/App/Netdisco/Web/Plugin/Report/DuplexMismatch.pm b/Netdisco/lib/App/Netdisco/Web/Plugin/Report/DuplexMismatch.pm index 7cb026f4..35806b48 100644 --- a/Netdisco/lib/App/Netdisco/Web/Plugin/Report/DuplexMismatch.pm +++ b/Netdisco/lib/App/Netdisco/Web/Plugin/Report/DuplexMismatch.pm @@ -1,26 +1,32 @@ package App::Netdisco::Web::Plugin::Report::DuplexMismatch; use Dancer ':syntax'; -use Dancer::Plugin::Ajax; use Dancer::Plugin::DBIC; use Dancer::Plugin::Auth::Extensible; use App::Netdisco::Web::Plugin; -register_report({ - category => 'Port', - tag => 'duplexmismatch', - label => 'Duplex Mismatches Between Devices', -}); +register_report( + { category => 'Port', + tag => 'duplexmismatch', + label => 'Duplex Mismatches Between Devices', + provides_csv => 1, + } +); -ajax '/ajax/content/report/duplexmismatch' => require_login sub { +get '/ajax/content/report/duplexmismatch' => require_login sub { my $set = schema('netdisco')->resultset('Virtual::DuplexMismatch'); return unless $set->count; - content_type('text/html'); - template 'ajax/report/duplexmismatch.tt', { - results => $set, - }, { layout => undef }; + if (request->is_ajax) { + template 'ajax/report/duplexmismatch.tt', { results => $set, }, + { layout => undef }; + } + else { + header( 'Content-Type' => 'text/comma-separated-values' ); + template 'ajax/report/duplexmismatch_csv.tt', { results => $set, }, + { layout => undef }; + } }; true; diff --git a/Netdisco/lib/App/Netdisco/Web/Plugin/Report/HalfDuplex.pm b/Netdisco/lib/App/Netdisco/Web/Plugin/Report/HalfDuplex.pm index 7a5c7a12..bf698d39 100644 --- a/Netdisco/lib/App/Netdisco/Web/Plugin/Report/HalfDuplex.pm +++ b/Netdisco/lib/App/Netdisco/Web/Plugin/Report/HalfDuplex.pm @@ -1,7 +1,6 @@ package App::Netdisco::Web::Plugin::Report::HalfDuplex; use Dancer ':syntax'; -use Dancer::Plugin::Ajax; use Dancer::Plugin::DBIC; use Dancer::Plugin::Auth::Extensible; @@ -11,19 +10,26 @@ register_report({ category => 'Port', tag => 'halfduplex', label => 'Ports in Half Duplex Mode', + provides_csv => 1, }); -ajax '/ajax/content/report/halfduplex' => require_login sub { +get '/ajax/content/report/halfduplex' => require_login sub { + my $format = param('format'); my $set = schema('netdisco')->resultset('DevicePort')->search( { up => 'up', duplex => { '-ilike' => 'half' } }, { order_by => [qw/device.dns port/], prefetch => 'device' }, ); return unless $set->count; - content_type('text/html'); - template 'ajax/report/halfduplex.tt', { - results => $set, - }, { layout => undef }; + if (request->is_ajax) { + template 'ajax/report/halfduplex.tt', { results => $set, }, + { layout => undef }; + } + else { + header( 'Content-Type' => 'text/comma-separated-values' ); + template 'ajax/report/halfduplex_csv.tt', { results => $set, }, + { layout => undef }; + } }; true; diff --git a/Netdisco/lib/App/Netdisco/Web/Plugin/Report/PortUtilization.pm b/Netdisco/lib/App/Netdisco/Web/Plugin/Report/PortUtilization.pm index defa9beb..a9701974 100644 --- a/Netdisco/lib/App/Netdisco/Web/Plugin/Report/PortUtilization.pm +++ b/Netdisco/lib/App/Netdisco/Web/Plugin/Report/PortUtilization.pm @@ -1,26 +1,32 @@ package App::Netdisco::Web::Plugin::Report::PortUtilization; use Dancer ':syntax'; -use Dancer::Plugin::Ajax; use Dancer::Plugin::DBIC; use Dancer::Plugin::Auth::Extensible; use App::Netdisco::Web::Plugin; -register_report({ - category => 'Device', - tag => 'portutilization', - label => 'Port Utilization', -}); +register_report( + { category => 'Device', + tag => 'portutilization', + label => 'Port Utilization', + provides_csv => 1, + } +); -ajax '/ajax/content/report/portutilization' => require_login sub { +get '/ajax/content/report/portutilization' => require_login sub { return unless schema('netdisco')->resultset('Device')->count; my $set = schema('netdisco')->resultset('Virtual::PortUtilization'); - content_type('text/html'); - template 'ajax/report/portutilization.tt', { - results => $set, - }, { layout => undef }; + if (request->is_ajax) { + template 'ajax/report/portutilization.tt', { results => $set, }, + { layout => undef }; + } + else { + header( 'Content-Type' => 'text/comma-separated-values' ); + template 'ajax/report/portutilization_csv.tt', { results => $set, }, + { layout => undef }; + } }; true; diff --git a/Netdisco/lib/App/Netdisco/Web/Plugin/Search/Device.pm b/Netdisco/lib/App/Netdisco/Web/Plugin/Search/Device.pm index 9c9e498c..98dc6561 100644 --- a/Netdisco/lib/App/Netdisco/Web/Plugin/Search/Device.pm +++ b/Netdisco/lib/App/Netdisco/Web/Plugin/Search/Device.pm @@ -1,7 +1,6 @@ package App::Netdisco::Web::Plugin::Search::Device; use Dancer ':syntax'; -use Dancer::Plugin::Ajax; use Dancer::Plugin::DBIC; use Dancer::Plugin::Auth::Extensible; @@ -9,10 +8,12 @@ use List::MoreUtils (); use App::Netdisco::Web::Plugin; -register_search_tab({ tag => 'device', label => 'Device' }); +register_search_tab({ tag => 'device', label => 'Device', provides_csv => 1 }); + +my $headers = ['Device','Contact','Location','System Name','Model','OS Version','Management IP','Serial']; # device with various properties or a default match-all -ajax '/ajax/content/search/device' => require_login sub { +get '/ajax/content/search/device' => require_login sub { my $has_opt = List::MoreUtils::any {param($_)} qw/name location dns ip description model os_ver vendor/; my $set; @@ -28,10 +29,17 @@ ajax '/ajax/content/search/device' => require_login sub { } return unless $set->count; - content_type('text/html'); - template 'ajax/search/device.tt', { - results => $set, - }, { layout => undef }; + if (request->is_ajax) { + template 'ajax/search/device.tt', {results => $set}, + { layout => undef }; + } + else { + header( 'Content-Type' => 'text/comma-separated-values' ); + template 'ajax/search/device_csv.tt', { + results => $set, + headers => $headers, + }, { layout => undef }; + } }; true; diff --git a/Netdisco/lib/App/Netdisco/Web/Plugin/Search/Port.pm b/Netdisco/lib/App/Netdisco/Web/Plugin/Search/Port.pm index 41792154..1dda5c89 100644 --- a/Netdisco/lib/App/Netdisco/Web/Plugin/Search/Port.pm +++ b/Netdisco/lib/App/Netdisco/Web/Plugin/Search/Port.pm @@ -1,16 +1,15 @@ package App::Netdisco::Web::Plugin::Search::Port; use Dancer ':syntax'; -use Dancer::Plugin::Ajax; use Dancer::Plugin::DBIC; use Dancer::Plugin::Auth::Extensible; use App::Netdisco::Web::Plugin; -register_search_tab({ tag => 'port', label => 'Port' }); +register_search_tab({ tag => 'port', label => 'Port', provides_csv => 1 }); # device ports with a description (er, name) matching -ajax '/ajax/content/search/port' => require_login sub { +get '/ajax/content/search/port' => require_login sub { my $q = param('q'); send_error('Missing query', 400) unless $q; my $set; @@ -30,10 +29,15 @@ ajax '/ajax/content/search/port' => require_login sub { } return unless $set->count; - content_type('text/html'); - template 'ajax/search/port.tt', { - results => $set, - }, { layout => undef }; + if (request->is_ajax) { + template 'ajax/search/port.tt', {results => $set}, + { layout => undef }; + } + else { + header( 'Content-Type' => 'text/comma-separated-values' ); + template 'ajax/search/port_csv.tt', {results => $set}, + { layout => undef }; + } }; true; diff --git a/Netdisco/lib/App/Netdisco/Web/Plugin/Search/VLAN.pm b/Netdisco/lib/App/Netdisco/Web/Plugin/Search/VLAN.pm index 4ecec8ce..8081dd8b 100644 --- a/Netdisco/lib/App/Netdisco/Web/Plugin/Search/VLAN.pm +++ b/Netdisco/lib/App/Netdisco/Web/Plugin/Search/VLAN.pm @@ -1,32 +1,38 @@ package App::Netdisco::Web::Plugin::Search::VLAN; use Dancer ':syntax'; -use Dancer::Plugin::Ajax; use Dancer::Plugin::DBIC; use Dancer::Plugin::Auth::Extensible; use App::Netdisco::Web::Plugin; -register_search_tab({ tag => 'vlan', label => 'VLAN' }); +register_search_tab( { tag => 'vlan', label => 'VLAN', provides_csv => 1 } ); # devices carrying vlan xxx -ajax '/ajax/content/search/vlan' => require_login sub { +get '/ajax/content/search/vlan' => require_login sub { my $q = param('q'); - send_error('Missing query', 400) unless $q; + send_error( 'Missing query', 400 ) unless $q; my $set; - if ($q =~ m/^\d+$/) { - $set = schema('netdisco')->resultset('Device')->carrying_vlan({vlan => $q}); + if ( $q =~ m/^\d+$/ ) { + $set = schema('netdisco')->resultset('Device') + ->carrying_vlan( { vlan => $q } ); } else { - $set = schema('netdisco')->resultset('Device')->carrying_vlan_name({name => $q}); + $set = schema('netdisco')->resultset('Device') + ->carrying_vlan_name( { name => $q } ); } return unless $set->count; - content_type('text/html'); - template 'ajax/search/vlan.tt', { - results => $set, - }, { layout => undef }; + if (request->is_ajax) { + template 'ajax/search/vlan.tt', { results => $set }, + { layout => undef }; + } + else { + header( 'Content-Type' => 'text/comma-separated-values' ); + template 'ajax/search/vlan_csv.tt', { results => $set }, + { layout => undef }; + } }; true; diff --git a/Netdisco/share/public/css/netdisco.css b/Netdisco/share/public/css/netdisco.css index 84d8da40..0e4e4707 100644 --- a/Netdisco/share/public/css/netdisco.css +++ b/Netdisco/share/public/css/netdisco.css @@ -200,6 +200,15 @@ td > form.nd_inline-form { color: #6D5720; } +/* reset to normal weight for the download as CSV icon */ +#nd_csv-download { + font-weight: normal; +} + +#nd_csv-download:hover { + text-decoration: none; +} + /* for the job control admin page play/pause links */ #nd_countdown-refresh:hover, #nd_countdown-control:hover { text-decoration: none; diff --git a/Netdisco/share/views/admintask.tt b/Netdisco/share/views/admintask.tt index 2baad94e..07322d53 100644 --- a/Netdisco/share/views/admintask.tt +++ b/Netdisco/share/views/admintask.tt @@ -36,6 +36,12 @@ + [% ELSIF task.provides_csv %] + + + + [% END %]
diff --git a/Netdisco/share/views/ajax/device/addresses_csv.tt b/Netdisco/share/views/ajax/device/addresses_csv.tt new file mode 100644 index 00000000..6c155605 --- /dev/null +++ b/Netdisco/share/views/ajax/device/addresses_csv.tt @@ -0,0 +1,11 @@ +[% USE CSV -%] +[% CSV.dump([ 'Address' 'DNS' 'Interface' 'Description' 'Prefix' ]) %] + +[% WHILE (row = results.next) %] + [% mylist = [] %] + [% FOREACH col IN [ row.alias row.dns row.port row.device_port.name row.subnet ] %] + [% mylist.push(col) %] + [% END %] + [% CSV.dump(mylist) %] + +[% END %] \ No newline at end of file diff --git a/Netdisco/share/views/ajax/report/apchanneldist_csv.tt b/Netdisco/share/views/ajax/report/apchanneldist_csv.tt new file mode 100644 index 00000000..7c242777 --- /dev/null +++ b/Netdisco/share/views/ajax/report/apchanneldist_csv.tt @@ -0,0 +1,10 @@ +[% USE CSV -%] +[% CSV.dump([ 'Channel' 'Count' ]) %] + +[% WHILE (row = results.next) %] + [% mylist = [] %] + [% mylist.push(row.channel) %] + [% mylist.push(row.get_column('ch_count')) %] + [% CSV.dump(mylist) %] + +[% END %] diff --git a/Netdisco/share/views/ajax/report/duplexmismatch_csv.tt b/Netdisco/share/views/ajax/report/duplexmismatch_csv.tt new file mode 100644 index 00000000..aff1075c --- /dev/null +++ b/Netdisco/share/views/ajax/report/duplexmismatch_csv.tt @@ -0,0 +1,13 @@ +[% USE CSV -%] +[% CSV.dump([ 'Left Device' 'Port' 'Duplex' 'Right Device' 'Port' 'Duplex' ]) %] + +[% WHILE (row = results.next) %] + [% mylist = [] %] + [% device_left = row.left_dns || row.left_ip %] + [% device_right = row.right_dns || row.right_ip %] + [% FOREACH col IN [ device_left row.left_port row.left_duplex.ucfirst device_right row.right_port row.right_duplex.ucfirst ] %] + [% mylist.push(col) %] + [% END %] + [% CSV.dump(mylist) %] + +[% END %] \ No newline at end of file diff --git a/Netdisco/share/views/ajax/report/halfduplex_csv.tt b/Netdisco/share/views/ajax/report/halfduplex_csv.tt new file mode 100644 index 00000000..9a4a1c5b --- /dev/null +++ b/Netdisco/share/views/ajax/report/halfduplex_csv.tt @@ -0,0 +1,12 @@ +[% USE CSV -%] +[% CSV.dump([ 'Device' 'Port' 'Description' 'Duplex' ]) %] + +[% WHILE (row = results.next) %] + [% mylist = [] %] + [% device = row.device.dns || row.device.ip %] + [% FOREACH col IN [ device row.port row.name row.duplex.ucfirst ] %] + [% mylist.push(col) %] + [% END %] + [% CSV.dump(mylist) %] + +[% END %] \ No newline at end of file diff --git a/Netdisco/share/views/ajax/report/portutilization_csv.tt b/Netdisco/share/views/ajax/report/portutilization_csv.tt new file mode 100644 index 00000000..48f1fff7 --- /dev/null +++ b/Netdisco/share/views/ajax/report/portutilization_csv.tt @@ -0,0 +1,12 @@ +[% USE CSV -%] +[% CSV.dump([ 'Device' 'Total Ports' 'In Use' 'Shutdown' 'Free' ]) %] + +[% WHILE (row = results.next) %] + [% mylist = [] %] + [% device = row.dns || row.ip %] + [% FOREACH col IN [ device row.port_count row.ports_in_use row.ports_shutdown row.ports_free ] %] + [% mylist.push(col) %] + [% END %] + [% CSV.dump(mylist) %] + +[% END %] \ No newline at end of file diff --git a/Netdisco/share/views/ajax/search/device_csv.tt b/Netdisco/share/views/ajax/search/device_csv.tt new file mode 100644 index 00000000..7402f87c --- /dev/null +++ b/Netdisco/share/views/ajax/search/device_csv.tt @@ -0,0 +1,12 @@ +[% USE CSV -%] +[% CSV.dump(headers) %] + +[% WHILE (row = results.next) %] + [% mylist = [] %] + [% device = row.dns || row.ip %] + [% FOREACH col IN [ device row.contact row.location row.name row.model row.os_ver row.ip row.serial] %] + [% mylist.push(col) %] + [% END %] + [% CSV.dump(mylist) %] + +[% END %] \ No newline at end of file diff --git a/Netdisco/share/views/ajax/search/port_csv.tt b/Netdisco/share/views/ajax/search/port_csv.tt new file mode 100644 index 00000000..6f97c7f7 --- /dev/null +++ b/Netdisco/share/views/ajax/search/port_csv.tt @@ -0,0 +1,12 @@ +[% USE CSV -%] +[% CSV.dump([ 'Description' 'Port' 'Name' 'Vlan' ]) %] + +[% WHILE (row = results.next) %] + [% mylist = [] %] + [% myport = "$row.ip [ $row.port ] (" _ row.device.dns _ ")" IF row.device.dns %] + [% FOREACH col IN [ row.name myport row.descr row.vlan ] %] + [% mylist.push(col) %] + [% END %] + [% CSV.dump(mylist) %] + +[% END %] \ No newline at end of file diff --git a/Netdisco/share/views/ajax/search/vlan_csv.tt b/Netdisco/share/views/ajax/search/vlan_csv.tt new file mode 100644 index 00000000..67dd9916 --- /dev/null +++ b/Netdisco/share/views/ajax/search/vlan_csv.tt @@ -0,0 +1,12 @@ +[% USE CSV -%] +[% CSV.dump([ 'Vlan' 'Device' 'Description' 'Model' 'OS' 'Vendor' ]) %] + +[% WHILE (row = results.next) %] + [% mylist = [] %] + [% device = row.dns || row.ip %] + [% FOREACH col IN [ row.vlan.vlan device row.vlan.description row.model row.os row.vendor ] %] + [% mylist.push(col) %] + [% END %] + [% CSV.dump(mylist) %] + +[% END %] diff --git a/Netdisco/share/views/device.tt b/Netdisco/share/views/device.tt index bfa27799..e70a2de7 100644 --- a/Netdisco/share/views/device.tt +++ b/Netdisco/share/views/device.tt @@ -45,7 +45,12 @@ [% FOREACH tab IN settings._device_tabs %] [% tab.label %] [% END %] - [% d.dns || d.name | html_entity %] + + [% d.dns || d.name | html_entity %] +   + +
[% FOREACH tab IN settings._device_tabs %] diff --git a/Netdisco/share/views/js/common.js b/Netdisco/share/views/js/common.js index d66e9e64..3f1dc021 100644 --- a/Netdisco/share/views/js/common.js +++ b/Netdisco/share/views/js/common.js @@ -1,3 +1,23 @@ + // csv download icon on any table page + // needs to be dynamically updated to use current search options + function update_csv_download_link (type, tab, show) { + var form = '#' + tab + '_form'; + var query = $(form).serialize(); + + if (show == '1') { + $('#nd_csv-download') + .attr('href', '/ajax/content/' + type + '/' + tab + '?' + query) + .attr('download', 'netdisco-' + type + '-' + tab + '.csv') + .show(); + } + else { + $('#nd_csv-download').hide(); + } + } + + // page title includes tab name and possibly device name + // this is nice for when you have multiple netdisco pages open in the + // browser function update_page_title (tab) { var pgtitle = 'Netdisco'; if ($('#nd_device-name').text().length) { @@ -43,6 +63,7 @@ [% FOREACH tab IN settings._search_tabs %] $('[% "#${tab.tag}_form" %]').submit(function (event) { var pgtitle = update_page_title('[% tab.tag %]'); + update_csv_download_link('search', '[% tab.tag %]', '[% tab.provides_csv %]'); update_browser_history('[% tab.tag %]', pgtitle); copy_navbar_to_sidebar('[% tab.tag %]'); do_search(event, '[% tab.tag %]'); @@ -55,8 +76,10 @@ [% FOREACH tab IN settings._device_tabs %] $('[% "#${tab.tag}_form" %]').submit(function (event) { var pgtitle = update_page_title('[% tab.tag %]'); + update_csv_download_link('device', '[% tab.tag %]', '[% tab.provides_csv %]'); update_browser_history('[% tab.tag %]', pgtitle); copy_navbar_to_sidebar('[% tab.tag %]'); + [% IF tab.tag == 'ports' %] var cookie = $('#ports_form').find('input,select') .not('#nd_port-query,input[name="q"],input[name="tab"]') @@ -66,6 +89,7 @@ }); $.cookie('nd_ports-form', $.param(cookie) ,{ expires: 365 }); [% END %] + do_search(event, '[% tab.tag %]'); }); [% END %] @@ -74,7 +98,8 @@ [% IF report %] // for the report pages $('[% "#${report.tag}_form" %]').submit(function (event) { - update_page_title('[% tab.tag %]'); + update_page_title('[% report.tag %]'); + update_csv_download_link('report', '[% report.tag %]', '1'); do_search(event, '[% report.tag %]'); }); [% END -%] @@ -82,7 +107,8 @@ [% IF task %] // for the admin pages $('[% "#${task.tag}_form" %]').submit(function (event) { - update_page_title('[% tab.tag %]'); + update_page_title('[% task.tag %]'); + update_csv_download_link('task', '[% task.tag %]', '1'); do_search(event, '[% task.tag %]'); }); [% END %] diff --git a/Netdisco/share/views/report.tt b/Netdisco/share/views/report.tt index b3cb963b..1473ae71 100644 --- a/Netdisco/share/views/report.tt +++ b/Netdisco/share/views/report.tt @@ -28,6 +28,13 @@
diff --git a/Netdisco/share/views/search.tt b/Netdisco/share/views/search.tt index 59d1f584..43c00b00 100644 --- a/Netdisco/share/views/search.tt +++ b/Netdisco/share/views/search.tt @@ -32,6 +32,11 @@ [% FOREACH tab IN settings._search_tabs %] [% tab.label %] [% END %] + + + +
[% FOREACH tab IN settings._search_tabs %]