update livemap to use rivets.js bindings for data updates

This commit is contained in:
Nabeel Shahzad
2018-05-03 15:07:16 -05:00
parent cbb5182cea
commit 23f1a8225a
21 changed files with 557 additions and 321 deletions

View File

@@ -97,6 +97,26 @@ class PirepController extends Controller
} }
} }
/**
* Get all the active PIREPs
* @param $id
* @return PirepResource
*/
public function index()
{
$active = [];
$pireps = $this->acarsRepo->getPositions();
foreach($pireps as $pirep) {
if(\count($pirep->position) === 0) {
continue;
}
$active[] = $pirep;
}
return PirepResource::collection(collect($active));
}
/** /**
* @param $id * @param $id
* @return PirepResource * @return PirepResource

View File

@@ -25,6 +25,7 @@ class PositionRequest extends FormRequest
'positions' => 'required|array', 'positions' => 'required|array',
'positions.*.lat' => 'required|numeric', 'positions.*.lat' => 'required|numeric',
'positions.*.lon' => 'required|numeric', 'positions.*.lon' => 'required|numeric',
'positions.*.status' => 'nullable',
'positions.*.altitude' => 'nullable|numeric', 'positions.*.altitude' => 'nullable|numeric',
'positions.*.heading' => 'nullable|numeric|between:0,360', 'positions.*.heading' => 'nullable|numeric|between:0,360',
'positions.*.vs' => 'nullable', 'positions.*.vs' => 'nullable',

View File

@@ -25,6 +25,7 @@ class PrefileRequest extends FormRequest
'arr_airport_id' => 'required', 'arr_airport_id' => 'required',
'source_name' => 'required', 'source_name' => 'required',
'status' => 'nullable',
'level' => 'nullable|numeric', 'level' => 'nullable|numeric',
'flight_type' => 'nullable', 'flight_type' => 'nullable',
'route_code' => 'nullable', 'route_code' => 'nullable',

View File

@@ -2,6 +2,8 @@
namespace App\Http\Resources; namespace App\Http\Resources;
use App\Support\Units\Distance;
use App\Support\Units\Fuel;
use Illuminate\Http\Resources\Json\Resource; use Illuminate\Http\Resources\Json\Resource;
class Acars extends Resource class Acars extends Resource
@@ -14,6 +16,16 @@ class Acars extends Resource
*/ */
public function toArray($request) public function toArray($request)
{ {
return parent::toArray($request); $obj = parent::toArray($request);
if ($this->distance instanceof Distance) {
$obj['distance'] = $this->distance->units;
}
if ($this->fuel instanceof Fuel) {
$obj['fuel'] = $this->fuel->units;
}
return $obj;
} }
} }

View File

