From 49d9ea969069430ef3fe23e5b1ac3599e929bb04 Mon Sep 17 00:00:00 2001 From: Mark Wells Date: Mon, 10 Oct 2016 11:59:41 -0700 Subject: new tower/sector UI, mapping features, and network monitoring, #37802 --- httemplate/browse/tower-map.html | 85 ++++++ httemplate/browse/tower.html | 6 +- httemplate/docs/license.html | 4 + httemplate/edit/process/tower.html | 2 +- httemplate/edit/tower.html | 19 +- .../elements/images/ui-icons_444444_256x240.png | Bin 0 -> 6992 bytes .../elements/images/ui-icons_515151_256x240.png | Bin 0 -> 6987 bytes .../elements/images/ui-icons_555555_256x240.png | Bin 0 -> 6988 bytes .../elements/images/ui-icons_777620_256x240.png | Bin 0 -> 4549 bytes .../elements/images/ui-icons_777777_256x240.png | Bin 0 -> 6999 bytes .../elements/images/ui-icons_cc0000_256x240.png | Bin 0 -> 4549 bytes httemplate/elements/jquery-gmaps-latlon-picker.js | 254 +++++++++++++++++ httemplate/elements/jquery-ui.min.css | 10 +- httemplate/elements/jquery-ui.min.js | 22 +- httemplate/elements/jquery-ui.structure.min.css | 5 + httemplate/elements/jquery-ui.theme.min.css | 5 + httemplate/elements/mapselect.html | 82 ++++++ httemplate/elements/tower_sector.html | 68 ----- httemplate/elements/tr-tower_sectors.html | 250 +++++++++++++++++ httemplate/misc/sector_coverage-json.cgi | 40 +++ httemplate/search/elements/gmap.html | 63 +++-- httemplate/search/sector.html | 1 + httemplate/search/svc_broadband-json.cgi | 108 ++++++++ httemplate/search/svc_broadband-map.html | 35 +-- httemplate/search/tower-map.html | 303 +++++++++++++++++++++ httemplate/view/svc_broadband-popup.html | 35 +++ 26 files changed, 1262 insertions(+), 135 deletions(-) create mode 100644 httemplate/browse/tower-map.html create mode 100644 httemplate/elements/images/ui-icons_444444_256x240.png create mode 100644 httemplate/elements/images/ui-icons_515151_256x240.png create mode 100644 httemplate/elements/images/ui-icons_555555_256x240.png create mode 100644 httemplate/elements/images/ui-icons_777620_256x240.png create mode 100644 httemplate/elements/images/ui-icons_777777_256x240.png create mode 100644 httemplate/elements/images/ui-icons_cc0000_256x240.png create mode 100644 httemplate/elements/jquery-gmaps-latlon-picker.js create mode 100644 httemplate/elements/jquery-ui.structure.min.css create mode 100644 httemplate/elements/jquery-ui.theme.min.css create mode 100644 httemplate/elements/mapselect.html delete mode 100644 httemplate/elements/tower_sector.html create mode 100644 httemplate/elements/tr-tower_sectors.html create mode 100644 httemplate/misc/sector_coverage-json.cgi create mode 100755 httemplate/search/svc_broadband-json.cgi create mode 100755 httemplate/search/tower-map.html create mode 100644 httemplate/view/svc_broadband-popup.html (limited to 'httemplate') diff --git a/httemplate/browse/tower-map.html b/httemplate/browse/tower-map.html new file mode 100644 index 000000000..62e08fcb5 --- /dev/null +++ b/httemplate/browse/tower-map.html @@ -0,0 +1,85 @@ +<& /elements/header.html, 'Towers and sectors' &> + + + + +
+ + + + + +
+
+
+ + diff --git a/httemplate/elements/tower_sector.html b/httemplate/elements/tower_sector.html deleted file mode 100644 index 987177582..000000000 --- a/httemplate/elements/tower_sector.html +++ /dev/null @@ -1,68 +0,0 @@ -% unless ( $opt{'js_only'} ) { - - - - - -% foreach my $field ( @fields ) { - - -% } - -
- get($field) |h %>" - <% $onchange %> - >
- <% $label{$field} %> -
- - -% } -<%init> - -my( %opt ) = @_; - -my $name = $opt{'element_name'} || $opt{'field'} || 'sectornum'; -my $id = $opt{'id'} || 'sectornum'; - -my $curr_value = $opt{'curr_value'} || $opt{'value'}; - -my $onchange = ''; -if ( $opt{'onchange'} ) { - $onchange = $opt{'onchange'}; - $onchange .= '(this)' unless $onchange =~ /\(\w*\);?$/; - $onchange =~ s/\(what\);/\(this\);/g; #ugh, terrible hack. all onchange - #callbacks should act the same - $onchange = 'onChange="'. $onchange. '"'; -} - -my $tower_sector; -if ( $curr_value ) { - $tower_sector = qsearchs('tower_sector', { 'sectornum' => $curr_value } ); -} else { - $tower_sector = new FS::tower_sector {}; -} - -my %size = ( 'title' => 12 ); - -tie my %label, 'Tie::IxHash', - 'sectorname' => 'Name', - 'ip_addr' => 'IP Address', - 'height' => 'Height', - 'freq_mhz' => 'Freq. (MHz)', - 'direction' => 'Direction', # or a button to set these to 0 for omni - 'downtilt' => 'Downtilt', - 'width' => 'Horiz. width', - 'v_width' => 'Vert. width', - 'sector_range' => 'Range', - 'margin' => 'Signal margin (dB)', -; - -my @fields = keys %label; - - diff --git a/httemplate/elements/tr-tower_sectors.html b/httemplate/elements/tr-tower_sectors.html new file mode 100644 index 000000000..4e8f3fb47 --- /dev/null +++ b/httemplate/elements/tr-tower_sectors.html @@ -0,0 +1,250 @@ +<%init> +my %opt = @_; +my $tower = $opt{'object'}; +my $towernum = $tower->towernum; +my $cgi = $opt{'cgi'}; + +my $tabcounter = 0; + +my @fields = qw( + sectorname ip_addr height freq_mhz direction width tilt v_width db_high + db_low sector_range +); + +my @sectors; +if ( $cgi->param('error') ) { + foreach my $k ($cgi->param) { + if ($k =~ /^sectornum\d+$/) { + my $sectornum = $cgi->param($k); + my $sector = FS::tower_sector->new({ + 'sectornum' => $sectornum, + 'towernum' => $towernum, + map { $_ => scalar($cgi->param($k.'_'.$_)) } @fields, + }); + push @sectors, $sector if length($sector->sectorname); + } + } +} elsif ( $towernum ) { + @sectors = $tower->tower_sector; +} # else new mode, no sectors yet + +my $id = $opt{id} || $opt{field} || 'sectornum'; + + +<& tablebreak-tr-title.html, value => 'Sectors' &> + + + + + + +%# prototypes +
+<& .tab, id => $id . '_P' &> +<& .panel, id => $id . '_P' &> +
+ +%# main container +
+ + +% $tabcounter = 0; +% foreach my $sector (@sectors) { +<& .panel, sector => $sector, id => $id . $tabcounter &> +% $tabcounter++; +% } +
+ + + +<%def .tab> +% my %opt = @_; +% my $sector = $opt{sector}; +% my $id = $opt{id}; +% my $title = $sector ? $sector->sectorname : mt('Add new'); +
  • + <% $title |h %> +
  • + +<%def .panel> +% my %opt = @_; +% my $sector = $opt{sector} || FS::tower_sector->new({}); +% my $id = $opt{id}; # sectornumX +
    +% # no id on this one, the panel gets the "sectornumX" id + +

    + + + + + +

    +

    + + + <% emt('feet above ground') %> +

    +

    + + ° + + ° +

    + +

    + + + <% emt('MHz') %> +

    + +

    + + ° + + ° +

    + + +
    + + <% emt('dB (high quality)') %> +
    + + + <% emt('dB (low quality)') %> +
    + +
    + diff --git a/httemplate/misc/sector_coverage-json.cgi b/httemplate/misc/sector_coverage-json.cgi new file mode 100644 index 000000000..37595f5e2 --- /dev/null +++ b/httemplate/misc/sector_coverage-json.cgi @@ -0,0 +1,40 @@ +<% encode_json($collection) %> +<%init> +my @sectors; +if ( my $towernum = $cgi->param('towernum') ) { + @sectors = qsearch('tower_sector', { towernum => $towernum }); +} elsif ( my $sectornum = $cgi->param('sectornum') ) { + @sectors = FS::tower_sector->by_key($sectornum); +} else { + die "towernum or sectornum required"; +} +my @features; +my $collection = { + type => 'FeatureCollection', + features => \@features, +}; +foreach my $sector (@sectors) { + my $sectornum = $sector->sectornum; + my $low = $sector->db_low; + my $high = $sector->db_high; + my $color = '#' . ($sector->tower->color || 'ffffff'); + foreach my $coverage ( $sector->sector_coverage ) { + #note $coverage->geometry is already JSON + my $level = $coverage->db_loss; + push @features, { + type => 'Feature', + id => "sector/$sectornum/$level", + properties => { + level => $level, + low => ($level == $low ? 1 : 0), + high => ($level == $high ? 1 : 0), + style => { + strokeColor => $color, + fillColor => $color, + }, + }, + geometry => decode_json($coverage->geometry), + }; + } +} + diff --git a/httemplate/search/elements/gmap.html b/httemplate/search/elements/gmap.html index b7d135dd6..69fdc5a09 100644 --- a/httemplate/search/elements/gmap.html +++ b/httemplate/search/elements/gmap.html @@ -37,6 +37,9 @@ Generic Google Maps front end. <%init> + +my $apikey = FS::Conf->new->config('google_maps_api_key'); + foreach (@features) { $_->{type} = 'Feature'; # any other per-feature massaging can go here @@ -57,7 +60,7 @@ body { height: 100%; margin: 0px; padding: 0px } #map_canvas { height: 100%; } - + + + +
    + + + + + +<& /elements/footer.html &> +<%init> + +die "access denied" unless + $FS::CurrentUser::CurrentUser->access_right('List services'); + +my $conf = new FS::Conf; + +my $apikey = $conf->config('google_maps_api_key'); + +my @features; # geoJSON structure + +my @towers = qsearch('tower', { + 'latitude' => { op=>'!=', value=>''}, + 'longitude' => { op=>'!=', value=>''}, +}); +my %sectors; # towernum => arrayref +my @towernums; + +foreach my $tower (@towers) { + my $towernum = $tower->towernum; + push @towernums, $towernum; + my @coord = ( + $tower->longitude + 0, + $tower->latitude + 0, + ); + push @features, + { + type => 'Feature', + id => 'tower/'.$towernum, + geometry => { + type => 'Point', + coordinates => \@coord, + }, + properties => { + style => { + icon => { + path => undef, + url => $fsurl.'images/antenna-square-21x51.png', + anchor => { x => 10, y => 4 }, + strokeColor => ($tower->color || 'black'), + }, + }, + content => include('.tower', $tower), + }, + }; + + $sectors{$towernum} = [ $tower->tower_sector ]; + +} # foreach $tower + +my $tower_data = { + type => 'FeatureCollection', + features => \@features +}; + + +<%def .tower> +% my $tower = shift; +% my $can_edit = $FS::CurrentUser::CurrentUser->access_right('Configuration'); +

    +% if ( $can_edit ) { + +% } +Tower #<% $tower->towernum %> | <% $tower->towername %> +% if ( $can_edit ) { + +% } +

    +% my $count_query = 'SELECT COUNT(*) FROM svc_broadband LEFT JOIN addr_status using (ip_addr) JOIN tower_sector USING (sectornum) WHERE tower_sector.towernum = '.$tower->towernum; +% my $num_down = FS::Record->scalar_sql("$count_query AND addr_status.up IS NULL AND addr_status._date IS NOT NULL"); +% my $num_up = FS::Record->scalar_sql("$count_query AND addr_status.up IS NOT NULL"); + +<% emt('Show services') %> +( <% $num_up %> <% emt('UP') %> +<% $num_down %> <% emt('DOWN') %> ) +
    + +<% emt('Show coverage') %> + diff --git a/httemplate/view/svc_broadband-popup.html b/httemplate/view/svc_broadband-popup.html new file mode 100644 index 000000000..1c2347454 --- /dev/null +++ b/httemplate/view/svc_broadband-popup.html @@ -0,0 +1,35 @@ +<%init> +die "access denied" + unless $FS::CurrentUser::CurrentUser->access_right('View customer services'); + +my ($svcnum) = $cgi->keywords; +# cleans svcnum, checks agent access, etc. +my $svc = qsearchs( FS::svc_broadband->search({ 'svcnum' => $svcnum }) ); +my $addr_status = $svc->addr_status; +my @label = $svc->cust_svc->label; + + +

    + + <% $label[0] |h %> #<% $svc->svcnum %> | <% $label[1] %> + +

    +% if ( $addr_status ) { +

    + + <% emt( $addr_status->up ? 'UP' : 'DOWN' ) %> + +% if ( $addr_status->up ) { + (<% $addr_status->delay |h %> ms) +% } + <% emt('as of') . ' ' . time2str('%b %o %H:%M', $addr_status->_date) %> +

    +% } +% my $cust_main = $svc->cust_main; + +<& /elements/small_custview.html, { + cust_main => $svc->cust_main, + #url => $fsurl.'view/cust_main.cgi', +} &> + + -- cgit v1.2.1