mirror of
https://github.com/henrywhitaker3/Speedtest-Tracker.git
synced 2025-12-21 21:33:08 +01:00
@@ -1,6 +1,6 @@
|
|||||||
# Speedtest Tracker
|
# Speedtest Tracker
|
||||||
|
|
||||||
[](https://hub.docker.com/r/henrywhitaker3/speedtest-tracker) [](https://github.com/henrywhitaker3/Speedtest-Tracker/commits) [](https://github.com/henrywhitaker3/Speedtest-Tracker/issues) [](https://github.com/henrywhitaker3/Speedtest-Tracker/commits)  [](https://github.com/henrywhitaker3/Speedtest-Tracker/blob/master/LICENSE)
|
[](https://hub.docker.com/r/henrywhitaker3/speedtest-tracker) [](https://github.com/henrywhitaker3/Speedtest-Tracker/commits) [](https://github.com/henrywhitaker3/Speedtest-Tracker/issues) [](https://github.com/henrywhitaker3/Speedtest-Tracker/commits)  [](https://github.com/henrywhitaker3/Speedtest-Tracker/blob/master/LICENSE)
|
||||||
|
|
||||||
This program runs a speedtest check every hour and graphs the results. The back-end is written in [Laravel](https://laravel.com/) and the front-end uses [React](https://reactjs.org/). It uses the [Ookla's speedtest cli](https://www.speedtest.net/apps/cli) package to get the data and uses [Chart.js](https://www.chartjs.org/) to plot the results.
|
This program runs a speedtest check every hour and graphs the results. The back-end is written in [Laravel](https://laravel.com/) and the front-end uses [React](https://reactjs.org/). It uses the [Ookla's speedtest cli](https://www.speedtest.net/apps/cli) package to get the data and uses [Chart.js](https://www.chartjs.org/) to plot the results.
|
||||||
|
|
||||||
|
|||||||
36
app/Events/SpeedtestFailedEvent.php
Normal file
36
app/Events/SpeedtestFailedEvent.php
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Events;
|
||||||
|
|
||||||
|
use Illuminate\Broadcasting\Channel;
|
||||||
|
use Illuminate\Broadcasting\InteractsWithSockets;
|
||||||
|
use Illuminate\Broadcasting\PresenceChannel;
|
||||||
|
use Illuminate\Broadcasting\PrivateChannel;
|
||||||
|
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
|
||||||
|
use Illuminate\Foundation\Events\Dispatchable;
|
||||||
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
|
||||||
|
class SpeedtestFailedEvent
|
||||||
|
{
|
||||||
|
use Dispatchable, InteractsWithSockets, SerializesModels;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new event instance.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the channels the event should broadcast on.
|
||||||
|
*
|
||||||
|
* @return \Illuminate\Broadcasting\Channel|array
|
||||||
|
*/
|
||||||
|
public function broadcastOn()
|
||||||
|
{
|
||||||
|
return new PrivateChannel('channel-name');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -27,7 +27,7 @@ class SpeedtestHelper {
|
|||||||
$output = json_decode($output, true, 512, JSON_THROW_ON_ERROR);
|
$output = json_decode($output, true, 512, JSON_THROW_ON_ERROR);
|
||||||
|
|
||||||
if(!SpeedtestHelper::checkOutputIsComplete($output)) {
|
if(!SpeedtestHelper::checkOutputIsComplete($output)) {
|
||||||
return false;
|
$test = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$test = Speedtest::create([
|
$test = Speedtest::create([
|
||||||
@@ -43,11 +43,27 @@ class SpeedtestHelper {
|
|||||||
} catch(JsonException $e) {
|
} catch(JsonException $e) {
|
||||||
Log::error('Failed to parse speedtest JSON');
|
Log::error('Failed to parse speedtest JSON');
|
||||||
Log::error($output);
|
Log::error($output);
|
||||||
|
$test = false;
|
||||||
} catch(Exception $e) {
|
} catch(Exception $e) {
|
||||||
Log::error($e->getMessage());
|
Log::error($e->getMessage());
|
||||||
|
$test = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (isset($test)) ? $test : false;
|
if(!$test) {
|
||||||
|
Speedtest::create([
|
||||||
|
'ping' => 0,
|
||||||
|
'upload' => 0,
|
||||||
|
'download' => 0,
|
||||||
|
'failed' => true,
|
||||||
|
'scheduled' => $scheduled,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!isset($test) || $test == false) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $test;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -83,6 +99,7 @@ class SpeedtestHelper {
|
|||||||
$t = Carbon::now()->subDay();
|
$t = Carbon::now()->subDay();
|
||||||
$s = Speedtest::select(DB::raw('AVG(ping) as ping, AVG(download) as download, AVG(upload) as upload'))
|
$s = Speedtest::select(DB::raw('AVG(ping) as ping, AVG(download) as download, AVG(upload) as upload'))
|
||||||
->where('created_at', '>=', $t)
|
->where('created_at', '>=', $t)
|
||||||
|
->where('failed', false)
|
||||||
->first()
|
->first()
|
||||||
->toArray();
|
->toArray();
|
||||||
|
|
||||||
|
|||||||
@@ -3,12 +3,14 @@
|
|||||||
namespace App\Jobs;
|
namespace App\Jobs;
|
||||||
|
|
||||||
use App\Events\SpeedtestCompleteEvent;
|
use App\Events\SpeedtestCompleteEvent;
|
||||||
|
use App\Events\SpeedtestFailedEvent;
|
||||||
use App\Helpers\SpeedtestHelper;
|
use App\Helpers\SpeedtestHelper;
|
||||||
use Illuminate\Bus\Queueable;
|
use Illuminate\Bus\Queueable;
|
||||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
use Illuminate\Foundation\Bus\Dispatchable;
|
use Illuminate\Foundation\Bus\Dispatchable;
|
||||||
use Illuminate\Queue\InteractsWithQueue;
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
use Illuminate\Queue\SerializesModels;
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
class SpeedtestJob implements ShouldQueue
|
class SpeedtestJob implements ShouldQueue
|
||||||
{
|
{
|
||||||
@@ -35,7 +37,13 @@ class SpeedtestJob implements ShouldQueue
|
|||||||
{
|
{
|
||||||
$output = SpeedtestHelper::output();
|
$output = SpeedtestHelper::output();
|
||||||
$speedtest = SpeedtestHelper::runSpeedtest($output, $this->scheduled);
|
$speedtest = SpeedtestHelper::runSpeedtest($output, $this->scheduled);
|
||||||
event(new SpeedtestCompleteEvent($speedtest));
|
Log::info($speedtest);
|
||||||
|
if($speedtest == false) {
|
||||||
|
Log::info('speedtest == false');
|
||||||
|
event(new SpeedtestFailedEvent());
|
||||||
|
} else {
|
||||||
|
event(new SpeedtestCompleteEvent($speedtest));
|
||||||
|
}
|
||||||
return $speedtest;
|
return $speedtest;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
54
app/Listeners/SpeedtestFailedListener.php
Normal file
54
app/Listeners/SpeedtestFailedListener.php
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Listeners;
|
||||||
|
|
||||||
|
use App\Helpers\SettingsHelper;
|
||||||
|
use App\Notifications\SpeedtestFailedSlack;
|
||||||
|
use App\Notifications\SpeedtestFailedTelegram;
|
||||||
|
use Exception;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
use Illuminate\Support\Facades\Notification;
|
||||||
|
|
||||||
|
class SpeedtestFailedListener
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Create the event listener.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle the event.
|
||||||
|
*
|
||||||
|
* @param object $event
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function handle($event)
|
||||||
|
{
|
||||||
|
if(env('SLACK_WEBHOOK')) {
|
||||||
|
try {
|
||||||
|
Notification::route('slack', env('SLACK_WEBHOOK'))
|
||||||
|
->notify(new SpeedtestFailedSlack());
|
||||||
|
} catch(Exception $e) {
|
||||||
|
Log::notice('Your sleck webhook is invalid');
|
||||||
|
Log::notice($e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(env('TELEGRAM_BOT_TOKEN') && env('TELEGRAM_CHAT_ID')) {
|
||||||
|
try {
|
||||||
|
Notification::route(TelegramChannel::class, env('TELEGRAM_CHAT_ID'))
|
||||||
|
->notify(new SpeedtestFailedTelegram());
|
||||||
|
} catch(Exception $e) {
|
||||||
|
Log::notice('Your telegram settings are invalid');
|
||||||
|
Log::notice($e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
53
app/Notifications/SpeedtestFailedSlack.php
Normal file
53
app/Notifications/SpeedtestFailedSlack.php
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Notifications;
|
||||||
|
|
||||||
|
use Illuminate\Bus\Queueable;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
|
use Illuminate\Notifications\Messages\MailMessage;
|
||||||
|
use Illuminate\Notifications\Messages\SlackMessage;
|
||||||
|
use Illuminate\Notifications\Notification;
|
||||||
|
|
||||||
|
class SpeedtestFailedSlack extends Notification implements ShouldQueue
|
||||||
|
{
|
||||||
|
use Queueable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new notification instance.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the notification's delivery channels.
|
||||||
|
*
|
||||||
|
* @param mixed $notifiable
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function via($notifiable)
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'slack',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Format slack notification
|
||||||
|
*
|
||||||
|
* @param mixed $notifiable
|
||||||
|
* @return SlackMessage
|
||||||
|
*/
|
||||||
|
public function toSlack($notifiable)
|
||||||
|
{
|
||||||
|
return (new SlackMessage)
|
||||||
|
->error()
|
||||||
|
->attachment(function ($attachment) {
|
||||||
|
$attachment->title('Failed speedtest')
|
||||||
|
->content('Something went wrong running your speedtest');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
47
app/Notifications/SpeedtestFailedTelegram.php
Normal file
47
app/Notifications/SpeedtestFailedTelegram.php
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Notifications;
|
||||||
|
|
||||||
|
use Illuminate\Bus\Queueable;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
|
use Illuminate\Notifications\Messages\MailMessage;
|
||||||
|
use Illuminate\Notifications\Notification;
|
||||||
|
use NotificationChannels\Telegram\TelegramChannel;
|
||||||
|
use NotificationChannels\Telegram\TelegramMessage;
|
||||||
|
|
||||||
|
class SpeedtestFailedTelegram extends Notification implements ShouldQueue
|
||||||
|
{
|
||||||
|
use Queueable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new notification instance.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
public function via($notifiable)
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
TelegramChannel::class
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Format tekegram notification
|
||||||
|
*
|
||||||
|
* @param mixed $notifiable
|
||||||
|
* @return TelegramMessage
|
||||||
|
*/
|
||||||
|
public function toTelegram($notifiable)
|
||||||
|
{
|
||||||
|
$msg = "Error: something went wrong running your speedtest";
|
||||||
|
return TelegramMessage::create()
|
||||||
|
->to(env('TELEGRAM_CHAT_ID'))
|
||||||
|
->content($msg)
|
||||||
|
->options(['parse_mode' => 'Markdown']);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,8 +3,10 @@
|
|||||||
namespace App\Providers;
|
namespace App\Providers;
|
||||||
|
|
||||||
use App\Events\SpeedtestCompleteEvent;
|
use App\Events\SpeedtestCompleteEvent;
|
||||||
|
use App\Events\SpeedtestFailedEvent;
|
||||||
use App\Events\SpeedtestOverviewEvent;
|
use App\Events\SpeedtestOverviewEvent;
|
||||||
use App\Listeners\SpeedtestCompleteListener;
|
use App\Listeners\SpeedtestCompleteListener;
|
||||||
|
use App\Listeners\SpeedtestFailedListener;
|
||||||
use App\Listeners\SpeedtestOverviewListener;
|
use App\Listeners\SpeedtestOverviewListener;
|
||||||
use Illuminate\Auth\Events\Registered;
|
use Illuminate\Auth\Events\Registered;
|
||||||
use Illuminate\Auth\Listeners\SendEmailVerificationNotification;
|
use Illuminate\Auth\Listeners\SendEmailVerificationNotification;
|
||||||
@@ -28,6 +30,9 @@ class EventServiceProvider extends ServiceProvider
|
|||||||
SpeedtestOverviewEvent::class => [
|
SpeedtestOverviewEvent::class => [
|
||||||
SpeedtestOverviewListener::class
|
SpeedtestOverviewListener::class
|
||||||
],
|
],
|
||||||
|
SpeedtestFailedEvent::class => [
|
||||||
|
SpeedtestFailedListener::class
|
||||||
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ class Speedtest extends Model
|
|||||||
'server_host',
|
'server_host',
|
||||||
'url',
|
'url',
|
||||||
'scheduled',
|
'scheduled',
|
||||||
|
'failed',
|
||||||
];
|
];
|
||||||
|
|
||||||
protected $table = 'speedtests';
|
protected $table = 'speedtests';
|
||||||
|
|||||||
@@ -1,4 +1,14 @@
|
|||||||
{
|
{
|
||||||
|
"1.7.3": [
|
||||||
|
{
|
||||||
|
"description": "Updated dependencies",
|
||||||
|
"link": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Added notifications and logging of failed tests",
|
||||||
|
"link": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
"1.7.2": [
|
"1.7.2": [
|
||||||
{
|
{
|
||||||
"description": "Updated UI for speedtest info",
|
"description": "Updated UI for speedtest info",
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ return [
|
|||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'version' => '1.7.2',
|
'version' => '1.7.3',
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
class UpdateSpeedtestAddFailedColumn extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
Schema::table('speedtests', function($table) {
|
||||||
|
$table->boolean('failed')->default(false);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::table('speedtests', function($table) {
|
||||||
|
$table->dropColumn('failed');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
2
public/js/app.js
vendored
2
public/js/app.js
vendored
File diff suppressed because one or more lines are too long
@@ -112,6 +112,7 @@ export default class LatestResults extends Component {
|
|||||||
value={parseFloat(data.data.ping).toFixed(1)}
|
value={parseFloat(data.data.ping).toFixed(1)}
|
||||||
avg={parseFloat(data.average.ping).toFixed(1)}
|
avg={parseFloat(data.average.ping).toFixed(1)}
|
||||||
max={parseFloat(data.max.ping).toFixed(1)}
|
max={parseFloat(data.max.ping).toFixed(1)}
|
||||||
|
failed={data.data.failed}
|
||||||
unit="ms"
|
unit="ms"
|
||||||
icon="ping"
|
icon="ping"
|
||||||
/>
|
/>
|
||||||
@@ -127,6 +128,7 @@ export default class LatestResults extends Component {
|
|||||||
value={parseFloat(data.data.download).toFixed(1)}
|
value={parseFloat(data.data.download).toFixed(1)}
|
||||||
avg={parseFloat(data.average.download).toFixed(1)}
|
avg={parseFloat(data.average.download).toFixed(1)}
|
||||||
max={parseFloat(data.max.download).toFixed(1)}
|
max={parseFloat(data.max.download).toFixed(1)}
|
||||||
|
failed={data.data.failed}
|
||||||
unit="Mbit/s"
|
unit="Mbit/s"
|
||||||
icon="dl"
|
icon="dl"
|
||||||
/>
|
/>
|
||||||
@@ -142,6 +144,7 @@ export default class LatestResults extends Component {
|
|||||||
value={parseFloat(data.data.upload).toFixed(1)}
|
value={parseFloat(data.data.upload).toFixed(1)}
|
||||||
avg={parseFloat(data.average.upload).toFixed(1)}
|
avg={parseFloat(data.average.upload).toFixed(1)}
|
||||||
max={parseFloat(data.max.upload).toFixed(1)}
|
max={parseFloat(data.max.upload).toFixed(1)}
|
||||||
|
failed={data.data.failed}
|
||||||
unit="Mbit/s"
|
unit="Mbit/s"
|
||||||
icon="ul"
|
icon="ul"
|
||||||
/>
|
/>
|
||||||
|
|||||||
71
resources/js/components/Graphics/TableRow.js
vendored
71
resources/js/components/Graphics/TableRow.js
vendored
@@ -29,36 +29,49 @@ export default class TableRow extends Component {
|
|||||||
var e = this.state.data;
|
var e = this.state.data;
|
||||||
var show = this.state.show;
|
var show = this.state.show;
|
||||||
|
|
||||||
return (
|
if(e.failed != true) {
|
||||||
<tr>
|
return (
|
||||||
<td>{e.id}</td>
|
<tr>
|
||||||
<td>{new Date(e.created_at).toLocaleString()}</td>
|
<td>{e.id}</td>
|
||||||
<td>{e.download}</td>
|
<td>{new Date(e.created_at).toLocaleString()}</td>
|
||||||
<td>{e.upload}</td>
|
<td>{e.download}</td>
|
||||||
<td>{e.ping}</td>
|
<td>{e.upload}</td>
|
||||||
{e.server_host != null ?
|
<td>{e.ping}</td>
|
||||||
<td>
|
{e.server_host != null ?
|
||||||
<span onClick={this.toggleShow} className="ti-arrow-top-right mouse"></span>
|
<td>
|
||||||
<Modal show={show} onHide={this.toggleShow}>
|
<span onClick={this.toggleShow} className="ti-arrow-top-right mouse"></span>
|
||||||
<Modal.Header>
|
<Modal show={show} onHide={this.toggleShow}>
|
||||||
<Modal.Title>More info</Modal.Title>
|
<Modal.Header>
|
||||||
</Modal.Header>
|
<Modal.Title>More info</Modal.Title>
|
||||||
<Modal.Body className="text-center">
|
</Modal.Header>
|
||||||
<p>Server ID: {e.server_id}</p>
|
<Modal.Body className="text-center">
|
||||||
<p>Name: {e.server_name}</p>
|
<p>Server ID: {e.server_id}</p>
|
||||||
<p>Host: {e.server_host}</p>
|
<p>Name: {e.server_name}</p>
|
||||||
<p>URL: <a href={e.url} target="_blank" rel="noopener noreferer">Speedtest.net</a></p>
|
<p>Host: {e.server_host}</p>
|
||||||
{e.scheduled != undefined &&
|
<p>URL: <a href={e.url} target="_blank" rel="noopener noreferer">Speedtest.net</a></p>
|
||||||
<p>Type: {e.scheduled == true ? 'scheduled' : 'manual'}</p>
|
{e.scheduled != undefined &&
|
||||||
}
|
<p>Type: {e.scheduled == true ? 'scheduled' : 'manual'}</p>
|
||||||
</Modal.Body>
|
}
|
||||||
</Modal>
|
</Modal.Body>
|
||||||
</td>
|
</Modal>
|
||||||
:
|
</td>
|
||||||
|
:
|
||||||
|
<td></td>
|
||||||
|
}
|
||||||
|
</tr>
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return (
|
||||||
|
<tr>
|
||||||
|
<td>{e.id}</td>
|
||||||
|
<td>{new Date(e.created_at).toLocaleString()}</td>
|
||||||
|
<td><span className="ti-close text-danger"></span></td>
|
||||||
|
<td><span className="ti-close text-danger"></span></td>
|
||||||
|
<td><span className="ti-close text-danger"></span></td>
|
||||||
<td></td>
|
<td></td>
|
||||||
}
|
</tr>
|
||||||
</tr>
|
);
|
||||||
);
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
6
resources/js/components/Graphics/Widget.js
vendored
6
resources/js/components/Graphics/Widget.js
vendored
@@ -12,7 +12,8 @@ export default class Widget extends Component {
|
|||||||
unit: this.props.unit,
|
unit: this.props.unit,
|
||||||
icon: this.props.icon,
|
icon: this.props.icon,
|
||||||
avg: this.props.avg,
|
avg: this.props.avg,
|
||||||
max: this.props.max
|
max: this.props.max,
|
||||||
|
failed: this.props.failed,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -36,6 +37,7 @@ export default class Widget extends Component {
|
|||||||
var icon = this.state.icon;
|
var icon = this.state.icon;
|
||||||
var max = this.state.max;
|
var max = this.state.max;
|
||||||
var avg = this.state.avg;
|
var avg = this.state.avg;
|
||||||
|
var failed = Boolean(Number(this.state.failed));
|
||||||
|
|
||||||
switch(icon) {
|
switch(icon) {
|
||||||
case 'ping':
|
case 'ping':
|
||||||
@@ -60,7 +62,7 @@ export default class Widget extends Component {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="text-truncate">
|
<div className="text-truncate">
|
||||||
<h3 className="d-inline">{value}</h3>
|
<h3 className="d-inline">{(!failed) ? value : <span className="ti-close text-danger"></span> }</h3>
|
||||||
<p className="d-inline ml-2">{unit} (current)</p>
|
<p className="d-inline ml-2">{unit} (current)</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="text-muted text-truncate">
|
<div className="text-muted text-truncate">
|
||||||
|
|||||||
Reference in New Issue
Block a user