@@ -19,6 +19,8 @@ class Pirep extends Resource
{ {
$pirep = parent::toArray($request); $pirep = parent::toArray($request);
$pirep['ident'] = $this->ident;
if ($this->distance instanceof Distance) { if ($this->distance instanceof Distance) {
$pirep['distance'] = $this->distance->units; $pirep['distance'] = $this->distance->units;
} }

View File

@@ -55,7 +55,7 @@ class AcarsRepository extends Repository
*/ */
public function getPositions() public function getPositions()
{ {
return Pirep::with(['airline', 'position']) return Pirep::with(['airline', 'position', 'aircraft'])
->where(['state' => PirepState::IN_PROGRESS]) ->where(['state' => PirepState::IN_PROGRESS])
->get(); ->get();
} }

View File

@@ -5,6 +5,7 @@
*/ */
Route::group([], function () { Route::group([], function () {
Route::get('acars', 'AcarsController@index'); Route::get('acars', 'AcarsController@index');
Route::get('pireps', 'PirepController@index');
Route::get('pireps/{pirep_id}', 'PirepController@get'); Route::get('pireps/{pirep_id}', 'PirepController@get');
Route::get('pireps/{pirep_id}/acars/geojson', 'PirepController@acars_geojson'); Route::get('pireps/{pirep_id}/acars/geojson', 'PirepController@acars_geojson');

View File

@@ -31,7 +31,7 @@ class DatabaseService extends Service
*/ */
protected function time(): string protected function time(): string
{ {
return Carbon::now('UTC')->format('Y-m-d H:i:s'); return Carbon::now('UTC'); //->format('Y-m-d H:i:s');
} }
/** /**
@@ -43,7 +43,6 @@ class DatabaseService extends Service
public function seed_from_yaml_file($yaml_file, $ignore_errors = false): array public function seed_from_yaml_file($yaml_file, $ignore_errors = false): array
{ {
$yml = file_get_contents($yaml_file); $yml = file_get_contents($yaml_file);
return $this->seed_from_yaml($yml, $ignore_errors); return $this->seed_from_yaml($yml, $ignore_errors);
} }
@@ -61,39 +60,56 @@ class DatabaseService extends Service
$imported[$table] = 0; $imported[$table] = 0;
foreach ($rows as $row) { foreach ($rows as $row) {
# see if this table uses a UUID as the PK
# if no ID is specified
if (in_array($table, $this->uuid_tables)) {
if (!array_key_exists('id', $row)) {
$row['id'] = Uuid::generate()->string;
}
}
# encrypt any password fields
if (array_key_exists('password', $row)) {
$row['password'] = bcrypt($row['password']);
}
# if any time fields are == to "now", then insert the right time
foreach ($this->time_fields as $tf) {
if (array_key_exists($tf, $row) && strtolower($row[$tf]) === 'now') {
$row[$tf] = $this->time();
}
}
try { try {
DB::table($table)->insert($row); $row = $this->insert_row($table, $row);
++$imported[$table]; } catch(QueryException $e) {
} catch (QueryException $e) {
if ($ignore_errors) { if ($ignore_errors) {
continue; continue;
} }
throw $e; throw $e;
} }
++$imported[$table];
} }
} }
return $imported; return $imported;
} }
/**
* @param $table
* @param $row
* @return mixed
* @throws \Exception
*/
public function insert_row($table, $row) {
# see if this table uses a UUID as the PK
# if no ID is specified
if (\in_array($table, $this->uuid_tables, true)) {
if (!array_key_exists('id', $row)) {
$row['id'] = Uuid::generate()->string;
}
}
# encrypt any password fields
if (array_key_exists('password', $row)) {
$row['password'] = bcrypt($row['password']);
}
# if any time fields are == to "now", then insert the right time
foreach($row as $column => $value) {
if(strtolower($value) === 'now') {
$row[$column] = $this->time();
}
}
try {
DB::table($table)->insert($row);
} catch (QueryException $e) {
throw $e;
}
return $row;
}
} }

File diff suppressed because one or more lines are too long

View File

@@ -1,28 +1,28 @@
/*! /*!
========================================================= =========================================================
* Now-ui-kit - v1.0.0 * Now-ui-kit - v1.0.0
========================================================= =========================================================
* Product Page: http://www.creative-tim.com/product/now-ui-kit * Product Page: http://www.creative-tim.com/product/now-ui-kit
* Copyright 2017 Creative Tim (http://www.creative-tim.com) * Copyright 2017 Creative Tim (http://www.creative-tim.com)
* Licensed under MIT (https://github.com/creativetimofficial/now-ui-kit/blob/master/LICENSE.md) * Licensed under MIT (https://github.com/creativetimofficial/now-ui-kit/blob/master/LICENSE.md)
* Designed by www.invisionapp.com Coded by www.creative-tim.com * Designed by www.invisionapp.com Coded by www.creative-tim.com
========================================================= =========================================================
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*/ */
/* brand Colors */ /* brand Colors */
/* light colors */ /* light colors */
/* ======================================================================== /* ========================================================================
* bootstrap-switch - v3.3.2 * bootstrap-switch - v3.3.2
* http://www.bootstrap-switch.org * http://www.bootstrap-switch.org
* ======================================================================== * ========================================================================
* Copyright 2012-2013 Mattia Larentis * Copyright 2012-2013 Mattia Larentis
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
*/ */
.bootstrap-switch { .bootstrap-switch {
display: inline-block; display: inline-block;
@@ -293,9 +293,9 @@
} }
/*! nouislider - 9.1.0 - 2016-12-10 16:00:32 */ /*! nouislider - 9.1.0 - 2016-12-10 16:00:32 */
/* Functional styling; /* Functional styling;
* These styles are required for noUiSlider to function. * These styles are required for noUiSlider to function.
* You don't need to change these rules to apply your design. * You don't need to change these rules to apply your design.
*/ */
.noUi-target, .noUi-target,
.noUi-target * { .noUi-target * {
@@ -353,8 +353,8 @@
cursor: inherit !important; cursor: inherit !important;
} }
/* Painting and performance; /* Painting and performance;
* Browsers can paint handles in their own layer. * Browsers can paint handles in their own layer.
*/ */
.noUi-base, .noUi-base,
.noUi-handle { .noUi-handle {
@@ -362,7 +362,7 @@
transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0);
} }
/* Slider size and handle placement; /* Slider size and handle placement;
*/ */
.noUi-horizontal { .noUi-horizontal {
height: 1px; height: 1px;
@@ -391,7 +391,7 @@
top: -17px; top: -17px;
} }
/* Styling; /* Styling;
*/ */
.noUi-target { .noUi-target {
background-color: rgba(182, 182, 182, 0.3); background-color: rgba(182, 182, 182, 0.3);
@@ -405,7 +405,7 @@
transition: background 450ms; transition: background 450ms;
} }
/* Handles and cursors; /* Handles and cursors;
*/ */
.noUi-draggable { .noUi-draggable {
cursor: ew-resize; cursor: ew-resize;
@@ -419,8 +419,8 @@
border-radius: 3px; border-radius: 3px;
background: #FFF; background: #FFF;
cursor: default; cursor: default;
-webkit-box-shadow: inset 0 0 1px #FFF, -webkit-box-shadow: inset 0 0 1px #FFF, inset 0 1px 7px #EBEBEB, 0 3px 6px -3px #BBB;
inset 0 1px 7px #EBEBEB, box-shadow: inset 0 0 1px #FFF, inset 0 1px 7px #EBEBEB, 0 3px 6px -3px #BBB;
-webkit-transition: 300ms ease 0s; -webkit-transition: 300ms ease 0s;
-moz-transition: 300ms ease 0s; -moz-transition: 300ms ease 0s;
-ms-transition: 300ms ease 0s; -ms-transition: 300ms ease 0s;
@@ -433,7 +433,7 @@
transform: scale3d(1.5, 1.5, 1); transform: scale3d(1.5, 1.5, 1);
} }
-webkit-transform: scale3d(1.5, 1.5, 1); /* Disabled state;
*/ */
[disabled] .noUi-connect { [disabled] .noUi-connect {
background: #B8B8B8; background: #B8B8B8;
@@ -445,8 +445,8 @@
cursor: not-allowed; cursor: not-allowed;
} }
[disabled] .noUi-handle { /* Base;
cursor: not-allowed; *
*/ */
.noUi-pips, .noUi-pips,
.noUi-pips * { .noUi-pips * {
@@ -459,8 +459,8 @@
color: #999; color: #999;
} }
position: absolute; /* Values;
color: #999; *
*/ */
.noUi-value { .noUi-value {
position: absolute; position: absolute;
@@ -472,8 +472,8 @@
font-size: 10px; font-size: 10px;
} }
color: #ccc; /* Markings;
font-size: 10px; *
*/ */
.noUi-marker { .noUi-marker {
position: absolute; position: absolute;
@@ -488,8 +488,8 @@
background: #AAA; background: #AAA;
} }
.noUi-marker-large { /* Horizontal layout;
background: #AAA; *
*/ */
.noUi-pips-horizontal { .noUi-pips-horizontal {
padding: 10px 0; padding: 10px 0;
@@ -518,8 +518,8 @@
height: 15px; height: 15px;
} }
.noUi-marker-horizontal.noUi-marker-large { /* Vertical layout;
height: 15px; *
*/ */
.noUi-pips-vertical { .noUi-pips-vertical {
padding: 0 10px; padding: 0 10px;
@@ -645,10 +645,10 @@
background-color: #FF3636; background-color: #FF3636;
} }
.slider.slider-danger .noUi-handle { /*!
background-color: #FF3636; * Datepicker for Bootstrap v1.7.0-dev (https://github.com/uxsolutions/bootstrap-datepicker)
} *
* Licensed under the Apache License v2.0 (http://www.apache.org/licenses/LICENSE-2.0)
*/ */
.datepicker { .datepicker {
padding: 8px 6px; padding: 8px 6px;
@@ -2198,17 +2198,17 @@ fieldset[disabled]
background-color: #E3E3E3; background-color: #E3E3E3;
} }
.input-group[disabled] .input-group-addon { /*.input-group .form-control:first-child,
background-color: #E3E3E3; .input-group-addon:first-child,
} .input-group-btn:first-child > .dropdown-toggle,
.input-group-btn:last-child > .btn:not(:last-child):not(.dropdown-toggle) {
/*.input-group .form-control:first-child, border-right: 0 none;
.input-group-addon:first-child, }
.input-group-btn:first-child > .dropdown-toggle, .input-group .form-control:last-child,
.input-group-btn:last-child > .btn:not(:last-child):not(.dropdown-toggle) { .input-group-addon:last-child,
border-right: 0 none; .input-group-btn:last-child > .dropdown-toggle,
} .input-group-btn:first-child > .btn:not(:first-child) {
.input-group .form-control:last-child, border-left: 0 none;
}*/ }*/
.form-control[disabled], .form-control[readonly], fieldset[disabled] .form-control { .form-control[disabled], .form-control[readonly], fieldset[disabled] .form-control {
background-color: #E3E3E3; background-color: #E3E3E3;
@@ -3755,12 +3755,12 @@ img {
box-shadow: 0px 5px 25px 0px rgba(0, 0, 0, 0.2); box-shadow: 0px 5px 25px 0px rgba(0, 0, 0, 0.2);
} }
-webkit-box-shadow: 0px 5px 25px 0px rgba(0, 0, 0, 0.2); /* --------------------------------
box-shadow: 0px 5px 25px 0px rgba(0, 0, 0, 0.2);
} Nucleo Outline Web Font - nucleoapp.com/
License - nucleoapp.com/license/
/* -------------------------------- Created using IcoMoon - icomoon.io
-------------------------------- */ -------------------------------- */
@font-face { @font-face {
font-family: 'Nucleo Outline'; font-family: 'Nucleo Outline';
@@ -3770,8 +3770,8 @@ Created using IcoMoon - icomoon.io
font-style: normal; font-style: normal;
} }
font-weight: normal; /*------------------------
font-style: normal; base class definition
-------------------------*/ -------------------------*/
.now-ui-icons { .now-ui-icons {
display: inline-block; display: inline-block;
@@ -3784,11 +3784,11 @@ Created using IcoMoon - icomoon.io
-moz-osx-font-smoothing: grayscale; -moz-osx-font-smoothing: grayscale;
} }
-webkit-font-smoothing: antialiased; /*------------------------
-moz-osx-font-smoothing: grayscale; change icon size
-------------------------*/ -------------------------*/
/*----------------------------------
/*------------------------ add a square/circle background
-----------------------------------*/ -----------------------------------*/
.now-ui-icons.circle { .now-ui-icons.circle {
padding: 0.33333333em; padding: 0.33333333em;
@@ -3800,8 +3800,8 @@ Created using IcoMoon - icomoon.io
border-radius: 50%; border-radius: 50%;
} }
.now-ui-icons.circle { /*------------------------
border-radius: 50%; list icons
-------------------------*/ -------------------------*/
.nc-icon-ul { .nc-icon-ul {
padding-left: 0; padding-left: 0;
@@ -3825,8 +3825,8 @@ Created using IcoMoon - icomoon.io
left: -1.9047619em; left: -1.9047619em;
} }
top: -0.19047619em; /*------------------------
left: -1.9047619em; spinning icons
-------------------------*/ -------------------------*/
.now-ui-icons.spin { .now-ui-icons.spin {
-webkit-animation: nc-icon-spin 2s infinite linear; -webkit-animation: nc-icon-spin 2s infinite linear;
@@ -3853,11 +3853,11 @@ Created using IcoMoon - icomoon.io
} }
} }
transform: rotate(360deg); /*------------------------
} rotated/flipped icons
-------------------------*/ -------------------------*/
/*------------------------
/*------------------------ font icons
-------------------------*/ -------------------------*/
.now-ui-icons.ui-1_check:before { .now-ui-icons.ui-1_check:before {
content: "\EA22"; content: "\EA22";
@@ -5668,21 +5668,21 @@ Created using IcoMoon - icomoon.io
} }
} }
width: auto; /*.separator{
} content: "Separator";
} color: #FFFFFF;
display: block;
/*.separator{ width: 100%;
content: "Separator"; padding: 20px;
color: #FFFFFF; }
display: block; .separator-line{
width: 100%; background-color: #EEE;
padding: 20px; height: 1px;
} width: 100%;
.separator-line{ display: block;
background-color: #EEE; }
height: 1px; .separator.separator-gray{
width: 100%; background-color: #EEEEEE;
}*/ }*/
.social-buttons-demo .btn { .social-buttons-demo .btn {
margin-right: 5px; margin-right: 5px;

View File

@@ -5,6 +5,16 @@
margin-top: 2px; margin-top: 2px;
} }
.map-info-box {
display: none;
position: absolute;
bottom: 0;
padding: 20px;
height: 100px;
z-index: 9999;
background-color: rgba(232, 232, 232, 0.9);
}
.dashboard-box { .dashboard-box {
background: #067ec1; background: #067ec1;
color: #FFF; color: #FFF;

File diff suppressed because one or more lines are too long

View File

@@ -6799,31 +6799,31 @@ button.close {
} }
/*# sourceMappingURL=bootstrap.css.map */ /*# sourceMappingURL=bootstrap.css.map */
/*! /*!
========================================================= =========================================================
* Now-ui-kit - v1.0.0 * Now-ui-kit - v1.0.0
========================================================= =========================================================
* Product Page: http://www.creative-tim.com/product/now-ui-kit * Product Page: http://www.creative-tim.com/product/now-ui-kit
* Copyright 2017 Creative Tim (http://www.creative-tim.com) * Copyright 2017 Creative Tim (http://www.creative-tim.com)
* Licensed under MIT (https://github.com/creativetimofficial/now-ui-kit/blob/master/LICENSE.md) * Licensed under MIT (https://github.com/creativetimofficial/now-ui-kit/blob/master/LICENSE.md)
* Designed by www.invisionapp.com Coded by www.creative-tim.com * Designed by www.invisionapp.com Coded by www.creative-tim.com
========================================================= =========================================================
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*/ */
/* brand Colors */ /* brand Colors */
/* light colors */ /* light colors */
/* ======================================================================== /* ========================================================================
* bootstrap-switch - v3.3.2 * bootstrap-switch - v3.3.2
* http://www.bootstrap-switch.org * http://www.bootstrap-switch.org
* ======================================================================== * ========================================================================
* Copyright 2012-2013 Mattia Larentis * Copyright 2012-2013 Mattia Larentis
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
*/ */
.bootstrap-switch { .bootstrap-switch {
display: inline-block; display: inline-block;
@@ -7094,9 +7094,9 @@ button.close {
} }
/*! nouislider - 9.1.0 - 2016-12-10 16:00:32 */ /*! nouislider - 9.1.0 - 2016-12-10 16:00:32 */
/* Functional styling; /* Functional styling;
* These styles are required for noUiSlider to function. * These styles are required for noUiSlider to function.
* You don't need to change these rules to apply your design. * You don't need to change these rules to apply your design.
*/ */
.noUi-target, .noUi-target,
.noUi-target * { .noUi-target * {
@@ -7154,8 +7154,8 @@ button.close {
cursor: inherit !important; cursor: inherit !important;
} }
/* Painting and performance; /* Painting and performance;
* Browsers can paint handles in their own layer. * Browsers can paint handles in their own layer.
*/ */
.noUi-base, .noUi-base,
.noUi-handle { .noUi-handle {
@@ -7163,7 +7163,7 @@ button.close {
transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0);
} }
/* Slider size and handle placement; /* Slider size and handle placement;
*/ */
.noUi-horizontal { .noUi-horizontal {
height: 1px; height: 1px;
@@ -7192,7 +7192,7 @@ button.close {
top: -17px; top: -17px;
} }
/* Styling; /* Styling;
*/ */
.noUi-target { .noUi-target {
background-color: rgba(182, 182, 182, 0.3); background-color: rgba(182, 182, 182, 0.3);
@@ -7206,7 +7206,7 @@ button.close {
transition: background 450ms; transition: background 450ms;
} }
/* Handles and cursors; /* Handles and cursors;
*/ */
.noUi-draggable { .noUi-draggable {
cursor: ew-resize; cursor: ew-resize;
@@ -7220,8 +7220,8 @@ button.close {
border-radius: 3px; border-radius: 3px;
background: #FFF; background: #FFF;
cursor: default; cursor: default;
-webkit-box-shadow: inset 0 0 1px #FFF, -webkit-box-shadow: inset 0 0 1px #FFF, inset 0 1px 7px #EBEBEB, 0 3px 6px -3px #BBB;
inset 0 1px 7px #EBEBEB, box-shadow: inset 0 0 1px #FFF, inset 0 1px 7px #EBEBEB, 0 3px 6px -3px #BBB;
-webkit-transition: 300ms ease 0s; -webkit-transition: 300ms ease 0s;
-moz-transition: 300ms ease 0s; -moz-transition: 300ms ease 0s;
-ms-transition: 300ms ease 0s; -ms-transition: 300ms ease 0s;
@@ -7234,7 +7234,7 @@ button.close {
transform: scale3d(1.5, 1.5, 1); transform: scale3d(1.5, 1.5, 1);
} }
-webkit-transform: scale3d(1.5, 1.5, 1); /* Disabled state;
*/ */
[disabled] .noUi-connect { [disabled] .noUi-connect {
background: #B8B8B8; background: #B8B8B8;
@@ -7246,8 +7246,8 @@ button.close {
cursor: not-allowed; cursor: not-allowed;
} }
[disabled] .noUi-handle { /* Base;
cursor: not-allowed; *
*/ */
.noUi-pips, .noUi-pips,
.noUi-pips * { .noUi-pips * {
@@ -7260,8 +7260,8 @@ button.close {
color: #999; color: #999;
} }
position: absolute; /* Values;
color: #999; *
*/ */
.noUi-value { .noUi-value {
position: absolute; position: absolute;
@@ -7273,8 +7273,8 @@ button.close {
font-size: 10px; font-size: 10px;
} }
color: #ccc; /* Markings;
font-size: 10px; *
*/ */
.noUi-marker { .noUi-marker {
position: absolute; position: absolute;
@@ -7289,8 +7289,8 @@ button.close {
background: #AAA; background: #AAA;
} }
.noUi-marker-large { /* Horizontal layout;
background: #AAA; *
*/ */
.noUi-pips-horizontal { .noUi-pips-horizontal {
padding: 10px 0; padding: 10px 0;
@@ -7319,8 +7319,8 @@ button.close {
height: 15px; height: 15px;
} }
.noUi-marker-horizontal.noUi-marker-large { /* Vertical layout;
height: 15px; *
*/ */
.noUi-pips-vertical { .noUi-pips-vertical {
padding: 0 10px; padding: 0 10px;
@@ -7446,10 +7446,10 @@ button.close {
background-color: #FF3636; background-color: #FF3636;
} }
.slider.slider-danger .noUi-handle { /*!
background-color: #FF3636; * Datepicker for Bootstrap v1.7.0-dev (https://github.com/uxsolutions/bootstrap-datepicker)
} *
* Licensed under the Apache License v2.0 (http://www.apache.org/licenses/LICENSE-2.0)
*/ */
.datepicker { .datepicker {
padding: 8px 6px; padding: 8px 6px;
@@ -8999,17 +8999,17 @@ fieldset[disabled]
background-color: #E3E3E3; background-color: #E3E3E3;
} }
.input-group[disabled] .input-group-addon { /*.input-group .form-control:first-child,
background-color: #E3E3E3; .input-group-addon:first-child,
} .input-group-btn:first-child > .dropdown-toggle,
.input-group-btn:last-child > .btn:not(:last-child):not(.dropdown-toggle) {
/*.input-group .form-control:first-child, border-right: 0 none;
.input-group-addon:first-child, }
.input-group-btn:first-child > .dropdown-toggle, .input-group .form-control:last-child,
.input-group-btn:last-child > .btn:not(:last-child):not(.dropdown-toggle) { .input-group-addon:last-child,
border-right: 0 none; .input-group-btn:last-child > .dropdown-toggle,
} .input-group-btn:first-child > .btn:not(:first-child) {
.input-group .form-control:last-child, border-left: 0 none;
}*/ }*/
.form-control[disabled], .form-control[readonly], fieldset[disabled] .form-control { .form-control[disabled], .form-control[readonly], fieldset[disabled] .form-control {
background-color: #E3E3E3; background-color: #E3E3E3;
@@ -10556,12 +10556,12 @@ img {
box-shadow: 0px 5px 25px 0px rgba(0, 0, 0, 0.2); box-shadow: 0px 5px 25px 0px rgba(0, 0, 0, 0.2);
} }
-webkit-box-shadow: 0px 5px 25px 0px rgba(0, 0, 0, 0.2); /* --------------------------------
box-shadow: 0px 5px 25px 0px rgba(0, 0, 0, 0.2);
} Nucleo Outline Web Font - nucleoapp.com/
License - nucleoapp.com/license/
/* -------------------------------- Created using IcoMoon - icomoon.io
-------------------------------- */ -------------------------------- */
@font-face { @font-face {
font-family: 'Nucleo Outline'; font-family: 'Nucleo Outline';
@@ -10571,8 +10571,8 @@ Created using IcoMoon - icomoon.io
font-style: normal; font-style: normal;
} }
font-weight: normal; /*------------------------
font-style: normal; base class definition
-------------------------*/ -------------------------*/
.now-ui-icons { .now-ui-icons {
display: inline-block; display: inline-block;
@@ -10585,11 +10585,11 @@ Created using IcoMoon - icomoon.io
-moz-osx-font-smoothing: grayscale; -moz-osx-font-smoothing: grayscale;
} }
-webkit-font-smoothing: antialiased; /*------------------------
-moz-osx-font-smoothing: grayscale; change icon size
-------------------------*/ -------------------------*/
/*----------------------------------
/*------------------------ add a square/circle background
-----------------------------------*/ -----------------------------------*/
.now-ui-icons.circle { .now-ui-icons.circle {
padding: 0.33333333em; padding: 0.33333333em;
@@ -10601,8 +10601,8 @@ Created using IcoMoon - icomoon.io
border-radius: 50%; border-radius: 50%;
} }
.now-ui-icons.circle { /*------------------------
border-radius: 50%; list icons
-------------------------*/ -------------------------*/
.nc-icon-ul { .nc-icon-ul {
padding-left: 0; padding-left: 0;
@@ -10626,8 +10626,8 @@ Created using IcoMoon - icomoon.io
left: -1.9047619em; left: -1.9047619em;
} }
top: -0.19047619em; /*------------------------
left: -1.9047619em; spinning icons
-------------------------*/ -------------------------*/
.now-ui-icons.spin { .now-ui-icons.spin {
-webkit-animation: nc-icon-spin 2s infinite linear; -webkit-animation: nc-icon-spin 2s infinite linear;
@@ -10654,11 +10654,11 @@ Created using IcoMoon - icomoon.io
} }
} }
transform: rotate(360deg); /*------------------------
} rotated/flipped icons
-------------------------*/ -------------------------*/
/*------------------------
/*------------------------ font icons
-------------------------*/ -------------------------*/
.now-ui-icons.ui-1_check:before { .now-ui-icons.ui-1_check:before {
content: "\EA22"; content: "\EA22";
@@ -12469,21 +12469,21 @@ Created using IcoMoon - icomoon.io
} }
} }
width: auto; /*.separator{
} content: "Separator";
} color: #FFFFFF;
display: block;
/*.separator{ width: 100%;
content: "Separator"; padding: 20px;
color: #FFFFFF; }
display: block; .separator-line{
width: 100%; background-color: #EEE;
padding: 20px; height: 1px;
} width: 100%;
.separator-line{ display: block;
background-color: #EEE; }
height: 1px; .separator.separator-gray{
width: 100%; background-color: #EEEEEE;
}*/ }*/
.social-buttons-demo .btn { .social-buttons-demo .btn {
margin-right: 5px; margin-right: 5px;

File diff suppressed because one or more lines are too long

View File

@@ -1,20 +1,20 @@
{ {
"/assets/frontend/js/app.js": "/assets/frontend/js/app.js?id=8f1a1bff7c8d0e2888db", "/assets/frontend/js/app.js": "/assets/frontend/js/app.js?id=a9c6b70866d562211ec7",
"/assets/frontend/css/now-ui-kit.css": "/assets/frontend/css/now-ui-kit.css?id=70c0f73b28bc686d7791", "/assets/frontend/css/now-ui-kit.css": "/assets/frontend/css/now-ui-kit.css?id=b0a0f05b94a4486db4f2",
"/assets/admin/css/vendor.min.css": "/assets/admin/css/vendor.min.css?id=42f138d32d03b309dec7", "/assets/admin/css/vendor.min.css": "/assets/admin/css/vendor.min.css?id=cc80aec3cf1646f83d8d",
"/assets/admin/js/app.js": "/assets/admin/js/app.js?id=e4a5d8869d23f708dd10", "/assets/admin/js/app.js": "/assets/admin/js/app.js?id=daa4de1b316b95d218ba",
"/assets/installer/js/app.js": "/assets/installer/js/app.js?id=27b9f2ce0b268e658f01", "/assets/installer/js/app.js": "/assets/installer/js/app.js?id=3a51850509367b06cd1f",
"/assets/fonts/glyphicons-halflings-regular.woff2": "/assets/fonts/glyphicons-halflings-regular.woff2?id=b5b5055c6d812c0f9f0d", "/assets/fonts/glyphicons-halflings-regular.woff2": "/assets/fonts/glyphicons-halflings-regular.woff2?id=b5b5055c6d812c0f9f0d",
"/assets/admin/fonts/glyphicons-halflings-regular.woff2": "/assets/admin/fonts/glyphicons-halflings-regular.woff2?id=b5b5055c6d812c0f9f0d", "/assets/admin/fonts/glyphicons-halflings-regular.woff2": "/assets/admin/fonts/glyphicons-halflings-regular.woff2?id=b5b5055c6d812c0f9f0d",
"/assets/admin/img/clear.png": "/assets/admin/img/clear.png?id=0e92f4c3efc6988a3c96", "/assets/admin/img/clear.png": "/assets/admin/img/clear.png?id=0e92f4c3efc6988a3c96",
"/assets/admin/img/loading.gif": "/assets/admin/img/loading.gif?id=90a4b76b4f11558691f6", "/assets/admin/img/loading.gif": "/assets/admin/img/loading.gif?id=90a4b76b4f11558691f6",
"/assets/global/js/jquery.js": "/assets/global/js/jquery.js?id=6a07da9fae934baf3f74", "/assets/global/js/jquery.js": "/assets/global/js/jquery.js?id=6a07da9fae934baf3f74",
"/assets/admin/css/vendor.css": "/assets/admin/css/vendor.css?id=f139af0f666d5cefde4d", "/assets/admin/css/vendor.css": "/assets/admin/css/vendor.css?id=99aedbd62dfa118e7b73",
"/assets/admin/js/vendor.js": "/assets/admin/js/vendor.js?id=5130233c88c71fc60135", "/assets/admin/js/vendor.js": "/assets/admin/js/vendor.js?id=5130233c88c71fc60135",
"/assets/admin/css/blue.png": "/assets/admin/css/blue.png?id=753a3c0dec86d3a38d9c", "/assets/admin/css/blue.png": "/assets/admin/css/blue.png?id=753a3c0dec86d3a38d9c",
"/assets/admin/css/blue@2x.png": "/assets/admin/css/blue@2x.png?id=97da23d47b838cbd4bef", "/assets/admin/css/blue@2x.png": "/assets/admin/css/blue@2x.png?id=97da23d47b838cbd4bef",
"/assets/global/js/vendor.js": "/assets/global/js/vendor.js?id=6436d215691e8f38eb12", "/assets/global/js/vendor.js": "/assets/global/js/vendor.js?id=6436d215691e8f38eb12",
"/assets/global/css/vendor.css": "/assets/global/css/vendor.css?id=115d5c4f2370ae94a962", "/assets/global/css/vendor.css": "/assets/global/css/vendor.css?id=115d5c4f2370ae94a962",
"/assets/installer/css/vendor.css": "/assets/installer/css/vendor.css?id=344796a10af1741dc754", "/assets/installer/css/vendor.css": "/assets/installer/css/vendor.css?id=cd76d2d9611b9a13d644",
"/assets/installer/js/vendor.js": "/assets/installer/js/vendor.js?id=01249af00bd2c1267e15" "/assets/installer/js/vendor.js": "/assets/installer/js/vendor.js?id=01249af00bd2c1267e15"
} }

View File

@@ -38,3 +38,5 @@ if (api_key) {
window.PHPVMS_USER_API_KEY = false; window.PHPVMS_USER_API_KEY = false;
console.error('API Key not found!') console.error('API Key not found!')
} }
require('./common');

View File

@@ -1,2 +1,56 @@
/**
*
*/
const rivets = require('rivets');
/**
* Generic formatter to prepend
* @param value
* @param prepend
* @returns {*}
*/
rivets.formatters.prepend = function (value, prepend) {
return prepend + value
};
/**
* Format minutes into HHh MMm
* @param value
* @returns {string}
*/
rivets.formatters.time_hm = function(value) {
const hours = Math.floor(value / 60);
const mins = value % 60;
return hours + 'h ' + mins + 'm';
};
/**
*
* @param value
* @param len
* @returns {boolean}
*/
rivets.formatters.gt = (value, len) => {
return value.length > len;
};
/**
*
* @param value
* @param len
* @returns {boolean}
*/
rivets.formatters.lt = (value, len) => {
return value.length < len;
};
/**
*
* @param value
* @param len
* @returns {boolean}
*/
rivets.formatters.eq = (value, len) => {
return value.length > len;
};

View File

@@ -1,4 +1,5 @@
const leaflet = require('leaflet'); const leaflet = require('leaflet');
const rivets = require('rivets');
import draw_base_map from './base_map' import draw_base_map from './base_map'
import {ACTUAL_ROUTE_COLOR} from './config' import {ACTUAL_ROUTE_COLOR} from './config'
@@ -33,6 +34,9 @@ export default (opts) => {
let layerSelFlightFeature = null; let layerSelFlightFeature = null;
let layerSelFlightLayer = null; let layerSelFlightLayer = null;
const r_map_view = rivets.bind($('#map-info-box'), {pirep: {}});
const r_table_view = rivets.bind($('#live_flights'), {pireps: []});
/** /**
* When a flight is clicked on, show the path, etc for that flight * When a flight is clicked on, show the path, etc for that flight
* @param feature * @param feature
@@ -41,7 +45,6 @@ export default (opts) => {
const onFlightClick = (feature, layer) => { const onFlightClick = (feature, layer) => {
const pirep_uri = opts.pirep_uri.replace('{id}', feature.properties.pirep_id); const pirep_uri = opts.pirep_uri.replace('{id}', feature.properties.pirep_id);
const link_uri = opts.pirep_link_uri.replace('{id}', feature.properties.pirep_id);
const geojson_uri = opts.pirep_uri.replace('{id}', feature.properties.pirep_id) + "/acars/geojson"; const geojson_uri = opts.pirep_uri.replace('{id}', feature.properties.pirep_id) + "/acars/geojson";
const pirep_info = $.ajax({ const pirep_info = $.ajax({
@@ -83,49 +86,9 @@ export default (opts) => {
// //
// When the PIREP info is done loading, show the bottom bar // When the PIREP info is done loading, show the bottom bar
// //
$.when(pirep_info).done(pirep => { pirep = pirep.data; $.when(pirep_info).done(pirep => {
r_map_view.update({pirep:pirep.data});
let dist, planned_dist; $('#map-info-box').show();
if(opts.units === 'nmi') {
dist = pirep.distance.nmi;
planned_dist = pirep.planned_distance.nmi;
} else if(opts.units === 'mi') {
dist = pirep.distance.mi;
planned_dist = pirep.planned_distance.mi;
} else if(opts.units === 'km') {
dist = pirep.distance.km;
planned_dist = pirep.planned_distance.km;
}
// Parse flight time
const hours = Math.floor(pirep.flight_time / 60);
const mins = pirep.flight_time % 60;
$('#map_flight_id').html(
'<a href="' + link_uri + '" target="_blank">' +
pirep.airline.icao + pirep.flight_number +
'</a>'
);
$('#map_flight_info').text(
pirep.dpt_airport.name + ' (' + pirep.dpt_airport.icao + ') to ' +
pirep.arr_airport.name + ' (' + pirep.arr_airport.icao + ')'
);
$('#map_flight_stats_middle').html(
'Status: <strong>' + pirep.status_text + '</strong><br />' +
'Flight Time: <strong>' + hours + 'h ' + mins + 'm</strong><br />' +
'Distance: <strong>' + dist + '</strong> / ' + planned_dist + opts.units + '<br />'
);
// Show flight stat info
$('#map_flight_stats_right').html(
'Ground Speed: <strong>' + pirep.position.gs + '</strong><br />' +
'Altitude: <strong>' + pirep.position.altitude + '</strong><br />' +
'Heading: <strong>' + pirep.position.heading + '</strong>'
);
$('#map-info-bar').show();
}); });
}; };
@@ -136,6 +99,12 @@ export default (opts) => {
/** /**
* AJAX UPDATE * AJAX UPDATE
*/ */
const pirep_uri = opts.pirep_uri.replace('{id}', '');
let pireps = $.ajax({
url: pirep_uri,
dataType: 'json',
error: console.log
});
let flights = $.ajax({ let flights = $.ajax({
url: opts.update_uri, url: opts.update_uri,
@@ -143,7 +112,7 @@ export default (opts) => {
error: console.log error: console.log
}); });
$.when(flights).done(function (flightGeoJson) { $.when(flights).done(flightGeoJson => {
if (layerFlights !== null) { if (layerFlights !== null) {
layerFlights.clearLayers() layerFlights.clearLayers()
@@ -178,7 +147,14 @@ export default (opts) => {
if (layerSelFlight !== null) { if (layerSelFlight !== null) {
onFlightClick(layerSelFlightFeature, layerSelFlightLayer) onFlightClick(layerSelFlightFeature, layerSelFlightLayer)
} }
}) });
$.when(pireps).done(pireps => {
r_table_view.update({
pireps: pireps.data,
has_data: (pireps.data.length > 0),
});
});
}; };
updateMap(); updateMap();

View File

@@ -79,6 +79,8 @@
{{-- Start of the required tags block. Don't remove these or things will break!! --}} {{-- Start of the required tags block. Don't remove these or things will break!! --}}
<script src="{{ public_asset('/assets/global/js/vendor.js') }}"></script> <script src="{{ public_asset('/assets/global/js/vendor.js') }}"></script>
<script src="{{ public_asset('/assets/frontend/js/app.js') }}"></script> <script src="{{ public_asset('/assets/frontend/js/app.js') }}"></script>
{{--<script src="bower_components/sightglass/index.js"></script>
<script src="bower_components/rivets/dist/rivets.min.js"></script>--}}
@yield('scripts') @yield('scripts')
{{-- End the required tags block --}} {{-- End the required tags block --}}

View File

@@ -18,8 +18,8 @@
If you change it, remember to change it in the in-array line as well If you change it, remember to change it in the in-array line as well
--}} --}}
<button class="btn btn-round btn-icon btn-icon-mini <button class="btn btn-round btn-icon btn-icon-mini
{{ in_array($flight->id, $saved, true) ? 'btn-info':'' }} {{ in_array($flight->id, $saved, true) ? 'btn-info':'' }}
save_flight" save_flight"
x-id="{{ $flight->id }}" x-id="{{ $flight->id }}"
x-saved-class="btn-info" x-saved-class="btn-info"
type="button" type="button"

View File

@@ -2,28 +2,62 @@
<div class="col-md-12"> <div class="col-md-12">
<div class="box-body"> <div class="box-body">
{{--
This map uses rivets.js to fill in the updates from the livemap
So the single brackets are used by rivets to fill in the values
And then the rv-* attributes are data-binds that will automatically
update whenever the base model behind it updates:
http://rivetsjs.com/docs/guide
Look in resources/js/maps/live_map.js to see where the actual binding
and update() call is made
--}}
<div id="map" style="width: {{ $config['width'] }}; height: {{ $config['height'] }}"> <div id="map" style="width: {{ $config['width'] }}; height: {{ $config['height'] }}">
<div id="map-info-bar"
style="display: none; {{--
position: absolute; This is the bottom bar that appears when you click on a flight in the map.
bottom: 0; You can show any data you want - use a JS debugger to see the value of "pirep",
padding: 20px; or look up the API documentation for the /api/pirep/{id}/acars call
height: 100px;
z-index: 9999; It's basically any of the fields from the database and pirep.position.X is any
background-color:rgba(232, 232, 232, 0.9); column from the ACARS table - holds the latest position.
width: {{ $config['width'] }};">
<div style="float: left; margin-right: 30px; width: 50%;"> Again, this is updated automatically via the rivets.js bindings, so be mindful
<h3 style="margin: 0" id="map_flight_id"></h3> when you're editing the { } - single brackets == rivets, double brackets == laravel
<p id="map_flight_info"></p>
A couple of places (like the distance) use both to output the correct bindings.
--}}
<div id="map-info-box" class="map-info-box"
style="width: {{ $config['width'] }};">
<div style="float: left; width: 50%;">
<h3 style="margin: 0" id="map_flight_id">
<a rv-href="pirep.id | prepend '{{url('/pireps/')}}/'" target="_blank">
{ pirep.airline.icao }{ pirep.flight_number }
</a>
</h3>
<p id="map_flight_info">
{ pirep.dpt_airport.name } ({ pirep.dpt_airport.icao }) to
{ pirep.arr_airport.name } ({ pirep.arr_airport.icao })
</p>
</div> </div>
<div style="float: left; margin-right: 30px;"> <div style="float: right; margin-left: 30px; margin-right: 30px;">
<p id="map_flight_stats_middle"></p> <p id="map_flight_stats_right">
Ground Speed: <span style="font-weight: bold">{ pirep.position.gs }</span><br/>
Altitude: <span style="font-weight: bold">{ pirep.position.altitude }</span><br/>
Heading: <span style="font-weight: bold">{ pirep.position.heading }</span><br/>
</p>
</div> </div>
<div style="float: left;"> <div style="float: right; margin-left: 30px;">
<p id="map_flight_stats_right"></p> <p id="map_flight_stats_middle">
Status: <span style="font-weight: bold">{ pirep.status_text }</span><br />
Flight Time: <span style="font-weight: bold">{ pirep.flight_time | time_hm }</span><br />
Distance: <span style="font-weight: bold">{ pirep.position.distance.{{setting('units.distance')}} }</span>
/ <span style="font-weight: bold">
{ pirep.planned_distance.{{setting('units.distance')}} }</span>
</p>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
@@ -31,26 +65,47 @@
<div class="clearfix" style="padding-top: 25px"></div> <div class="clearfix" style="padding-top: 25px"></div>
{{--<div id="flights_table" class="row"> {{--
This table is also handled/rendered by rivets from the livemap
Handles the updates by automatically updating the data in the row.
Same note applies from above about the data from the PIREP API being available
and being mindful of the rivets bindings
--}}
<div id="live_flights" class="row">
<div class="col-md-12"> <div class="col-md-12">
@if(!filled($pireps)) <div rv-hide="has_data" class="jumbotron text-center">There are no flights</div>
<div class="jumbotron text-center">There are no flights</div> <table rv-show="has_data" id="live_flights_table" class="table table-striped">
@endif <thead>
<table class="table"> <tr class="text-small header">
@foreach($pireps as $pirep) <td class="text-small">Flight</td>
<tr> <td class="text-small">Departure</td>
<td>{{ $pirep->airline->code }}{{ $pirep->ident }}</td> <td class="text-small">Arrival</td>
<td>{{ $pirep->dpt_airport_id }}</td> <td class="text-small">Aircraft</td>
<td>{{ $pirep->arr_airport_id }}</td> <td class="text-small">Altitude</td>
<td>{{ $pirep->aircraft->name }}</td> <td class="text-small">GS</td>
<td> <td class="text-small">Distance</td>
{{ PirepStatus::label($pirep->status) }} <td class="text-small">Status</td>
</td>
</tr> </tr>
@endforeach </thead>
<tbody>
<tr rv-each-pirep="pireps">
<td>{ pirep.airline.code }{ pirep.ident}</td>
{{-- Show the full airport name on hover --}}
<td><span rv-title="pirep.dpt_airport.name">{ pirep.dpt_airport.icao }</span></td>
<td><span rv-title="pirep.arr_airport.name">{ pirep.arr_airport.icao }</span></td>
<td>{ pirep.aircraft.name }</td>
<td>{ pirep.position.altitude }</td>
<td>{ pirep.position.gs }</td>
<td>{ pirep.position.distance.{{setting('units.distance')}} } /
{ pirep.planned_distance.{{setting('units.distance')}} }
</td>
<td>{ pirep.status_text }</td>
</tr>
</tbody>
</table> </table>
</div> </div>
</div>--}} </div>
@section('scripts') @section('scripts')
<script> <script>