From c1fcf77deae2dd93f5b55724a7ebf17f55f7e50d Mon Sep 17 00:00:00 2001 From: svenvg93 Date: Mon, 5 Aug 2024 23:01:12 +0200 Subject: [PATCH 01/15] first commit --- app/Filament/Widgets/StatsOverviewWidget.php | 64 ++++++++++++++++---- 1 file changed, 53 insertions(+), 11 deletions(-) diff --git a/app/Filament/Widgets/StatsOverviewWidget.php b/app/Filament/Widgets/StatsOverviewWidget.php index 6a7721147..52936e65d 100644 --- a/app/Filament/Widgets/StatsOverviewWidget.php +++ b/app/Filament/Widgets/StatsOverviewWidget.php @@ -5,6 +5,7 @@ use App\Enums\ResultStatus; use App\Helpers\Number; use App\Models\Result; +use Carbon\Carbon; use Filament\Widgets\StatsOverviewWidget as BaseWidget; use Filament\Widgets\StatsOverviewWidget\Stat; @@ -43,21 +44,40 @@ protected function getCards(): array ->latest() ->first(); - if (! $previous) { - return [ - Stat::make('Latest download', fn (): string => ! blank($this->result) ? Number::toBitRate(bits: $this->result->download_bits, precision: 2) : 'n/a') - ->icon('heroicon-o-arrow-down-tray'), - Stat::make('Latest upload', fn (): string => ! blank($this->result) ? Number::toBitRate(bits: $this->result->upload_bits, precision: 2) : 'n/a') - ->icon('heroicon-o-arrow-up-tray'), - Stat::make('Latest ping', fn (): string => ! blank($this->result) ? number_format($this->result->ping, 2).' ms' : 'n/a') - ->icon('heroicon-o-clock'), - ]; - } - $downloadChange = percentChange($this->result->download, $previous->download, 2); $uploadChange = percentChange($this->result->upload, $previous->upload, 2); $pingChange = percentChange($this->result->ping, $previous->ping, 2); + $last24hData = Result::query() + ->select(['download', 'upload', 'ping']) + ->where('status', '=', ResultStatus::Completed) + ->where('created_at', '>=', Carbon::now()->subDay()) + ->get(); + + $averageDownload24h = $last24hData->avg('download'); + $averageUpload24h = $last24hData->avg('upload'); + $averagePing24h = $last24hData->avg('ping'); + + $last7dData = Result::query() + ->select(['download', 'upload', 'ping']) + ->where('status', '=', ResultStatus::Completed) + ->where('created_at', '>=', Carbon::now()->subWeek()) + ->get(); + + $averageDownload7d = $last7dData->avg('download'); + $averageUpload7d = $last7dData->avg('upload'); + $averagePing7d = $last7dData->avg('ping'); + + $last1mData = Result::query() + ->select(['download', 'upload', 'ping']) + ->where('status', '=', ResultStatus::Completed) + ->where('created_at', '>=', Carbon::now()->subMonth()) + ->get(); + + $averageDownload1m = $last1mData->avg('download'); + $averageUpload1m = $last1mData->avg('upload'); + $averagePing1m = $last1mData->avg('ping'); + return [ Stat::make('Latest download', fn (): string => ! blank($this->result) ? Number::toBitRate(bits: $this->result->download_bits, precision: 2) : 'n/a') ->icon('heroicon-o-arrow-down-tray') @@ -74,6 +94,28 @@ protected function getCards(): array ->description($pingChange > 0 ? $pingChange.'% slower' : abs($pingChange).'% faster') ->descriptionIcon($pingChange > 0 ? 'heroicon-m-arrow-trending-up' : 'heroicon-m-arrow-trending-down') ->color($pingChange > 0 ? 'danger' : 'success'), + + Stat::make('Average Download', '') + ->icon('heroicon-o-arrow-down-tray') + ->description( + '24 Hours: '.(blank($averageDownload24h) ? 'n/a' : Number::toBitRate(bits: $averageDownload24h * 8, precision: 2))."\n". + '7 Days: '.(blank($averageDownload7d) ? 'n/a' : Number::toBitRate(bits: $averageDownload7d * 8, precision: 2))."\n". + '1 Month: '.(blank($averageDownload1m) ? 'n/a' : Number::toBitRate(bits: $averageDownload1m * 8, precision: 2)) + ), + Stat::make('Average Upload', '') + ->icon('heroicon-o-arrow-down-tray') + ->description( + '24 Hours: '.(blank($averageUpload24h) ? 'n/a' : Number::toBitRate(bits: $averageUpload24h * 8, precision: 2))."\n". + '7 Days: '.(blank($averageUpload7d) ? 'n/a' : Number::toBitRate(bits: $averageUpload7d * 8, precision: 2))."\n". + '1 Month: '.(blank($averageUpload1m) ? 'n/a' : Number::toBitRate(bits: $averageUpload1m * 8, precision: 2)) + ), + Stat::make('Average Ping', '') + ->icon('heroicon-o-arrow-down-tray') + ->description( + '24 Hours: '.(blank($averagePing24h) ? 'n/a' : number_format($averagePing24h, 2).' ms')."\n". + '7 Days: '.(blank($averagePing7d) ? 'n/a' : number_format($averagePing7d, 2).' ms')."\n". + '1 Month: '.(blank($averagePing1m) ? 'n/a' : number_format($averagePing1m, 2).' ms') + ), ]; } } From 1fb06af461989dd5a1dad52c5c26a12961864781 Mon Sep 17 00:00:00 2001 From: svenvg93 Date: Thu, 8 Aug 2024 21:44:31 +0200 Subject: [PATCH 02/15] Commit it --- .../Widgets/RecentDownloadChartWidget.php | 21 +++++- app/Filament/Widgets/StatsOverviewWidget.php | 66 ++++--------------- 2 files changed, 30 insertions(+), 57 deletions(-) diff --git a/app/Filament/Widgets/RecentDownloadChartWidget.php b/app/Filament/Widgets/RecentDownloadChartWidget.php index 7aca1d1df..0625f7e5d 100644 --- a/app/Filament/Widgets/RecentDownloadChartWidget.php +++ b/app/Filament/Widgets/RecentDownloadChartWidget.php @@ -48,17 +48,32 @@ protected function getData(): array ->orderBy('created_at') ->get(); + $downloads = $results->map(fn ($item) => !blank($item->download) ? Number::bitsToMagnitude(bits: $item->download_bits, precision: 2, magnitude: 'mbit') : 0); + $averageDownload = $downloads->avg(); + return [ 'datasets' => [ [ 'label' => 'Download', - 'data' => $results->map(fn ($item) => ! blank($item->download) ? Number::bitsToMagnitude(bits: $item->download_bits, precision: 2, magnitude: 'mbit') : 0), + 'data' => $downloads, 'borderColor' => '#0ea5e9', 'backgroundColor' => '#0ea5e9', 'pointBackgroundColor' => '#0ea5e9', 'fill' => false, 'cubicInterpolationMode' => 'monotone', 'tension' => 0.4, + 'pointRadius' => 0, + ], + [ + 'label' => 'Average', + 'data' => array_fill(0, count($downloads), $averageDownload), + 'borderColor' => '#ff0000', + 'pointBackgroundColor' => '#ff0000', + 'fill' => false, + 'cubicInterpolationMode' => 'monotone', + 'tension' => 0.4, + 'borderDash' => [5, 5], + 'pointRadius' => 0, ], ], 'labels' => $results->map(fn ($item) => $item->created_at->timezone(config('app.display_timezone'))->format(config('app.chart_datetime_format'))), @@ -70,12 +85,12 @@ protected function getOptions(): array return [ 'plugins' => [ 'legend' => [ - 'display' => false, + 'display' => true, ], ], 'scales' => [ 'y' => [ - 'beginAtZero' => true, + 'beginAtZero' => false, ], ], ]; diff --git a/app/Filament/Widgets/StatsOverviewWidget.php b/app/Filament/Widgets/StatsOverviewWidget.php index 52936e65d..d6e89f505 100644 --- a/app/Filament/Widgets/StatsOverviewWidget.php +++ b/app/Filament/Widgets/StatsOverviewWidget.php @@ -5,7 +5,6 @@ use App\Enums\ResultStatus; use App\Helpers\Number; use App\Models\Result; -use Carbon\Carbon; use Filament\Widgets\StatsOverviewWidget as BaseWidget; use Filament\Widgets\StatsOverviewWidget\Stat; @@ -44,40 +43,21 @@ protected function getCards(): array ->latest() ->first(); + if (! $previous) { + return [ + Stat::make('Latest download', fn (): string => ! blank($this->result) ? Number::toBitRate(bits: $this->result->download_bits, precision: 2) : 'n/a') + ->icon('heroicon-o-arrow-down-tray'), + Stat::make('Latest upload', fn (): string => ! blank($this->result) ? Number::toBitRate(bits: $this->result->upload_bits, precision: 2) : 'n/a') + ->icon('heroicon-o-arrow-up-tray'), + Stat::make('Latest ping', fn (): string => ! blank($this->result) ? number_format($this->result->ping, 2).' ms' : 'n/a') + ->icon('heroicon-o-clock'), + ]; + } + $downloadChange = percentChange($this->result->download, $previous->download, 2); $uploadChange = percentChange($this->result->upload, $previous->upload, 2); $pingChange = percentChange($this->result->ping, $previous->ping, 2); - $last24hData = Result::query() - ->select(['download', 'upload', 'ping']) - ->where('status', '=', ResultStatus::Completed) - ->where('created_at', '>=', Carbon::now()->subDay()) - ->get(); - - $averageDownload24h = $last24hData->avg('download'); - $averageUpload24h = $last24hData->avg('upload'); - $averagePing24h = $last24hData->avg('ping'); - - $last7dData = Result::query() - ->select(['download', 'upload', 'ping']) - ->where('status', '=', ResultStatus::Completed) - ->where('created_at', '>=', Carbon::now()->subWeek()) - ->get(); - - $averageDownload7d = $last7dData->avg('download'); - $averageUpload7d = $last7dData->avg('upload'); - $averagePing7d = $last7dData->avg('ping'); - - $last1mData = Result::query() - ->select(['download', 'upload', 'ping']) - ->where('status', '=', ResultStatus::Completed) - ->where('created_at', '>=', Carbon::now()->subMonth()) - ->get(); - - $averageDownload1m = $last1mData->avg('download'); - $averageUpload1m = $last1mData->avg('upload'); - $averagePing1m = $last1mData->avg('ping'); - return [ Stat::make('Latest download', fn (): string => ! blank($this->result) ? Number::toBitRate(bits: $this->result->download_bits, precision: 2) : 'n/a') ->icon('heroicon-o-arrow-down-tray') @@ -94,28 +74,6 @@ protected function getCards(): array ->description($pingChange > 0 ? $pingChange.'% slower' : abs($pingChange).'% faster') ->descriptionIcon($pingChange > 0 ? 'heroicon-m-arrow-trending-up' : 'heroicon-m-arrow-trending-down') ->color($pingChange > 0 ? 'danger' : 'success'), - - Stat::make('Average Download', '') - ->icon('heroicon-o-arrow-down-tray') - ->description( - '24 Hours: '.(blank($averageDownload24h) ? 'n/a' : Number::toBitRate(bits: $averageDownload24h * 8, precision: 2))."\n". - '7 Days: '.(blank($averageDownload7d) ? 'n/a' : Number::toBitRate(bits: $averageDownload7d * 8, precision: 2))."\n". - '1 Month: '.(blank($averageDownload1m) ? 'n/a' : Number::toBitRate(bits: $averageDownload1m * 8, precision: 2)) - ), - Stat::make('Average Upload', '') - ->icon('heroicon-o-arrow-down-tray') - ->description( - '24 Hours: '.(blank($averageUpload24h) ? 'n/a' : Number::toBitRate(bits: $averageUpload24h * 8, precision: 2))."\n". - '7 Days: '.(blank($averageUpload7d) ? 'n/a' : Number::toBitRate(bits: $averageUpload7d * 8, precision: 2))."\n". - '1 Month: '.(blank($averageUpload1m) ? 'n/a' : Number::toBitRate(bits: $averageUpload1m * 8, precision: 2)) - ), - Stat::make('Average Ping', '') - ->icon('heroicon-o-arrow-down-tray') - ->description( - '24 Hours: '.(blank($averagePing24h) ? 'n/a' : number_format($averagePing24h, 2).' ms')."\n". - '7 Days: '.(blank($averagePing7d) ? 'n/a' : number_format($averagePing7d, 2).' ms')."\n". - '1 Month: '.(blank($averagePing1m) ? 'n/a' : number_format($averagePing1m, 2).' ms') - ), ]; } -} +} \ No newline at end of file From 78252569233898afba8e7ae9d3ac2ddf027c2795 Mon Sep 17 00:00:00 2001 From: svenvg93 Date: Thu, 8 Aug 2024 21:47:02 +0200 Subject: [PATCH 03/15] lint --- app/Filament/Widgets/RecentDownloadChartWidget.php | 2 +- app/Filament/Widgets/StatsOverviewWidget.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/Filament/Widgets/RecentDownloadChartWidget.php b/app/Filament/Widgets/RecentDownloadChartWidget.php index 0625f7e5d..32ae8acb8 100644 --- a/app/Filament/Widgets/RecentDownloadChartWidget.php +++ b/app/Filament/Widgets/RecentDownloadChartWidget.php @@ -48,7 +48,7 @@ protected function getData(): array ->orderBy('created_at') ->get(); - $downloads = $results->map(fn ($item) => !blank($item->download) ? Number::bitsToMagnitude(bits: $item->download_bits, precision: 2, magnitude: 'mbit') : 0); + $downloads = $results->map(fn ($item) => ! blank($item->download) ? Number::bitsToMagnitude(bits: $item->download_bits, precision: 2, magnitude: 'mbit') : 0); $averageDownload = $downloads->avg(); return [ diff --git a/app/Filament/Widgets/StatsOverviewWidget.php b/app/Filament/Widgets/StatsOverviewWidget.php index d6e89f505..6a7721147 100644 --- a/app/Filament/Widgets/StatsOverviewWidget.php +++ b/app/Filament/Widgets/StatsOverviewWidget.php @@ -76,4 +76,4 @@ protected function getCards(): array ->color($pingChange > 0 ? 'danger' : 'success'), ]; } -} \ No newline at end of file +} From 7f1e903237aeac0b46070c50e548f8e0a33022e7 Mon Sep 17 00:00:00 2001 From: svenvg93 Date: Fri, 9 Aug 2024 10:55:58 +0200 Subject: [PATCH 04/15] update-all-charts --- .../RecentDownloadLatencyChartWidget.php | 5 +++- .../Widgets/RecentJitterChartWidget.php | 5 +++- .../Widgets/RecentPingChartWidget.php | 24 +++++++++++++++++-- .../Widgets/RecentUploadChartWidget.php | 21 +++++++++++++--- .../RecentUploadLatencyChartWidget.php | 5 +++- 5 files changed, 52 insertions(+), 8 deletions(-) diff --git a/app/Filament/Widgets/RecentDownloadLatencyChartWidget.php b/app/Filament/Widgets/RecentDownloadLatencyChartWidget.php index c7bb0e05a..fc2bfc05a 100644 --- a/app/Filament/Widgets/RecentDownloadLatencyChartWidget.php +++ b/app/Filament/Widgets/RecentDownloadLatencyChartWidget.php @@ -58,6 +58,7 @@ protected function getData(): array 'fill' => false, 'cubicInterpolationMode' => 'monotone', 'tension' => 0.4, + 'pointRadius' => 0, ], [ 'label' => 'High (ms)', @@ -68,6 +69,7 @@ protected function getData(): array 'fill' => false, 'cubicInterpolationMode' => 'monotone', 'tension' => 0.4, + 'pointRadius' => 0, ], [ 'label' => 'Low (ms)', @@ -78,6 +80,7 @@ protected function getData(): array 'fill' => false, 'cubicInterpolationMode' => 'monotone', 'tension' => 0.4, + 'pointRadius' => 0, ], ], 'labels' => $results->map(fn ($item) => $item->created_at->timezone(config('app.display_timezone'))->format(config('app.chart_datetime_format'))), @@ -89,7 +92,7 @@ protected function getOptions(): array return [ 'scales' => [ 'y' => [ - 'beginAtZero' => true, + 'beginAtZero' => false, ], ], ]; diff --git a/app/Filament/Widgets/RecentJitterChartWidget.php b/app/Filament/Widgets/RecentJitterChartWidget.php index 2d2454862..0b4b2df3f 100644 --- a/app/Filament/Widgets/RecentJitterChartWidget.php +++ b/app/Filament/Widgets/RecentJitterChartWidget.php @@ -58,6 +58,7 @@ protected function getData(): array 'fill' => false, 'cubicInterpolationMode' => 'monotone', 'tension' => 0.4, + 'pointRadius' => 0, ], [ 'label' => 'Upload (ms)', @@ -68,6 +69,7 @@ protected function getData(): array 'fill' => false, 'cubicInterpolationMode' => 'monotone', 'tension' => 0.4, + 'pointRadius' => 0, ], [ 'label' => 'Ping (ms)', @@ -78,6 +80,7 @@ protected function getData(): array 'fill' => false, 'cubicInterpolationMode' => 'monotone', 'tension' => 0.4, + 'pointRadius' => 0, ], ], 'labels' => $results->map(fn ($item) => $item->created_at->timezone(config('app.display_timezone'))->format(config('app.chart_datetime_format'))), @@ -89,7 +92,7 @@ protected function getOptions(): array return [ 'scales' => [ 'y' => [ - 'beginAtZero' => true, + 'beginAtZero' => false, ], ], ]; diff --git a/app/Filament/Widgets/RecentPingChartWidget.php b/app/Filament/Widgets/RecentPingChartWidget.php index 57a10eee5..8dccdd286 100644 --- a/app/Filament/Widgets/RecentPingChartWidget.php +++ b/app/Filament/Widgets/RecentPingChartWidget.php @@ -47,17 +47,32 @@ protected function getData(): array ->orderBy('created_at') ->get(); + $ping = $results->map(fn ($item) => ! blank($item->ping) ? number_format($item->ping, 2) : 0); + $averagePing = $ping->avg(); + return [ 'datasets' => [ [ 'label' => 'Ping (ms)', - 'data' => $results->map(fn ($item) => ! blank($item->ping) ? number_format($item->ping, 2) : 0), + 'data' => $ping, 'borderColor' => '#10b981', 'backgroundColor' => '#10b981', 'pointBackgroundColor' => '#10b981', 'fill' => false, 'cubicInterpolationMode' => 'monotone', 'tension' => 0.4, + 'pointRadius' => 0, + ], + [ + 'label' => 'Average', + 'data' => array_fill(0, count($ping), $averagePing), + 'borderColor' => '#ff0000', + 'pointBackgroundColor' => '#ff0000', + 'fill' => false, + 'cubicInterpolationMode' => 'monotone', + 'tension' => 0.4, + 'borderDash' => [5, 5], + 'pointRadius' => 0, ], ], 'labels' => $results->map(fn ($item) => $item->created_at->timezone(config('app.display_timezone'))->format(config('app.chart_datetime_format'))), @@ -67,9 +82,14 @@ protected function getData(): array protected function getOptions(): array { return [ + 'plugins' => [ + 'legend' => [ + 'display' => true, + ], + ], 'scales' => [ 'y' => [ - 'beginAtZero' => true, + 'beginAtZero' => false, ], ], ]; diff --git a/app/Filament/Widgets/RecentUploadChartWidget.php b/app/Filament/Widgets/RecentUploadChartWidget.php index 5c9c85baf..d3086353a 100644 --- a/app/Filament/Widgets/RecentUploadChartWidget.php +++ b/app/Filament/Widgets/RecentUploadChartWidget.php @@ -48,17 +48,32 @@ protected function getData(): array ->orderBy('created_at') ->get(); + $upload = $results->map(fn ($item) => ! blank($item->upload) ? Number::bitsToMagnitude(bits: $item->upload_bits, precision: 2, magnitude: 'mbit') : 0); + $averageUpload = $upload->avg(); + return [ 'datasets' => [ [ 'label' => 'Upload', - 'data' => $results->map(fn ($item) => ! blank($item->upload) ? Number::bitsToMagnitude(bits: $item->upload_bits, precision: 2, magnitude: 'mbit') : 0), + 'data' => $upload, 'borderColor' => '#8b5cf6', 'backgroundColor' => '#8b5cf6', 'pointBackgroundColor' => '#8b5cf6', 'fill' => false, 'cubicInterpolationMode' => 'monotone', 'tension' => 0.4, + 'pointRadius' => 0, + ], + [ + 'label' => 'Average', + 'data' => array_fill(0, count($upload), $averageUpload), + 'borderColor' => '#ff0000', + 'pointBackgroundColor' => '#ff0000', + 'fill' => false, + 'cubicInterpolationMode' => 'monotone', + 'tension' => 0.4, + 'borderDash' => [5, 5], + 'pointRadius' => 0, ], ], 'labels' => $results->map(fn ($item) => $item->created_at->timezone(config('app.display_timezone'))->format(config('app.chart_datetime_format'))), @@ -70,12 +85,12 @@ protected function getOptions(): array return [ 'plugins' => [ 'legend' => [ - 'display' => false, + 'display' => true, ], ], 'scales' => [ 'y' => [ - 'beginAtZero' => true, + 'beginAtZero' => false, ], ], ]; diff --git a/app/Filament/Widgets/RecentUploadLatencyChartWidget.php b/app/Filament/Widgets/RecentUploadLatencyChartWidget.php index 049055adc..94ccfd321 100644 --- a/app/Filament/Widgets/RecentUploadLatencyChartWidget.php +++ b/app/Filament/Widgets/RecentUploadLatencyChartWidget.php @@ -58,6 +58,7 @@ protected function getData(): array 'fill' => false, 'cubicInterpolationMode' => 'monotone', 'tension' => 0.4, + 'pointRadius' => 0, ], [ 'label' => 'High (ms)', @@ -68,6 +69,7 @@ protected function getData(): array 'fill' => false, 'cubicInterpolationMode' => 'monotone', 'tension' => 0.4, + 'pointRadius' => 0, ], [ 'label' => 'Low (ms)', @@ -78,6 +80,7 @@ protected function getData(): array 'fill' => false, 'cubicInterpolationMode' => 'monotone', 'tension' => 0.4, + 'pointRadius' => 0, ], ], 'labels' => $results->map(fn ($item) => $item->created_at->timezone(config('app.display_timezone'))->format(config('app.chart_datetime_format'))), @@ -89,7 +92,7 @@ protected function getOptions(): array return [ 'scales' => [ 'y' => [ - 'beginAtZero' => true, + 'beginAtZero' => false, ], ], ]; From 0073e6affe897cea814b8f9a96c7e3495cc20803 Mon Sep 17 00:00:00 2001 From: svenvg93 Date: Mon, 12 Aug 2024 18:21:36 +0200 Subject: [PATCH 05/15] push_local_git --- .../Widgets/RecentDownloadChartWidget.php | 10 +++--- .../RecentDownloadLatencyChartWidget.php | 36 +++++++++---------- .../Widgets/RecentJitterChartWidget.php | 36 +++++++++---------- .../Widgets/RecentPingChartWidget.php | 10 +++--- .../Widgets/RecentUploadChartWidget.php | 10 +++--- .../RecentUploadLatencyChartWidget.php | 36 +++++++++---------- 6 files changed, 69 insertions(+), 69 deletions(-) diff --git a/app/Filament/Widgets/RecentDownloadChartWidget.php b/app/Filament/Widgets/RecentDownloadChartWidget.php index 32ae8acb8..36b72df74 100644 --- a/app/Filament/Widgets/RecentDownloadChartWidget.php +++ b/app/Filament/Widgets/RecentDownloadChartWidget.php @@ -56,13 +56,13 @@ protected function getData(): array [ 'label' => 'Download', 'data' => $downloads, - 'borderColor' => '#0ea5e9', - 'backgroundColor' => '#0ea5e9', - 'pointBackgroundColor' => '#0ea5e9', - 'fill' => false, + 'borderColor' => 'rgba(14, 165, 233)', + 'backgroundColor' => 'rgba(14, 165, 233, 0.1)', // 10% opacity + 'pointBackgroundColor' => 'rgba(14, 165, 233)', + 'fill' => true, 'cubicInterpolationMode' => 'monotone', 'tension' => 0.4, - 'pointRadius' => 0, + 'pointRadius' => count($downloads) <= 25 ? 3 : 0, ], [ 'label' => 'Average', diff --git a/app/Filament/Widgets/RecentDownloadLatencyChartWidget.php b/app/Filament/Widgets/RecentDownloadLatencyChartWidget.php index fc2bfc05a..80ce99ac0 100644 --- a/app/Filament/Widgets/RecentDownloadLatencyChartWidget.php +++ b/app/Filament/Widgets/RecentDownloadLatencyChartWidget.php @@ -51,36 +51,36 @@ protected function getData(): array 'datasets' => [ [ 'label' => 'Average (ms)', - 'data' => $results->map(fn ($item) => $item->download_latency_iqm ? number_format($item->download_latency_iqm, 2) : 0), - 'borderColor' => '#10b981', - 'backgroundColor' => '#10b981', - 'pointBackgroundColor' => '#10b981', - 'fill' => false, + 'data' => $averageData = $results->map(fn ($item) => $item->download_latency_iqm ? number_format($item->download_latency_iqm, 2) : 0), + 'borderColor' => 'rgba(16, 185, 129)', + 'backgroundColor' => 'rgba(16, 185, 129, 0.1)', + 'pointBackgroundColor' => 'rgba(16, 185, 129)', + 'fill' => true, 'cubicInterpolationMode' => 'monotone', 'tension' => 0.4, - 'pointRadius' => 0, + 'pointRadius' => $averageData->count() <= 25 ? 3 : 0, ], [ 'label' => 'High (ms)', - 'data' => $results->map(fn ($item) => $item->download_latency_high ? number_format($item->download_latency_high, 2) : 0), - 'borderColor' => '#0ea5e9', - 'backgroundColor' => '#0ea5e9', - 'pointBackgroundColor' => '#0ea5e9', - 'fill' => false, + 'data' => $highData = $results->map(fn ($item) => $item->download_latency_high ? number_format($item->download_latency_high, 2) : 0), + 'borderColor' => 'rgba(14, 165, 233)', + 'backgroundColor' => 'rgba(14, 165, 233, 0.1)', + 'pointBackgroundColor' => 'rgba(14, 165, 233)', + 'fill' => true, 'cubicInterpolationMode' => 'monotone', 'tension' => 0.4, - 'pointRadius' => 0, + 'pointRadius' => $highData->count() <= 25 ? 3 : 0, ], [ 'label' => 'Low (ms)', - 'data' => $results->map(fn ($item) => $item->download_latency_low ? number_format($item->download_latency_low, 2) : 0), - 'borderColor' => '#8b5cf6', - 'backgroundColor' => '#8b5cf6', - 'pointBackgroundColor' => '#8b5cf6', - 'fill' => false, + 'data' => $lowData = $results->map(fn ($item) => $item->download_latency_low ? number_format($item->download_latency_low, 2) : 0), + 'borderColor' => 'rgba(139, 92, 246)', + 'backgroundColor' => 'rgba(139, 92, 246, 0.1)', + 'pointBackgroundColor' => 'rgba(139, 92, 246)', + 'fill' => true, 'cubicInterpolationMode' => 'monotone', 'tension' => 0.4, - 'pointRadius' => 0, + 'pointRadius' => $lowData->count() <= 25 ? 3 : 0, ], ], 'labels' => $results->map(fn ($item) => $item->created_at->timezone(config('app.display_timezone'))->format(config('app.chart_datetime_format'))), diff --git a/app/Filament/Widgets/RecentJitterChartWidget.php b/app/Filament/Widgets/RecentJitterChartWidget.php index 0b4b2df3f..e18745bb5 100644 --- a/app/Filament/Widgets/RecentJitterChartWidget.php +++ b/app/Filament/Widgets/RecentJitterChartWidget.php @@ -51,36 +51,36 @@ protected function getData(): array 'datasets' => [ [ 'label' => 'Download (ms)', - 'data' => $results->map(fn ($item) => $item->download_jitter ? number_format($item->download_jitter, 2) : 0), - 'borderColor' => '#0ea5e9', - 'backgroundColor' => '#0ea5e9', - 'pointBackgroundColor' => '#0ea5e9', - 'fill' => false, + 'data' => $downloadData = $results->map(fn ($item) => $item->download_jitter ? number_format($item->download_jitter, 2) : 0), + 'borderColor' => 'rgba(14, 165, 233)', + 'backgroundColor' => 'rgba(14, 165, 233, 0.1)', + 'pointBackgroundColor' => 'rgba(14, 165, 233)', + 'fill' => true, 'cubicInterpolationMode' => 'monotone', 'tension' => 0.4, - 'pointRadius' => 0, + 'pointRadius' => $downloadData->count() <= 25 ? 3 : 0, ], [ 'label' => 'Upload (ms)', - 'data' => $results->map(fn ($item) => $item->upload_jitter ? number_format($item->upload_jitter, 2) : 0), - 'borderColor' => '#8b5cf6', - 'backgroundColor' => '#8b5cf6', - 'pointBackgroundColor' => '#8b5cf6', - 'fill' => false, + 'data' => $uploadData = $results->map(fn ($item) => $item->upload_jitter ? number_format($item->upload_jitter, 2) : 0), + 'borderColor' => 'rgba(139, 92, 246)', + 'backgroundColor' => 'rgba(139, 92, 246, 0.1)', + 'pointBackgroundColor' => 'rgba(139, 92, 246)', + 'fill' => true, 'cubicInterpolationMode' => 'monotone', 'tension' => 0.4, - 'pointRadius' => 0, + 'pointRadius' => $uploadData->count() <= 25 ? 3 : 0, ], [ 'label' => 'Ping (ms)', - 'data' => $results->map(fn ($item) => $item->ping_jitter ? number_format($item->ping_jitter, 2) : 0), - 'borderColor' => '#10b981', - 'backgroundColor' => '#10b981', - 'pointBackgroundColor' => '#10b981', - 'fill' => false, + 'data' => $pingData = $results->map(fn ($item) => $item->ping_jitter ? number_format($item->ping_jitter, 2) : 0), + 'borderColor' => 'rgba(16, 185, 129)', + 'backgroundColor' => 'rgba(16, 185, 129, 0.1)', + 'pointBackgroundColor' => 'rgba(16, 185, 129)', + 'fill' => true, 'cubicInterpolationMode' => 'monotone', 'tension' => 0.4, - 'pointRadius' => 0, + 'pointRadius' => $pingData->count() <= 25 ? 3 : 0, ], ], 'labels' => $results->map(fn ($item) => $item->created_at->timezone(config('app.display_timezone'))->format(config('app.chart_datetime_format'))), diff --git a/app/Filament/Widgets/RecentPingChartWidget.php b/app/Filament/Widgets/RecentPingChartWidget.php index 8dccdd286..f8da5a180 100644 --- a/app/Filament/Widgets/RecentPingChartWidget.php +++ b/app/Filament/Widgets/RecentPingChartWidget.php @@ -55,13 +55,13 @@ protected function getData(): array [ 'label' => 'Ping (ms)', 'data' => $ping, - 'borderColor' => '#10b981', - 'backgroundColor' => '#10b981', - 'pointBackgroundColor' => '#10b981', - 'fill' => false, + 'borderColor' => 'rgba(16, 185, 129)', + 'backgroundColor' => 'rgba(16, 185, 129, 0.1)', + 'pointBackgroundColor' => 'rgba(16, 185, 129)', + 'fill' => true, 'cubicInterpolationMode' => 'monotone', 'tension' => 0.4, - 'pointRadius' => 0, + 'pointRadius' => count($ping) <= 25 ? 3 : 0, ], [ 'label' => 'Average', diff --git a/app/Filament/Widgets/RecentUploadChartWidget.php b/app/Filament/Widgets/RecentUploadChartWidget.php index d3086353a..f96d1bb09 100644 --- a/app/Filament/Widgets/RecentUploadChartWidget.php +++ b/app/Filament/Widgets/RecentUploadChartWidget.php @@ -56,13 +56,13 @@ protected function getData(): array [ 'label' => 'Upload', 'data' => $upload, - 'borderColor' => '#8b5cf6', - 'backgroundColor' => '#8b5cf6', - 'pointBackgroundColor' => '#8b5cf6', - 'fill' => false, + 'borderColor' => 'rgba(139, 92, 246)', + 'backgroundColor' => 'rgba(139, 92, 246, 0.1)', + 'pointBackgroundColor' => 'rgba(139, 92, 246)', + 'fill' => true, 'cubicInterpolationMode' => 'monotone', 'tension' => 0.4, - 'pointRadius' => 0, + 'pointRadius' => count($upload) <= 25 ? 3 : 0, ], [ 'label' => 'Average', diff --git a/app/Filament/Widgets/RecentUploadLatencyChartWidget.php b/app/Filament/Widgets/RecentUploadLatencyChartWidget.php index 94ccfd321..0a2f676ef 100644 --- a/app/Filament/Widgets/RecentUploadLatencyChartWidget.php +++ b/app/Filament/Widgets/RecentUploadLatencyChartWidget.php @@ -51,36 +51,36 @@ protected function getData(): array 'datasets' => [ [ 'label' => 'Average (ms)', - 'data' => $results->map(fn ($item) => $item->upload_latency_iqm ? number_format($item->upload_latency_iqm, 2) : 0), - 'borderColor' => '#10b981', - 'backgroundColor' => '#10b981', - 'pointBackgroundColor' => '#10b981', - 'fill' => false, + 'data' => $averageData = $results->map(fn ($item) => $item->upload_latency_iqm ? number_format($item->upload_latency_iqm, 2) : 0), + 'borderColor' => 'rgba(16, 185, 129)', + 'backgroundColor' => 'rgba(16, 185, 129, 0.1)', + 'pointBackgroundColor' => 'rgba(16, 185, 129)', + 'fill' => true, 'cubicInterpolationMode' => 'monotone', 'tension' => 0.4, - 'pointRadius' => 0, + 'pointRadius' => $averageData->count() <= 25 ? 3 : 0, ], [ 'label' => 'High (ms)', - 'data' => $results->map(fn ($item) => $item->upload_latency_high ? number_format($item->upload_latency_high, 2) : 0), - 'borderColor' => '#0ea5e9', - 'backgroundColor' => '#0ea5e9', - 'pointBackgroundColor' => '#0ea5e9', - 'fill' => false, + 'data' => $highData = $results->map(fn ($item) => $item->upload_latency_high ? number_format($item->upload_latency_high, 2) : 0), + 'borderColor' => 'rgba(14, 165, 233)', + 'backgroundColor' => 'rgba(14, 165, 233, 0.1)', + 'pointBackgroundColor' => 'rgba(14, 165, 233)', + 'fill' => true, 'cubicInterpolationMode' => 'monotone', 'tension' => 0.4, - 'pointRadius' => 0, + 'pointRadius' => $highData->count() <= 25 ? 3 : 0, ], [ 'label' => 'Low (ms)', - 'data' => $results->map(fn ($item) => $item->upload_latency_low ? number_format($item->upload_latency_low, 2) : 0), - 'borderColor' => '#8b5cf6', - 'backgroundColor' => '#8b5cf6', - 'pointBackgroundColor' => '#8b5cf6', - 'fill' => false, + 'data' => $lowData = $results->map(fn ($item) => $item->upload_latency_low ? number_format($item->upload_latency_low, 2) : 0), + 'borderColor' => 'rgba(139, 92, 246)', + 'backgroundColor' => 'rgba(139, 92, 246, 0.1)', + 'pointBackgroundColor' => 'rgba(139, 92, 246)', + 'fill' => true, 'cubicInterpolationMode' => 'monotone', 'tension' => 0.4, - 'pointRadius' => 0, + 'pointRadius' => $lowData->count() <= 25 ? 3 : 0, ], ], 'labels' => $results->map(fn ($item) => $item->created_at->timezone(config('app.display_timezone'))->format(config('app.chart_datetime_format'))), From 21221422a2ea931a726705dd6cdc5c0ddab1ea0e Mon Sep 17 00:00:00 2001 From: svenvg93 Date: Mon, 12 Aug 2024 22:29:16 +0200 Subject: [PATCH 06/15] add-timepicker --- app/Filament/Pages/Dashboard.php | 43 +++++++++++++++++-- .../Widgets/RecentDownloadChartWidget.php | 32 +++++--------- .../RecentDownloadLatencyChartWidget.php | 36 ++++++---------- .../Widgets/RecentJitterChartWidget.php | 36 ++++++---------- .../Widgets/RecentPingChartWidget.php | 32 +++++--------- .../Widgets/RecentUploadChartWidget.php | 32 +++++--------- .../RecentUploadLatencyChartWidget.php | 36 ++++++---------- config/speedtest.php | 4 ++ .../views/filament/pages/dashboard.blade.php | 3 -- 9 files changed, 115 insertions(+), 139 deletions(-) delete mode 100644 resources/views/filament/pages/dashboard.blade.php diff --git a/app/Filament/Pages/Dashboard.php b/app/Filament/Pages/Dashboard.php index 3737cf9bf..64fd6afdd 100644 --- a/app/Filament/Pages/Dashboard.php +++ b/app/Filament/Pages/Dashboard.php @@ -14,16 +14,20 @@ use Cron\CronExpression; use Filament\Actions\Action; use Filament\Actions\ActionGroup; +use Filament\Forms; +use Filament\Forms\Components\DatePicker; +use Filament\Forms\Form; use Filament\Notifications\Notification; -use Filament\Pages\Dashboard as BasePage; +use Filament\Pages\Dashboard as BaseDashboard; +use Filament\Pages\Dashboard\Concerns\HasFiltersForm; use Filament\Support\Enums\IconPosition; use Illuminate\Support\Arr; -class Dashboard extends BasePage +class Dashboard extends BaseDashboard { - protected static ?string $navigationIcon = 'heroicon-o-chart-bar'; + use HasFiltersForm; - protected static string $view = 'filament.pages.dashboard'; + protected static ?string $navigationIcon = 'heroicon-o-chart-bar'; public function getSubheading(): ?string { @@ -38,6 +42,31 @@ public function getSubheading(): ?string return 'Next speedtest at: '.$nextRunDate; } + public function filtersForm(Form $form): Form + { + // Retrieve the default number of days from the configuration + $defaultRangeDays = config('speedtest.chart_time_range'); + + // Calculate the start and end dates based on the configuration value + $endDate = now(); // Today + $startDate = now()->subDays($defaultRangeDays); // Start date for the range + + return $form + ->schema([ + Forms\Components\Section::make() + ->schema([ + DatePicker::make('startDate') + ->default($startDate), + DatePicker::make('endDate') + ->default($endDate), + ]) + ->columns([ + 'default' => 1, + 'sm' => 2, + ]), + ]); + } + protected function getHeaderActions(): array { return [ @@ -83,6 +112,12 @@ protected function getHeaderWidgets(): array { return [ StatsOverviewWidget::make(), + ]; + } + + public function getWidgets(): array + { + return [ RecentDownloadChartWidget::make(), RecentUploadChartWidget::make(), RecentPingChartWidget::make(), diff --git a/app/Filament/Widgets/RecentDownloadChartWidget.php b/app/Filament/Widgets/RecentDownloadChartWidget.php index 36b72df74..e6a9d7b23 100644 --- a/app/Filament/Widgets/RecentDownloadChartWidget.php +++ b/app/Filament/Widgets/RecentDownloadChartWidget.php @@ -6,45 +6,35 @@ use App\Helpers\Number; use App\Models\Result; use Filament\Widgets\ChartWidget; +use Filament\Widgets\Concerns\InteractsWithPageFilters; +use Illuminate\Database\Eloquent\Builder; class RecentDownloadChartWidget extends ChartWidget { + use InteractsWithPageFilters; + protected static ?string $heading = 'Download (Mbps)'; protected int|string|array $columnSpan = 'full'; protected static ?string $maxHeight = '250px'; - public ?string $filter = '24h'; - protected function getPollingInterval(): ?string { return config('speedtest.dashboard_polling'); } - protected function getFilters(): ?array - { - return [ - '24h' => 'Last 24h', - 'week' => 'Last week', - 'month' => 'Last month', - ]; - } - protected function getData(): array { + + $startDate = $this->filters['startDate'] ?? now()->subWeek(); + $endDate = $this->filters['endDate'] ?? now(); + $results = Result::query() ->select(['id', 'download', 'created_at']) ->where('status', '=', ResultStatus::Completed) - ->when($this->filter == '24h', function ($query) { - $query->where('created_at', '>=', now()->subDay()); - }) - ->when($this->filter == 'week', function ($query) { - $query->where('created_at', '>=', now()->subWeek()); - }) - ->when($this->filter == 'month', function ($query) { - $query->where('created_at', '>=', now()->subMonth()); - }) + ->when($startDate, fn (Builder $query) => $query->whereDate('created_at', '>=', $startDate)) + ->when($endDate, fn (Builder $query) => $query->whereDate('created_at', '<=', $endDate)) ->orderBy('created_at') ->get(); @@ -62,7 +52,7 @@ protected function getData(): array 'fill' => true, 'cubicInterpolationMode' => 'monotone', 'tension' => 0.4, - 'pointRadius' => count($downloads) <= 25 ? 3 : 0, + 'pointRadius' => count($downloads) <= 5 ? 3 : 0, ], [ 'label' => 'Average', diff --git a/app/Filament/Widgets/RecentDownloadLatencyChartWidget.php b/app/Filament/Widgets/RecentDownloadLatencyChartWidget.php index 80ce99ac0..4ac6f416d 100644 --- a/app/Filament/Widgets/RecentDownloadLatencyChartWidget.php +++ b/app/Filament/Widgets/RecentDownloadLatencyChartWidget.php @@ -5,45 +5,35 @@ use App\Enums\ResultStatus; use App\Models\Result; use Filament\Widgets\ChartWidget; +use Filament\Widgets\Concerns\InteractsWithPageFilters; +use Illuminate\Database\Eloquent\Builder; class RecentDownloadLatencyChartWidget extends ChartWidget { + use InteractsWithPageFilters; + protected static ?string $heading = 'Download Latency'; protected int|string|array $columnSpan = 'full'; protected static ?string $maxHeight = '250px'; - public ?string $filter = '24h'; - protected function getPollingInterval(): ?string { return config('speedtest.dashboard_polling'); } - protected function getFilters(): ?array - { - return [ - '24h' => 'Last 24h', - 'week' => 'Last week', - 'month' => 'Last month', - ]; - } - protected function getData(): array { + + $startDate = $this->filters['startDate'] ?? now()->subWeek(); + $endDate = $this->filters['endDate'] ?? now(); + $results = Result::query() ->select(['id', 'data', 'created_at']) ->where('status', '=', ResultStatus::Completed) - ->when($this->filter == '24h', function ($query) { - $query->where('created_at', '>=', now()->subDay()); - }) - ->when($this->filter == 'week', function ($query) { - $query->where('created_at', '>=', now()->subWeek()); - }) - ->when($this->filter == 'month', function ($query) { - $query->where('created_at', '>=', now()->subMonth()); - }) + ->when($startDate, fn (Builder $query) => $query->whereDate('created_at', '>=', $startDate)) + ->when($endDate, fn (Builder $query) => $query->whereDate('created_at', '<=', $endDate)) ->orderBy('created_at') ->get(); @@ -58,7 +48,7 @@ protected function getData(): array 'fill' => true, 'cubicInterpolationMode' => 'monotone', 'tension' => 0.4, - 'pointRadius' => $averageData->count() <= 25 ? 3 : 0, + 'pointRadius' => $averageData->count() <= 5 ? 3 : 0, ], [ 'label' => 'High (ms)', @@ -69,7 +59,7 @@ protected function getData(): array 'fill' => true, 'cubicInterpolationMode' => 'monotone', 'tension' => 0.4, - 'pointRadius' => $highData->count() <= 25 ? 3 : 0, + 'pointRadius' => $highData->count() <= 5 ? 3 : 0, ], [ 'label' => 'Low (ms)', @@ -80,7 +70,7 @@ protected function getData(): array 'fill' => true, 'cubicInterpolationMode' => 'monotone', 'tension' => 0.4, - 'pointRadius' => $lowData->count() <= 25 ? 3 : 0, + 'pointRadius' => $lowData->count() <= 5 ? 3 : 0, ], ], 'labels' => $results->map(fn ($item) => $item->created_at->timezone(config('app.display_timezone'))->format(config('app.chart_datetime_format'))), diff --git a/app/Filament/Widgets/RecentJitterChartWidget.php b/app/Filament/Widgets/RecentJitterChartWidget.php index e18745bb5..e1dae4dea 100644 --- a/app/Filament/Widgets/RecentJitterChartWidget.php +++ b/app/Filament/Widgets/RecentJitterChartWidget.php @@ -5,45 +5,35 @@ use App\Enums\ResultStatus; use App\Models\Result; use Filament\Widgets\ChartWidget; +use Filament\Widgets\Concerns\InteractsWithPageFilters; +use Illuminate\Database\Eloquent\Builder; class RecentJitterChartWidget extends ChartWidget { + use InteractsWithPageFilters; + protected static ?string $heading = 'Jitter'; protected int|string|array $columnSpan = 'full'; protected static ?string $maxHeight = '250px'; - public ?string $filter = '24h'; - protected function getPollingInterval(): ?string { return config('speedtest.dashboard_polling'); } - protected function getFilters(): ?array - { - return [ - '24h' => 'Last 24h', - 'week' => 'Last week', - 'month' => 'Last month', - ]; - } - protected function getData(): array { + + $startDate = $this->filters['startDate'] ?? now()->subWeek(); + $endDate = $this->filters['endDate'] ?? now(); + $results = Result::query() ->select(['id', 'data', 'created_at']) ->where('status', '=', ResultStatus::Completed) - ->when($this->filter == '24h', function ($query) { - $query->where('created_at', '>=', now()->subDay()); - }) - ->when($this->filter == 'week', function ($query) { - $query->where('created_at', '>=', now()->subWeek()); - }) - ->when($this->filter == 'month', function ($query) { - $query->where('created_at', '>=', now()->subMonth()); - }) + ->when($startDate, fn (Builder $query) => $query->whereDate('created_at', '>=', $startDate)) + ->when($endDate, fn (Builder $query) => $query->whereDate('created_at', '<=', $endDate)) ->orderBy('created_at') ->get(); @@ -58,7 +48,7 @@ protected function getData(): array 'fill' => true, 'cubicInterpolationMode' => 'monotone', 'tension' => 0.4, - 'pointRadius' => $downloadData->count() <= 25 ? 3 : 0, + 'pointRadius' => $downloadData->count() <= 5 ? 3 : 0, ], [ 'label' => 'Upload (ms)', @@ -69,7 +59,7 @@ protected function getData(): array 'fill' => true, 'cubicInterpolationMode' => 'monotone', 'tension' => 0.4, - 'pointRadius' => $uploadData->count() <= 25 ? 3 : 0, + 'pointRadius' => $uploadData->count() <= 5 ? 3 : 0, ], [ 'label' => 'Ping (ms)', @@ -80,7 +70,7 @@ protected function getData(): array 'fill' => true, 'cubicInterpolationMode' => 'monotone', 'tension' => 0.4, - 'pointRadius' => $pingData->count() <= 25 ? 3 : 0, + 'pointRadius' => $pingData->count() <= 5 ? 3 : 0, ], ], 'labels' => $results->map(fn ($item) => $item->created_at->timezone(config('app.display_timezone'))->format(config('app.chart_datetime_format'))), diff --git a/app/Filament/Widgets/RecentPingChartWidget.php b/app/Filament/Widgets/RecentPingChartWidget.php index f8da5a180..7c142f59a 100644 --- a/app/Filament/Widgets/RecentPingChartWidget.php +++ b/app/Filament/Widgets/RecentPingChartWidget.php @@ -5,45 +5,35 @@ use App\Enums\ResultStatus; use App\Models\Result; use Filament\Widgets\ChartWidget; +use Filament\Widgets\Concerns\InteractsWithPageFilters; +use Illuminate\Database\Eloquent\Builder; class RecentPingChartWidget extends ChartWidget { + use InteractsWithPageFilters; + protected static ?string $heading = 'Ping (ms)'; protected int|string|array $columnSpan = 'full'; protected static ?string $maxHeight = '250px'; - public ?string $filter = '24h'; - protected function getPollingInterval(): ?string { return config('speedtest.dashboard_polling'); } - protected function getFilters(): ?array - { - return [ - '24h' => 'Last 24h', - 'week' => 'Last week', - 'month' => 'Last month', - ]; - } - protected function getData(): array { + + $startDate = $this->filters['startDate'] ?? now()->subWeek(); + $endDate = $this->filters['endDate'] ?? now(); + $results = Result::query() ->select(['id', 'ping', 'created_at']) ->where('status', '=', ResultStatus::Completed) - ->when($this->filter == '24h', function ($query) { - $query->where('created_at', '>=', now()->subDay()); - }) - ->when($this->filter == 'week', function ($query) { - $query->where('created_at', '>=', now()->subWeek()); - }) - ->when($this->filter == 'month', function ($query) { - $query->where('created_at', '>=', now()->subMonth()); - }) + ->when($startDate, fn (Builder $query) => $query->whereDate('created_at', '>=', $startDate)) + ->when($endDate, fn (Builder $query) => $query->whereDate('created_at', '<=', $endDate)) ->orderBy('created_at') ->get(); @@ -61,7 +51,7 @@ protected function getData(): array 'fill' => true, 'cubicInterpolationMode' => 'monotone', 'tension' => 0.4, - 'pointRadius' => count($ping) <= 25 ? 3 : 0, + 'pointRadius' => count($ping) <= 5 ? 3 : 0, ], [ 'label' => 'Average', diff --git a/app/Filament/Widgets/RecentUploadChartWidget.php b/app/Filament/Widgets/RecentUploadChartWidget.php index f96d1bb09..ef24b76e1 100644 --- a/app/Filament/Widgets/RecentUploadChartWidget.php +++ b/app/Filament/Widgets/RecentUploadChartWidget.php @@ -6,45 +6,35 @@ use App\Helpers\Number; use App\Models\Result; use Filament\Widgets\ChartWidget; +use Filament\Widgets\Concerns\InteractsWithPageFilters; +use Illuminate\Database\Eloquent\Builder; class RecentUploadChartWidget extends ChartWidget { + use InteractsWithPageFilters; + protected static ?string $heading = 'Upload (Mbps)'; protected int|string|array $columnSpan = 'full'; protected static ?string $maxHeight = '250px'; - public ?string $filter = '24h'; - protected function getPollingInterval(): ?string { return config('speedtest.dashboard_polling'); } - protected function getFilters(): ?array - { - return [ - '24h' => 'Last 24h', - 'week' => 'Last week', - 'month' => 'Last month', - ]; - } - protected function getData(): array { + + $startDate = $this->filters['startDate'] ?? now()->subWeek(); + $endDate = $this->filters['endDate'] ?? now(); + $results = Result::query() ->select(['id', 'upload', 'created_at']) ->where('status', '=', ResultStatus::Completed) - ->when($this->filter == '24h', function ($query) { - $query->where('created_at', '>=', now()->subDay()); - }) - ->when($this->filter == 'week', function ($query) { - $query->where('created_at', '>=', now()->subWeek()); - }) - ->when($this->filter == 'month', function ($query) { - $query->where('created_at', '>=', now()->subMonth()); - }) + ->when($startDate, fn (Builder $query) => $query->whereDate('created_at', '>=', $startDate)) + ->when($endDate, fn (Builder $query) => $query->whereDate('created_at', '<=', $endDate)) ->orderBy('created_at') ->get(); @@ -62,7 +52,7 @@ protected function getData(): array 'fill' => true, 'cubicInterpolationMode' => 'monotone', 'tension' => 0.4, - 'pointRadius' => count($upload) <= 25 ? 3 : 0, + 'pointRadius' => count($upload) <= 5 ? 3 : 0, ], [ 'label' => 'Average', diff --git a/app/Filament/Widgets/RecentUploadLatencyChartWidget.php b/app/Filament/Widgets/RecentUploadLatencyChartWidget.php index 0a2f676ef..5dcc830e9 100644 --- a/app/Filament/Widgets/RecentUploadLatencyChartWidget.php +++ b/app/Filament/Widgets/RecentUploadLatencyChartWidget.php @@ -5,45 +5,35 @@ use App\Enums\ResultStatus; use App\Models\Result; use Filament\Widgets\ChartWidget; +use Filament\Widgets\Concerns\InteractsWithPageFilters; +use Illuminate\Database\Eloquent\Builder; class RecentUploadLatencyChartWidget extends ChartWidget { + use InteractsWithPageFilters; + protected static ?string $heading = 'Upload Latency'; protected int|string|array $columnSpan = 'full'; protected static ?string $maxHeight = '250px'; - public ?string $filter = '24h'; - protected function getPollingInterval(): ?string { return config('speedtest.dashboard_polling'); } - protected function getFilters(): ?array - { - return [ - '24h' => 'Last 24h', - 'week' => 'Last week', - 'month' => 'Last month', - ]; - } - protected function getData(): array { + + $startDate = $this->filters['startDate'] ?? now()->subWeek(); + $endDate = $this->filters['endDate'] ?? now(); + $results = Result::query() ->select(['id', 'data', 'created_at']) ->where('status', '=', ResultStatus::Completed) - ->when($this->filter == '24h', function ($query) { - $query->where('created_at', '>=', now()->subDay()); - }) - ->when($this->filter == 'week', function ($query) { - $query->where('created_at', '>=', now()->subWeek()); - }) - ->when($this->filter == 'month', function ($query) { - $query->where('created_at', '>=', now()->subMonth()); - }) + ->when($startDate, fn (Builder $query) => $query->whereDate('created_at', '>=', $startDate)) + ->when($endDate, fn (Builder $query) => $query->whereDate('created_at', '<=', $endDate)) ->orderBy('created_at') ->get(); @@ -58,7 +48,7 @@ protected function getData(): array 'fill' => true, 'cubicInterpolationMode' => 'monotone', 'tension' => 0.4, - 'pointRadius' => $averageData->count() <= 25 ? 3 : 0, + 'pointRadius' => $averageData->count() <= 5 ? 3 : 0, ], [ 'label' => 'High (ms)', @@ -69,7 +59,7 @@ protected function getData(): array 'fill' => true, 'cubicInterpolationMode' => 'monotone', 'tension' => 0.4, - 'pointRadius' => $highData->count() <= 25 ? 3 : 0, + 'pointRadius' => $highData->count() <= 5 ? 3 : 0, ], [ 'label' => 'Low (ms)', @@ -80,7 +70,7 @@ protected function getData(): array 'fill' => true, 'cubicInterpolationMode' => 'monotone', 'tension' => 0.4, - 'pointRadius' => $lowData->count() <= 25 ? 3 : 0, + 'pointRadius' => $lowData->count() <= 5 ? 3 : 0, ], ], 'labels' => $results->map(fn ($item) => $item->created_at->timezone(config('app.display_timezone'))->format(config('app.chart_datetime_format'))), diff --git a/config/speedtest.php b/config/speedtest.php index 3d532b5c8..0f88af691 100644 --- a/config/speedtest.php +++ b/config/speedtest.php @@ -17,6 +17,8 @@ 'public_dashboard' => env('PUBLIC_DASHBOARD', false), + 'chart_time_range' => env('CHART_TIME_RANGE', 7), + /** * Polling settings. */ @@ -35,4 +37,6 @@ 'servers' => env('SPEEDTEST_SERVERS', ''), + + ]; diff --git a/resources/views/filament/pages/dashboard.blade.php b/resources/views/filament/pages/dashboard.blade.php deleted file mode 100644 index f351a1c97..000000000 --- a/resources/views/filament/pages/dashboard.blade.php +++ /dev/null @@ -1,3 +0,0 @@ - - {{-- Silence is golden --}} - From 05b0091ee8c52bdf35123844c05306bbc650fbc8 Mon Sep 17 00:00:00 2001 From: svenvg93 Date: Tue, 13 Aug 2024 17:23:16 +0200 Subject: [PATCH 07/15] add-some-predefined-ranges --- app/Filament/Pages/Dashboard.php | 74 +++++++++++++++++++++++++++++--- config/app.php | 2 + config/speedtest.php | 2 - 3 files changed, 70 insertions(+), 8 deletions(-) diff --git a/app/Filament/Pages/Dashboard.php b/app/Filament/Pages/Dashboard.php index 64fd6afdd..1102b2896 100644 --- a/app/Filament/Pages/Dashboard.php +++ b/app/Filament/Pages/Dashboard.php @@ -16,6 +16,7 @@ use Filament\Actions\ActionGroup; use Filament\Forms; use Filament\Forms\Components\DatePicker; +use Filament\Forms\Components\Select; use Filament\Forms\Form; use Filament\Notifications\Notification; use Filament\Pages\Dashboard as BaseDashboard; @@ -45,24 +46,85 @@ public function getSubheading(): ?string public function filtersForm(Form $form): Form { // Retrieve the default number of days from the configuration - $defaultRangeDays = config('speedtest.chart_time_range'); + $defaultRangeDays = config('app.chart_time_range'); // Calculate the start and end dates based on the configuration value - $endDate = now(); // Today - $startDate = now()->subDays($defaultRangeDays); // Start date for the range + $defaultEndDate = now(); // Today + $defaultStartDate = now()->subDays($defaultRangeDays); // Start date for the range return $form ->schema([ Forms\Components\Section::make() ->schema([ + Select::make('predefinedRange') + ->label('Time Range') + ->options([ + '3_hours' => 'Last 3 Hours', + '6_hours' => 'Last 6 Hours', + '12_hours' => 'Last 12 Hours', + '24_hours' => 'Last 24 Hours', + '1_week' => 'Last 1 Week', + '1_month' => 'Last 1 Month', + '3_months' => 'Last 3 Months', + '6_months' => 'Last 6 Months', + 'custom' => 'Custom Range', + ]) + ->reactive() + ->afterStateUpdated(function ($state, callable $set) { + switch ($state) { + case '3_hours': + $set('startDate', now()->subHours(3)->toDateString()); + $set('endDate', now()->toDateString()); + break; + case '6_hours': + $set('startDate', now()->subHours(6)->toDateString()); + $set('endDate', now()->toDateString()); + break; + case '12_hours': + $set('startDate', now()->subHours(12)->toDateString()); + $set('endDate', now()->toDateString()); + break; + case '24_hours': + $set('startDate', now()->subDay()->toDateString()); + $set('endDate', now()->toDateString()); + break; + case '1_week': + $set('startDate', now()->subWeek()->toDateString()); + $set('endDate', now()->toDateString()); + break; + case '1_month': + $set('startDate', now()->subMonth()->toDateString()); + $set('endDate', now()->toDateString()); + break; + case '3_months': + $set('startDate', now()->subMonths(3)->toDateString()); + $set('endDate', now()->toDateString()); + break; + case '6_months': + $set('startDate', now()->subMonths(6)->toDateString()); + $set('endDate', now()->toDateString()); + break; + case 'custom': + break; + } + }) + ->default('custom'), + DatePicker::make('startDate') - ->default($startDate), + ->label('Start Date') + ->default($defaultStartDate->toDateString()) + ->reactive() + ->hidden(fn ($get) => $get('predefinedRange') !== 'custom'), + DatePicker::make('endDate') - ->default($endDate), + ->label('End Date') + ->default($defaultEndDate->toDateString()) + ->reactive() + ->hidden(fn ($get) => $get('predefinedRange') !== 'custom'), ]) ->columns([ 'default' => 1, - 'sm' => 2, + 'sm' => 3, ]), ]); } diff --git a/config/app.php b/config/app.php index 60b38f700..2f757b84e 100644 --- a/config/app.php +++ b/config/app.php @@ -14,4 +14,6 @@ 'force_https' => env('FORCE_HTTPS', false), + 'chart_time_range' => env('CHART_TIME_RANGE', 7), + ]; diff --git a/config/speedtest.php b/config/speedtest.php index b43c785b5..6e3654552 100644 --- a/config/speedtest.php +++ b/config/speedtest.php @@ -17,8 +17,6 @@ 'public_dashboard' => env('PUBLIC_DASHBOARD', false), - 'chart_time_range' => env('CHART_TIME_RANGE', 7), - /** * Polling settings. */ From afcf6b3888b0ff239996701e896ed0a8c9340347 Mon Sep 17 00:00:00 2001 From: svenvg93 Date: Tue, 13 Aug 2024 17:30:42 +0200 Subject: [PATCH 08/15] remove whiteline --- config/speedtest.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/config/speedtest.php b/config/speedtest.php index 6e3654552..8a55110c7 100644 --- a/config/speedtest.php +++ b/config/speedtest.php @@ -35,6 +35,4 @@ 'servers' => env('SPEEDTEST_SERVERS', ''), - - ]; From 756b324085fa32272e65393ca6aef746c274743c Mon Sep 17 00:00:00 2001 From: svenvg93 Date: Thu, 15 Aug 2024 15:56:54 +0200 Subject: [PATCH 09/15] Add_env_for_chart_start --- app/Filament/Widgets/RecentDownloadChartWidget.php | 4 ++-- app/Filament/Widgets/RecentDownloadLatencyChartWidget.php | 2 +- app/Filament/Widgets/RecentJitterChartWidget.php | 2 +- app/Filament/Widgets/RecentPingChartWidget.php | 2 +- app/Filament/Widgets/RecentUploadChartWidget.php | 2 +- app/Filament/Widgets/RecentUploadLatencyChartWidget.php | 2 +- config/app.php | 2 ++ 7 files changed, 9 insertions(+), 7 deletions(-) diff --git a/app/Filament/Widgets/RecentDownloadChartWidget.php b/app/Filament/Widgets/RecentDownloadChartWidget.php index e6a9d7b23..e50ada7ff 100644 --- a/app/Filament/Widgets/RecentDownloadChartWidget.php +++ b/app/Filament/Widgets/RecentDownloadChartWidget.php @@ -49,7 +49,7 @@ protected function getData(): array 'borderColor' => 'rgba(14, 165, 233)', 'backgroundColor' => 'rgba(14, 165, 233, 0.1)', // 10% opacity 'pointBackgroundColor' => 'rgba(14, 165, 233)', - 'fill' => true, + 'fill' => config('app.chart_fill_background'), 'cubicInterpolationMode' => 'monotone', 'tension' => 0.4, 'pointRadius' => count($downloads) <= 5 ? 3 : 0, @@ -80,7 +80,7 @@ protected function getOptions(): array ], 'scales' => [ 'y' => [ - 'beginAtZero' => false, + 'beginAtZero' => config('app.chart_begin_at_zero'), ], ], ]; diff --git a/app/Filament/Widgets/RecentDownloadLatencyChartWidget.php b/app/Filament/Widgets/RecentDownloadLatencyChartWidget.php index 4ac6f416d..da69c1199 100644 --- a/app/Filament/Widgets/RecentDownloadLatencyChartWidget.php +++ b/app/Filament/Widgets/RecentDownloadLatencyChartWidget.php @@ -82,7 +82,7 @@ protected function getOptions(): array return [ 'scales' => [ 'y' => [ - 'beginAtZero' => false, + 'beginAtZero' => config('app.chart_begin_at_zero'), ], ], ]; diff --git a/app/Filament/Widgets/RecentJitterChartWidget.php b/app/Filament/Widgets/RecentJitterChartWidget.php index e1dae4dea..70ccd03c4 100644 --- a/app/Filament/Widgets/RecentJitterChartWidget.php +++ b/app/Filament/Widgets/RecentJitterChartWidget.php @@ -82,7 +82,7 @@ protected function getOptions(): array return [ 'scales' => [ 'y' => [ - 'beginAtZero' => false, + 'beginAtZero' => config('app.chart_begin_at_zero'), ], ], ]; diff --git a/app/Filament/Widgets/RecentPingChartWidget.php b/app/Filament/Widgets/RecentPingChartWidget.php index 7c142f59a..5233c3abc 100644 --- a/app/Filament/Widgets/RecentPingChartWidget.php +++ b/app/Filament/Widgets/RecentPingChartWidget.php @@ -79,7 +79,7 @@ protected function getOptions(): array ], 'scales' => [ 'y' => [ - 'beginAtZero' => false, + 'beginAtZero' => config('app.chart_begin_at_zero'), ], ], ]; diff --git a/app/Filament/Widgets/RecentUploadChartWidget.php b/app/Filament/Widgets/RecentUploadChartWidget.php index ef24b76e1..3bf0d5ba0 100644 --- a/app/Filament/Widgets/RecentUploadChartWidget.php +++ b/app/Filament/Widgets/RecentUploadChartWidget.php @@ -80,7 +80,7 @@ protected function getOptions(): array ], 'scales' => [ 'y' => [ - 'beginAtZero' => false, + 'beginAtZero' => config('app.chart_begin_at_zero'), ], ], ]; diff --git a/app/Filament/Widgets/RecentUploadLatencyChartWidget.php b/app/Filament/Widgets/RecentUploadLatencyChartWidget.php index 5dcc830e9..9c08663b4 100644 --- a/app/Filament/Widgets/RecentUploadLatencyChartWidget.php +++ b/app/Filament/Widgets/RecentUploadLatencyChartWidget.php @@ -82,7 +82,7 @@ protected function getOptions(): array return [ 'scales' => [ 'y' => [ - 'beginAtZero' => false, + 'beginAtZero' => config('app.chart_begin_at_zero'), ], ], ]; diff --git a/config/app.php b/config/app.php index 2f757b84e..025fa8f90 100644 --- a/config/app.php +++ b/config/app.php @@ -16,4 +16,6 @@ 'chart_time_range' => env('CHART_TIME_RANGE', 7), + 'chart_begin_at_zero' => env('CHART_BEGIN_AT_ZERO', true), + ]; From 1c4a92c6fd64f218988eae0e0efac97d125d6661 Mon Sep 17 00:00:00 2001 From: svenvg93 Date: Thu, 15 Aug 2024 16:11:58 +0200 Subject: [PATCH 10/15] change-env-and_time-ranges --- app/Filament/Pages/Dashboard.php | 27 +------------------ .../Widgets/RecentDownloadChartWidget.php | 2 +- config/app.php | 2 +- 3 files changed, 3 insertions(+), 28 deletions(-) diff --git a/app/Filament/Pages/Dashboard.php b/app/Filament/Pages/Dashboard.php index 1102b2896..da99d0a43 100644 --- a/app/Filament/Pages/Dashboard.php +++ b/app/Filament/Pages/Dashboard.php @@ -46,7 +46,7 @@ public function getSubheading(): ?string public function filtersForm(Form $form): Form { // Retrieve the default number of days from the configuration - $defaultRangeDays = config('app.chart_time_range'); + $defaultRangeDays = config('app.chart_default_date_range'); // Calculate the start and end dates based on the configuration value $defaultEndDate = now(); // Today @@ -59,31 +59,14 @@ public function filtersForm(Form $form): Form Select::make('predefinedRange') ->label('Time Range') ->options([ - '3_hours' => 'Last 3 Hours', - '6_hours' => 'Last 6 Hours', - '12_hours' => 'Last 12 Hours', '24_hours' => 'Last 24 Hours', '1_week' => 'Last 1 Week', '1_month' => 'Last 1 Month', - '3_months' => 'Last 3 Months', - '6_months' => 'Last 6 Months', 'custom' => 'Custom Range', ]) ->reactive() ->afterStateUpdated(function ($state, callable $set) { switch ($state) { - case '3_hours': - $set('startDate', now()->subHours(3)->toDateString()); - $set('endDate', now()->toDateString()); - break; - case '6_hours': - $set('startDate', now()->subHours(6)->toDateString()); - $set('endDate', now()->toDateString()); - break; - case '12_hours': - $set('startDate', now()->subHours(12)->toDateString()); - $set('endDate', now()->toDateString()); - break; case '24_hours': $set('startDate', now()->subDay()->toDateString()); $set('endDate', now()->toDateString()); @@ -96,14 +79,6 @@ public function filtersForm(Form $form): Form $set('startDate', now()->subMonth()->toDateString()); $set('endDate', now()->toDateString()); break; - case '3_months': - $set('startDate', now()->subMonths(3)->toDateString()); - $set('endDate', now()->toDateString()); - break; - case '6_months': - $set('startDate', now()->subMonths(6)->toDateString()); - $set('endDate', now()->toDateString()); - break; case 'custom': break; } diff --git a/app/Filament/Widgets/RecentDownloadChartWidget.php b/app/Filament/Widgets/RecentDownloadChartWidget.php index e50ada7ff..14ed3356b 100644 --- a/app/Filament/Widgets/RecentDownloadChartWidget.php +++ b/app/Filament/Widgets/RecentDownloadChartWidget.php @@ -49,7 +49,7 @@ protected function getData(): array 'borderColor' => 'rgba(14, 165, 233)', 'backgroundColor' => 'rgba(14, 165, 233, 0.1)', // 10% opacity 'pointBackgroundColor' => 'rgba(14, 165, 233)', - 'fill' => config('app.chart_fill_background'), + 'fill' => true, 'cubicInterpolationMode' => 'monotone', 'tension' => 0.4, 'pointRadius' => count($downloads) <= 5 ? 3 : 0, diff --git a/config/app.php b/config/app.php index 025fa8f90..1d98019cf 100644 --- a/config/app.php +++ b/config/app.php @@ -14,7 +14,7 @@ 'force_https' => env('FORCE_HTTPS', false), - 'chart_time_range' => env('CHART_TIME_RANGE', 7), + 'chart_default_date_range' => env('CHART_DEFAULT_DATE_RANGE', 7), 'chart_begin_at_zero' => env('CHART_BEGIN_AT_ZERO', true), From 249340e3198254feafe8bba242790d1f6c6c197b Mon Sep 17 00:00:00 2001 From: svenvg93 Date: Wed, 21 Aug 2024 20:28:21 +0200 Subject: [PATCH 11/15] change_average_to_orange --- app/Filament/Widgets/RecentDownloadChartWidget.php | 4 ++-- app/Filament/Widgets/RecentPingChartWidget.php | 4 ++-- app/Filament/Widgets/RecentUploadChartWidget.php | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/app/Filament/Widgets/RecentDownloadChartWidget.php b/app/Filament/Widgets/RecentDownloadChartWidget.php index 14ed3356b..1a34fecb1 100644 --- a/app/Filament/Widgets/RecentDownloadChartWidget.php +++ b/app/Filament/Widgets/RecentDownloadChartWidget.php @@ -57,8 +57,8 @@ protected function getData(): array [ 'label' => 'Average', 'data' => array_fill(0, count($downloads), $averageDownload), - 'borderColor' => '#ff0000', - 'pointBackgroundColor' => '#ff0000', + 'borderColor' => 'rgb(255, 165, 0)', + 'pointBackgroundColor' => 'rgb(255, 165, 0)', 'fill' => false, 'cubicInterpolationMode' => 'monotone', 'tension' => 0.4, diff --git a/app/Filament/Widgets/RecentPingChartWidget.php b/app/Filament/Widgets/RecentPingChartWidget.php index 5233c3abc..1135c8062 100644 --- a/app/Filament/Widgets/RecentPingChartWidget.php +++ b/app/Filament/Widgets/RecentPingChartWidget.php @@ -56,8 +56,8 @@ protected function getData(): array [ 'label' => 'Average', 'data' => array_fill(0, count($ping), $averagePing), - 'borderColor' => '#ff0000', - 'pointBackgroundColor' => '#ff0000', + 'borderColor' => 'rgb(255, 165, 0)', + 'pointBackgroundColor' => 'rgb(255, 165, 0)', 'fill' => false, 'cubicInterpolationMode' => 'monotone', 'tension' => 0.4, diff --git a/app/Filament/Widgets/RecentUploadChartWidget.php b/app/Filament/Widgets/RecentUploadChartWidget.php index 3bf0d5ba0..7cf40e16c 100644 --- a/app/Filament/Widgets/RecentUploadChartWidget.php +++ b/app/Filament/Widgets/RecentUploadChartWidget.php @@ -57,8 +57,8 @@ protected function getData(): array [ 'label' => 'Average', 'data' => array_fill(0, count($upload), $averageUpload), - 'borderColor' => '#ff0000', - 'pointBackgroundColor' => '#ff0000', + 'borderColor' => 'rgb(255, 165, 0)', + 'pointBackgroundColor' => 'rgb(255, 165, 0)', 'fill' => false, 'cubicInterpolationMode' => 'monotone', 'tension' => 0.4, From 68389f1105d6770335eebbde53b40d4c4fb5462f Mon Sep 17 00:00:00 2001 From: Sven van Ginkel Date: Wed, 21 Aug 2024 21:14:18 +0200 Subject: [PATCH 12/15] Revert "Add failed and thresholds" --- app/Filament/Pages/Dashboard.php | 80 +------------------ .../Widgets/RecentDownloadChartWidget.php | 57 ++++++------- .../RecentDownloadLatencyChartWidget.php | 65 ++++++++------- .../Widgets/RecentJitterChartWidget.php | 65 ++++++++------- .../Widgets/RecentPingChartWidget.php | 60 ++++++-------- .../Widgets/RecentUploadChartWidget.php | 57 ++++++------- .../RecentUploadLatencyChartWidget.php | 65 ++++++++------- config/app.php | 4 - .../views/filament/pages/dashboard.blade.php | 3 + 9 files changed, 192 insertions(+), 264 deletions(-) create mode 100644 resources/views/filament/pages/dashboard.blade.php diff --git a/app/Filament/Pages/Dashboard.php b/app/Filament/Pages/Dashboard.php index da99d0a43..3737cf9bf 100644 --- a/app/Filament/Pages/Dashboard.php +++ b/app/Filament/Pages/Dashboard.php @@ -14,22 +14,17 @@ use Cron\CronExpression; use Filament\Actions\Action; use Filament\Actions\ActionGroup; -use Filament\Forms; -use Filament\Forms\Components\DatePicker; -use Filament\Forms\Components\Select; -use Filament\Forms\Form; use Filament\Notifications\Notification; -use Filament\Pages\Dashboard as BaseDashboard; -use Filament\Pages\Dashboard\Concerns\HasFiltersForm; +use Filament\Pages\Dashboard as BasePage; use Filament\Support\Enums\IconPosition; use Illuminate\Support\Arr; -class Dashboard extends BaseDashboard +class Dashboard extends BasePage { - use HasFiltersForm; - protected static ?string $navigationIcon = 'heroicon-o-chart-bar'; + protected static string $view = 'filament.pages.dashboard'; + public function getSubheading(): ?string { if (blank(config('speedtest.schedule'))) { @@ -43,67 +38,6 @@ public function getSubheading(): ?string return 'Next speedtest at: '.$nextRunDate; } - public function filtersForm(Form $form): Form - { - // Retrieve the default number of days from the configuration - $defaultRangeDays = config('app.chart_default_date_range'); - - // Calculate the start and end dates based on the configuration value - $defaultEndDate = now(); // Today - $defaultStartDate = now()->subDays($defaultRangeDays); // Start date for the range - - return $form - ->schema([ - Forms\Components\Section::make() - ->schema([ - Select::make('predefinedRange') - ->label('Time Range') - ->options([ - '24_hours' => 'Last 24 Hours', - '1_week' => 'Last 1 Week', - '1_month' => 'Last 1 Month', - 'custom' => 'Custom Range', - ]) - ->reactive() - ->afterStateUpdated(function ($state, callable $set) { - switch ($state) { - case '24_hours': - $set('startDate', now()->subDay()->toDateString()); - $set('endDate', now()->toDateString()); - break; - case '1_week': - $set('startDate', now()->subWeek()->toDateString()); - $set('endDate', now()->toDateString()); - break; - case '1_month': - $set('startDate', now()->subMonth()->toDateString()); - $set('endDate', now()->toDateString()); - break; - case 'custom': - break; - } - }) - ->default('custom'), - - DatePicker::make('startDate') - ->label('Start Date') - ->default($defaultStartDate->toDateString()) - ->reactive() - ->hidden(fn ($get) => $get('predefinedRange') !== 'custom'), - - DatePicker::make('endDate') - ->label('End Date') - ->default($defaultEndDate->toDateString()) - ->reactive() - ->hidden(fn ($get) => $get('predefinedRange') !== 'custom'), - ]) - ->columns([ - 'default' => 1, - 'sm' => 3, - ]), - ]); - } - protected function getHeaderActions(): array { return [ @@ -149,12 +83,6 @@ protected function getHeaderWidgets(): array { return [ StatsOverviewWidget::make(), - ]; - } - - public function getWidgets(): array - { - return [ RecentDownloadChartWidget::make(), RecentUploadChartWidget::make(), RecentPingChartWidget::make(), diff --git a/app/Filament/Widgets/RecentDownloadChartWidget.php b/app/Filament/Widgets/RecentDownloadChartWidget.php index 1a34fecb1..7aca1d1df 100644 --- a/app/Filament/Widgets/RecentDownloadChartWidget.php +++ b/app/Filament/Widgets/RecentDownloadChartWidget.php @@ -6,64 +6,59 @@ use App\Helpers\Number; use App\Models\Result; use Filament\Widgets\ChartWidget; -use Filament\Widgets\Concerns\InteractsWithPageFilters; -use Illuminate\Database\Eloquent\Builder; class RecentDownloadChartWidget extends ChartWidget { - use InteractsWithPageFilters; - protected static ?string $heading = 'Download (Mbps)'; protected int|string|array $columnSpan = 'full'; protected static ?string $maxHeight = '250px'; + public ?string $filter = '24h'; + protected function getPollingInterval(): ?string { return config('speedtest.dashboard_polling'); } - protected function getData(): array + protected function getFilters(): ?array { + return [ + '24h' => 'Last 24h', + 'week' => 'Last week', + 'month' => 'Last month', + ]; + } - $startDate = $this->filters['startDate'] ?? now()->subWeek(); - $endDate = $this->filters['endDate'] ?? now(); - + protected function getData(): array + { $results = Result::query() ->select(['id', 'download', 'created_at']) ->where('status', '=', ResultStatus::Completed) - ->when($startDate, fn (Builder $query) => $query->whereDate('created_at', '>=', $startDate)) - ->when($endDate, fn (Builder $query) => $query->whereDate('created_at', '<=', $endDate)) + ->when($this->filter == '24h', function ($query) { + $query->where('created_at', '>=', now()->subDay()); + }) + ->when($this->filter == 'week', function ($query) { + $query->where('created_at', '>=', now()->subWeek()); + }) + ->when($this->filter == 'month', function ($query) { + $query->where('created_at', '>=', now()->subMonth()); + }) ->orderBy('created_at') ->get(); - $downloads = $results->map(fn ($item) => ! blank($item->download) ? Number::bitsToMagnitude(bits: $item->download_bits, precision: 2, magnitude: 'mbit') : 0); - $averageDownload = $downloads->avg(); - return [ 'datasets' => [ [ 'label' => 'Download', - 'data' => $downloads, - 'borderColor' => 'rgba(14, 165, 233)', - 'backgroundColor' => 'rgba(14, 165, 233, 0.1)', // 10% opacity - 'pointBackgroundColor' => 'rgba(14, 165, 233)', - 'fill' => true, - 'cubicInterpolationMode' => 'monotone', - 'tension' => 0.4, - 'pointRadius' => count($downloads) <= 5 ? 3 : 0, - ], - [ - 'label' => 'Average', - 'data' => array_fill(0, count($downloads), $averageDownload), - 'borderColor' => 'rgb(255, 165, 0)', - 'pointBackgroundColor' => 'rgb(255, 165, 0)', + 'data' => $results->map(fn ($item) => ! blank($item->download) ? Number::bitsToMagnitude(bits: $item->download_bits, precision: 2, magnitude: 'mbit') : 0), + 'borderColor' => '#0ea5e9', + 'backgroundColor' => '#0ea5e9', + 'pointBackgroundColor' => '#0ea5e9', 'fill' => false, 'cubicInterpolationMode' => 'monotone', 'tension' => 0.4, - 'borderDash' => [5, 5], - 'pointRadius' => 0, ], ], 'labels' => $results->map(fn ($item) => $item->created_at->timezone(config('app.display_timezone'))->format(config('app.chart_datetime_format'))), @@ -75,12 +70,12 @@ protected function getOptions(): array return [ 'plugins' => [ 'legend' => [ - 'display' => true, + 'display' => false, ], ], 'scales' => [ 'y' => [ - 'beginAtZero' => config('app.chart_begin_at_zero'), + 'beginAtZero' => true, ], ], ]; diff --git a/app/Filament/Widgets/RecentDownloadLatencyChartWidget.php b/app/Filament/Widgets/RecentDownloadLatencyChartWidget.php index da69c1199..c7bb0e05a 100644 --- a/app/Filament/Widgets/RecentDownloadLatencyChartWidget.php +++ b/app/Filament/Widgets/RecentDownloadLatencyChartWidget.php @@ -5,35 +5,45 @@ use App\Enums\ResultStatus; use App\Models\Result; use Filament\Widgets\ChartWidget; -use Filament\Widgets\Concerns\InteractsWithPageFilters; -use Illuminate\Database\Eloquent\Builder; class RecentDownloadLatencyChartWidget extends ChartWidget { - use InteractsWithPageFilters; - protected static ?string $heading = 'Download Latency'; protected int|string|array $columnSpan = 'full'; protected static ?string $maxHeight = '250px'; + public ?string $filter = '24h'; + protected function getPollingInterval(): ?string { return config('speedtest.dashboard_polling'); } - protected function getData(): array + protected function getFilters(): ?array { + return [ + '24h' => 'Last 24h', + 'week' => 'Last week', + 'month' => 'Last month', + ]; + } - $startDate = $this->filters['startDate'] ?? now()->subWeek(); - $endDate = $this->filters['endDate'] ?? now(); - + protected function getData(): array + { $results = Result::query() ->select(['id', 'data', 'created_at']) ->where('status', '=', ResultStatus::Completed) - ->when($startDate, fn (Builder $query) => $query->whereDate('created_at', '>=', $startDate)) - ->when($endDate, fn (Builder $query) => $query->whereDate('created_at', '<=', $endDate)) + ->when($this->filter == '24h', function ($query) { + $query->where('created_at', '>=', now()->subDay()); + }) + ->when($this->filter == 'week', function ($query) { + $query->where('created_at', '>=', now()->subWeek()); + }) + ->when($this->filter == 'month', function ($query) { + $query->where('created_at', '>=', now()->subMonth()); + }) ->orderBy('created_at') ->get(); @@ -41,36 +51,33 @@ protected function getData(): array 'datasets' => [ [ 'label' => 'Average (ms)', - 'data' => $averageData = $results->map(fn ($item) => $item->download_latency_iqm ? number_format($item->download_latency_iqm, 2) : 0), - 'borderColor' => 'rgba(16, 185, 129)', - 'backgroundColor' => 'rgba(16, 185, 129, 0.1)', - 'pointBackgroundColor' => 'rgba(16, 185, 129)', - 'fill' => true, + 'data' => $results->map(fn ($item) => $item->download_latency_iqm ? number_format($item->download_latency_iqm, 2) : 0), + 'borderColor' => '#10b981', + 'backgroundColor' => '#10b981', + 'pointBackgroundColor' => '#10b981', + 'fill' => false, 'cubicInterpolationMode' => 'monotone', 'tension' => 0.4, - 'pointRadius' => $averageData->count() <= 5 ? 3 : 0, ], [ 'label' => 'High (ms)', - 'data' => $highData = $results->map(fn ($item) => $item->download_latency_high ? number_format($item->download_latency_high, 2) : 0), - 'borderColor' => 'rgba(14, 165, 233)', - 'backgroundColor' => 'rgba(14, 165, 233, 0.1)', - 'pointBackgroundColor' => 'rgba(14, 165, 233)', - 'fill' => true, + 'data' => $results->map(fn ($item) => $item->download_latency_high ? number_format($item->download_latency_high, 2) : 0), + 'borderColor' => '#0ea5e9', + 'backgroundColor' => '#0ea5e9', + 'pointBackgroundColor' => '#0ea5e9', + 'fill' => false, 'cubicInterpolationMode' => 'monotone', 'tension' => 0.4, - 'pointRadius' => $highData->count() <= 5 ? 3 : 0, ], [ 'label' => 'Low (ms)', - 'data' => $lowData = $results->map(fn ($item) => $item->download_latency_low ? number_format($item->download_latency_low, 2) : 0), - 'borderColor' => 'rgba(139, 92, 246)', - 'backgroundColor' => 'rgba(139, 92, 246, 0.1)', - 'pointBackgroundColor' => 'rgba(139, 92, 246)', - 'fill' => true, + 'data' => $results->map(fn ($item) => $item->download_latency_low ? number_format($item->download_latency_low, 2) : 0), + 'borderColor' => '#8b5cf6', + 'backgroundColor' => '#8b5cf6', + 'pointBackgroundColor' => '#8b5cf6', + 'fill' => false, 'cubicInterpolationMode' => 'monotone', 'tension' => 0.4, - 'pointRadius' => $lowData->count() <= 5 ? 3 : 0, ], ], 'labels' => $results->map(fn ($item) => $item->created_at->timezone(config('app.display_timezone'))->format(config('app.chart_datetime_format'))), @@ -82,7 +89,7 @@ protected function getOptions(): array return [ 'scales' => [ 'y' => [ - 'beginAtZero' => config('app.chart_begin_at_zero'), + 'beginAtZero' => true, ], ], ]; diff --git a/app/Filament/Widgets/RecentJitterChartWidget.php b/app/Filament/Widgets/RecentJitterChartWidget.php index 70ccd03c4..2d2454862 100644 --- a/app/Filament/Widgets/RecentJitterChartWidget.php +++ b/app/Filament/Widgets/RecentJitterChartWidget.php @@ -5,35 +5,45 @@ use App\Enums\ResultStatus; use App\Models\Result; use Filament\Widgets\ChartWidget; -use Filament\Widgets\Concerns\InteractsWithPageFilters; -use Illuminate\Database\Eloquent\Builder; class RecentJitterChartWidget extends ChartWidget { - use InteractsWithPageFilters; - protected static ?string $heading = 'Jitter'; protected int|string|array $columnSpan = 'full'; protected static ?string $maxHeight = '250px'; + public ?string $filter = '24h'; + protected function getPollingInterval(): ?string { return config('speedtest.dashboard_polling'); } - protected function getData(): array + protected function getFilters(): ?array { + return [ + '24h' => 'Last 24h', + 'week' => 'Last week', + 'month' => 'Last month', + ]; + } - $startDate = $this->filters['startDate'] ?? now()->subWeek(); - $endDate = $this->filters['endDate'] ?? now(); - + protected function getData(): array + { $results = Result::query() ->select(['id', 'data', 'created_at']) ->where('status', '=', ResultStatus::Completed) - ->when($startDate, fn (Builder $query) => $query->whereDate('created_at', '>=', $startDate)) - ->when($endDate, fn (Builder $query) => $query->whereDate('created_at', '<=', $endDate)) + ->when($this->filter == '24h', function ($query) { + $query->where('created_at', '>=', now()->subDay()); + }) + ->when($this->filter == 'week', function ($query) { + $query->where('created_at', '>=', now()->subWeek()); + }) + ->when($this->filter == 'month', function ($query) { + $query->where('created_at', '>=', now()->subMonth()); + }) ->orderBy('created_at') ->get(); @@ -41,36 +51,33 @@ protected function getData(): array 'datasets' => [ [ 'label' => 'Download (ms)', - 'data' => $downloadData = $results->map(fn ($item) => $item->download_jitter ? number_format($item->download_jitter, 2) : 0), - 'borderColor' => 'rgba(14, 165, 233)', - 'backgroundColor' => 'rgba(14, 165, 233, 0.1)', - 'pointBackgroundColor' => 'rgba(14, 165, 233)', - 'fill' => true, + 'data' => $results->map(fn ($item) => $item->download_jitter ? number_format($item->download_jitter, 2) : 0), + 'borderColor' => '#0ea5e9', + 'backgroundColor' => '#0ea5e9', + 'pointBackgroundColor' => '#0ea5e9', + 'fill' => false, 'cubicInterpolationMode' => 'monotone', 'tension' => 0.4, - 'pointRadius' => $downloadData->count() <= 5 ? 3 : 0, ], [ 'label' => 'Upload (ms)', - 'data' => $uploadData = $results->map(fn ($item) => $item->upload_jitter ? number_format($item->upload_jitter, 2) : 0), - 'borderColor' => 'rgba(139, 92, 246)', - 'backgroundColor' => 'rgba(139, 92, 246, 0.1)', - 'pointBackgroundColor' => 'rgba(139, 92, 246)', - 'fill' => true, + 'data' => $results->map(fn ($item) => $item->upload_jitter ? number_format($item->upload_jitter, 2) : 0), + 'borderColor' => '#8b5cf6', + 'backgroundColor' => '#8b5cf6', + 'pointBackgroundColor' => '#8b5cf6', + 'fill' => false, 'cubicInterpolationMode' => 'monotone', 'tension' => 0.4, - 'pointRadius' => $uploadData->count() <= 5 ? 3 : 0, ], [ 'label' => 'Ping (ms)', - 'data' => $pingData = $results->map(fn ($item) => $item->ping_jitter ? number_format($item->ping_jitter, 2) : 0), - 'borderColor' => 'rgba(16, 185, 129)', - 'backgroundColor' => 'rgba(16, 185, 129, 0.1)', - 'pointBackgroundColor' => 'rgba(16, 185, 129)', - 'fill' => true, + 'data' => $results->map(fn ($item) => $item->ping_jitter ? number_format($item->ping_jitter, 2) : 0), + 'borderColor' => '#10b981', + 'backgroundColor' => '#10b981', + 'pointBackgroundColor' => '#10b981', + 'fill' => false, 'cubicInterpolationMode' => 'monotone', 'tension' => 0.4, - 'pointRadius' => $pingData->count() <= 5 ? 3 : 0, ], ], 'labels' => $results->map(fn ($item) => $item->created_at->timezone(config('app.display_timezone'))->format(config('app.chart_datetime_format'))), @@ -82,7 +89,7 @@ protected function getOptions(): array return [ 'scales' => [ 'y' => [ - 'beginAtZero' => config('app.chart_begin_at_zero'), + 'beginAtZero' => true, ], ], ]; diff --git a/app/Filament/Widgets/RecentPingChartWidget.php b/app/Filament/Widgets/RecentPingChartWidget.php index 1135c8062..57a10eee5 100644 --- a/app/Filament/Widgets/RecentPingChartWidget.php +++ b/app/Filament/Widgets/RecentPingChartWidget.php @@ -5,64 +5,59 @@ use App\Enums\ResultStatus; use App\Models\Result; use Filament\Widgets\ChartWidget; -use Filament\Widgets\Concerns\InteractsWithPageFilters; -use Illuminate\Database\Eloquent\Builder; class RecentPingChartWidget extends ChartWidget { - use InteractsWithPageFilters; - protected static ?string $heading = 'Ping (ms)'; protected int|string|array $columnSpan = 'full'; protected static ?string $maxHeight = '250px'; + public ?string $filter = '24h'; + protected function getPollingInterval(): ?string { return config('speedtest.dashboard_polling'); } - protected function getData(): array + protected function getFilters(): ?array { + return [ + '24h' => 'Last 24h', + 'week' => 'Last week', + 'month' => 'Last month', + ]; + } - $startDate = $this->filters['startDate'] ?? now()->subWeek(); - $endDate = $this->filters['endDate'] ?? now(); - + protected function getData(): array + { $results = Result::query() ->select(['id', 'ping', 'created_at']) ->where('status', '=', ResultStatus::Completed) - ->when($startDate, fn (Builder $query) => $query->whereDate('created_at', '>=', $startDate)) - ->when($endDate, fn (Builder $query) => $query->whereDate('created_at', '<=', $endDate)) + ->when($this->filter == '24h', function ($query) { + $query->where('created_at', '>=', now()->subDay()); + }) + ->when($this->filter == 'week', function ($query) { + $query->where('created_at', '>=', now()->subWeek()); + }) + ->when($this->filter == 'month', function ($query) { + $query->where('created_at', '>=', now()->subMonth()); + }) ->orderBy('created_at') ->get(); - $ping = $results->map(fn ($item) => ! blank($item->ping) ? number_format($item->ping, 2) : 0); - $averagePing = $ping->avg(); - return [ 'datasets' => [ [ 'label' => 'Ping (ms)', - 'data' => $ping, - 'borderColor' => 'rgba(16, 185, 129)', - 'backgroundColor' => 'rgba(16, 185, 129, 0.1)', - 'pointBackgroundColor' => 'rgba(16, 185, 129)', - 'fill' => true, - 'cubicInterpolationMode' => 'monotone', - 'tension' => 0.4, - 'pointRadius' => count($ping) <= 5 ? 3 : 0, - ], - [ - 'label' => 'Average', - 'data' => array_fill(0, count($ping), $averagePing), - 'borderColor' => 'rgb(255, 165, 0)', - 'pointBackgroundColor' => 'rgb(255, 165, 0)', + 'data' => $results->map(fn ($item) => ! blank($item->ping) ? number_format($item->ping, 2) : 0), + 'borderColor' => '#10b981', + 'backgroundColor' => '#10b981', + 'pointBackgroundColor' => '#10b981', 'fill' => false, 'cubicInterpolationMode' => 'monotone', 'tension' => 0.4, - 'borderDash' => [5, 5], - 'pointRadius' => 0, ], ], 'labels' => $results->map(fn ($item) => $item->created_at->timezone(config('app.display_timezone'))->format(config('app.chart_datetime_format'))), @@ -72,14 +67,9 @@ protected function getData(): array protected function getOptions(): array { return [ - 'plugins' => [ - 'legend' => [ - 'display' => true, - ], - ], 'scales' => [ 'y' => [ - 'beginAtZero' => config('app.chart_begin_at_zero'), + 'beginAtZero' => true, ], ], ]; diff --git a/app/Filament/Widgets/RecentUploadChartWidget.php b/app/Filament/Widgets/RecentUploadChartWidget.php index 7cf40e16c..5c9c85baf 100644 --- a/app/Filament/Widgets/RecentUploadChartWidget.php +++ b/app/Filament/Widgets/RecentUploadChartWidget.php @@ -6,64 +6,59 @@ use App\Helpers\Number; use App\Models\Result; use Filament\Widgets\ChartWidget; -use Filament\Widgets\Concerns\InteractsWithPageFilters; -use Illuminate\Database\Eloquent\Builder; class RecentUploadChartWidget extends ChartWidget { - use InteractsWithPageFilters; - protected static ?string $heading = 'Upload (Mbps)'; protected int|string|array $columnSpan = 'full'; protected static ?string $maxHeight = '250px'; + public ?string $filter = '24h'; + protected function getPollingInterval(): ?string { return config('speedtest.dashboard_polling'); } - protected function getData(): array + protected function getFilters(): ?array { + return [ + '24h' => 'Last 24h', + 'week' => 'Last week', + 'month' => 'Last month', + ]; + } - $startDate = $this->filters['startDate'] ?? now()->subWeek(); - $endDate = $this->filters['endDate'] ?? now(); - + protected function getData(): array + { $results = Result::query() ->select(['id', 'upload', 'created_at']) ->where('status', '=', ResultStatus::Completed) - ->when($startDate, fn (Builder $query) => $query->whereDate('created_at', '>=', $startDate)) - ->when($endDate, fn (Builder $query) => $query->whereDate('created_at', '<=', $endDate)) + ->when($this->filter == '24h', function ($query) { + $query->where('created_at', '>=', now()->subDay()); + }) + ->when($this->filter == 'week', function ($query) { + $query->where('created_at', '>=', now()->subWeek()); + }) + ->when($this->filter == 'month', function ($query) { + $query->where('created_at', '>=', now()->subMonth()); + }) ->orderBy('created_at') ->get(); - $upload = $results->map(fn ($item) => ! blank($item->upload) ? Number::bitsToMagnitude(bits: $item->upload_bits, precision: 2, magnitude: 'mbit') : 0); - $averageUpload = $upload->avg(); - return [ 'datasets' => [ [ 'label' => 'Upload', - 'data' => $upload, - 'borderColor' => 'rgba(139, 92, 246)', - 'backgroundColor' => 'rgba(139, 92, 246, 0.1)', - 'pointBackgroundColor' => 'rgba(139, 92, 246)', - 'fill' => true, - 'cubicInterpolationMode' => 'monotone', - 'tension' => 0.4, - 'pointRadius' => count($upload) <= 5 ? 3 : 0, - ], - [ - 'label' => 'Average', - 'data' => array_fill(0, count($upload), $averageUpload), - 'borderColor' => 'rgb(255, 165, 0)', - 'pointBackgroundColor' => 'rgb(255, 165, 0)', + 'data' => $results->map(fn ($item) => ! blank($item->upload) ? Number::bitsToMagnitude(bits: $item->upload_bits, precision: 2, magnitude: 'mbit') : 0), + 'borderColor' => '#8b5cf6', + 'backgroundColor' => '#8b5cf6', + 'pointBackgroundColor' => '#8b5cf6', 'fill' => false, 'cubicInterpolationMode' => 'monotone', 'tension' => 0.4, - 'borderDash' => [5, 5], - 'pointRadius' => 0, ], ], 'labels' => $results->map(fn ($item) => $item->created_at->timezone(config('app.display_timezone'))->format(config('app.chart_datetime_format'))), @@ -75,12 +70,12 @@ protected function getOptions(): array return [ 'plugins' => [ 'legend' => [ - 'display' => true, + 'display' => false, ], ], 'scales' => [ 'y' => [ - 'beginAtZero' => config('app.chart_begin_at_zero'), + 'beginAtZero' => true, ], ], ]; diff --git a/app/Filament/Widgets/RecentUploadLatencyChartWidget.php b/app/Filament/Widgets/RecentUploadLatencyChartWidget.php index 9c08663b4..049055adc 100644 --- a/app/Filament/Widgets/RecentUploadLatencyChartWidget.php +++ b/app/Filament/Widgets/RecentUploadLatencyChartWidget.php @@ -5,35 +5,45 @@ use App\Enums\ResultStatus; use App\Models\Result; use Filament\Widgets\ChartWidget; -use Filament\Widgets\Concerns\InteractsWithPageFilters; -use Illuminate\Database\Eloquent\Builder; class RecentUploadLatencyChartWidget extends ChartWidget { - use InteractsWithPageFilters; - protected static ?string $heading = 'Upload Latency'; protected int|string|array $columnSpan = 'full'; protected static ?string $maxHeight = '250px'; + public ?string $filter = '24h'; + protected function getPollingInterval(): ?string { return config('speedtest.dashboard_polling'); } - protected function getData(): array + protected function getFilters(): ?array { + return [ + '24h' => 'Last 24h', + 'week' => 'Last week', + 'month' => 'Last month', + ]; + } - $startDate = $this->filters['startDate'] ?? now()->subWeek(); - $endDate = $this->filters['endDate'] ?? now(); - + protected function getData(): array + { $results = Result::query() ->select(['id', 'data', 'created_at']) ->where('status', '=', ResultStatus::Completed) - ->when($startDate, fn (Builder $query) => $query->whereDate('created_at', '>=', $startDate)) - ->when($endDate, fn (Builder $query) => $query->whereDate('created_at', '<=', $endDate)) + ->when($this->filter == '24h', function ($query) { + $query->where('created_at', '>=', now()->subDay()); + }) + ->when($this->filter == 'week', function ($query) { + $query->where('created_at', '>=', now()->subWeek()); + }) + ->when($this->filter == 'month', function ($query) { + $query->where('created_at', '>=', now()->subMonth()); + }) ->orderBy('created_at') ->get(); @@ -41,36 +51,33 @@ protected function getData(): array 'datasets' => [ [ 'label' => 'Average (ms)', - 'data' => $averageData = $results->map(fn ($item) => $item->upload_latency_iqm ? number_format($item->upload_latency_iqm, 2) : 0), - 'borderColor' => 'rgba(16, 185, 129)', - 'backgroundColor' => 'rgba(16, 185, 129, 0.1)', - 'pointBackgroundColor' => 'rgba(16, 185, 129)', - 'fill' => true, + 'data' => $results->map(fn ($item) => $item->upload_latency_iqm ? number_format($item->upload_latency_iqm, 2) : 0), + 'borderColor' => '#10b981', + 'backgroundColor' => '#10b981', + 'pointBackgroundColor' => '#10b981', + 'fill' => false, 'cubicInterpolationMode' => 'monotone', 'tension' => 0.4, - 'pointRadius' => $averageData->count() <= 5 ? 3 : 0, ], [ 'label' => 'High (ms)', - 'data' => $highData = $results->map(fn ($item) => $item->upload_latency_high ? number_format($item->upload_latency_high, 2) : 0), - 'borderColor' => 'rgba(14, 165, 233)', - 'backgroundColor' => 'rgba(14, 165, 233, 0.1)', - 'pointBackgroundColor' => 'rgba(14, 165, 233)', - 'fill' => true, + 'data' => $results->map(fn ($item) => $item->upload_latency_high ? number_format($item->upload_latency_high, 2) : 0), + 'borderColor' => '#0ea5e9', + 'backgroundColor' => '#0ea5e9', + 'pointBackgroundColor' => '#0ea5e9', + 'fill' => false, 'cubicInterpolationMode' => 'monotone', 'tension' => 0.4, - 'pointRadius' => $highData->count() <= 5 ? 3 : 0, ], [ 'label' => 'Low (ms)', - 'data' => $lowData = $results->map(fn ($item) => $item->upload_latency_low ? number_format($item->upload_latency_low, 2) : 0), - 'borderColor' => 'rgba(139, 92, 246)', - 'backgroundColor' => 'rgba(139, 92, 246, 0.1)', - 'pointBackgroundColor' => 'rgba(139, 92, 246)', - 'fill' => true, + 'data' => $results->map(fn ($item) => $item->upload_latency_low ? number_format($item->upload_latency_low, 2) : 0), + 'borderColor' => '#8b5cf6', + 'backgroundColor' => '#8b5cf6', + 'pointBackgroundColor' => '#8b5cf6', + 'fill' => false, 'cubicInterpolationMode' => 'monotone', 'tension' => 0.4, - 'pointRadius' => $lowData->count() <= 5 ? 3 : 0, ], ], 'labels' => $results->map(fn ($item) => $item->created_at->timezone(config('app.display_timezone'))->format(config('app.chart_datetime_format'))), @@ -82,7 +89,7 @@ protected function getOptions(): array return [ 'scales' => [ 'y' => [ - 'beginAtZero' => config('app.chart_begin_at_zero'), + 'beginAtZero' => true, ], ], ]; diff --git a/config/app.php b/config/app.php index 1d98019cf..60b38f700 100644 --- a/config/app.php +++ b/config/app.php @@ -14,8 +14,4 @@ 'force_https' => env('FORCE_HTTPS', false), - 'chart_default_date_range' => env('CHART_DEFAULT_DATE_RANGE', 7), - - 'chart_begin_at_zero' => env('CHART_BEGIN_AT_ZERO', true), - ]; diff --git a/resources/views/filament/pages/dashboard.blade.php b/resources/views/filament/pages/dashboard.blade.php new file mode 100644 index 000000000..f351a1c97 --- /dev/null +++ b/resources/views/filament/pages/dashboard.blade.php @@ -0,0 +1,3 @@ + + {{-- Silence is golden --}} + From d09fc4adf076cfa4a76d11196af3c4ca369278a0 Mon Sep 17 00:00:00 2001 From: svenvg93 Date: Mon, 23 Sep 2024 22:45:54 +0200 Subject: [PATCH 13/15] letsgo --- .phpstorm.meta.php | 22 +-- .../SendGotifyTestNotification.php | 42 ++++-- .../SendNtfyTestNotification.php | 62 +++++--- .../Pages/Settings/NotificationPage.php | 24 ++- .../SendSpeedtestCompletedNotification.php | 56 ++++--- .../SendSpeedtestThresholdNotification.php | 83 +++++------ .../SendSpeedtestCompletedNotification.php | 72 +++++---- .../SendSpeedtestThresholdNotification.php | 139 ++++++------------ .../SpeedtestCompletedNotificationPayload.php | 30 ++++ .../SpeedtestThresholdNotificationPayload.php | 83 +++++++++++ composer.json | 4 +- composer.lock | 106 ++++++++++++- .../speedtest-completed.blade.php | 13 ++ .../speedtest-threshold.blade.php | 9 ++ .../views/ntfy/speedtest-completed.blade.php | 13 -- .../views/ntfy/speedtest-threshold.blade.php | 9 -- 16 files changed, 499 insertions(+), 268 deletions(-) create mode 100644 app/Services/SpeedtestCompletedNotificationPayload.php create mode 100644 app/Services/SpeedtestThresholdNotificationPayload.php create mode 100644 resources/views/notifications/speedtest-completed.blade.php create mode 100644 resources/views/notifications/speedtest-threshold.blade.php delete mode 100644 resources/views/ntfy/speedtest-completed.blade.php delete mode 100644 resources/views/ntfy/speedtest-threshold.blade.php diff --git a/.phpstorm.meta.php b/.phpstorm.meta.php index dbf185899..b33e7cfeb 100644 --- a/.phpstorm.meta.php +++ b/.phpstorm.meta.php @@ -52,7 +52,7 @@ 'Illuminate\Console\Scheduling\ScheduleTestCommand' => \Illuminate\Console\Scheduling\ScheduleTestCommand::class, 'Illuminate\Console\Scheduling\ScheduleWorkCommand' => \Illuminate\Console\Scheduling\ScheduleWorkCommand::class, 'Illuminate\Contracts\Auth\Access\Gate' => \Illuminate\Auth\Access\Gate::class, - 'Illuminate\Contracts\Broadcasting\Broadcaster' => \Illuminate\Broadcasting\Broadcasters\NullBroadcaster::class, + 'Illuminate\Contracts\Broadcasting\Broadcaster' => \Illuminate\Broadcasting\Broadcasters\LogBroadcaster::class, 'Illuminate\Contracts\Console\Kernel' => \Illuminate\Foundation\Console\Kernel::class, 'Illuminate\Contracts\Debug\ExceptionHandler' => \NunoMaduro\Collision\Adapters\Laravel\ExceptionHandler::class, 'Illuminate\Contracts\Foundation\ExceptionRenderer' => \Spatie\LaravelIgnition\Renderers\IgnitionExceptionRenderer::class, @@ -294,7 +294,7 @@ 'Illuminate\Console\Scheduling\ScheduleTestCommand' => \Illuminate\Console\Scheduling\ScheduleTestCommand::class, 'Illuminate\Console\Scheduling\ScheduleWorkCommand' => \Illuminate\Console\Scheduling\ScheduleWorkCommand::class, 'Illuminate\Contracts\Auth\Access\Gate' => \Illuminate\Auth\Access\Gate::class, - 'Illuminate\Contracts\Broadcasting\Broadcaster' => \Illuminate\Broadcasting\Broadcasters\NullBroadcaster::class, + 'Illuminate\Contracts\Broadcasting\Broadcaster' => \Illuminate\Broadcasting\Broadcasters\LogBroadcaster::class, 'Illuminate\Contracts\Console\Kernel' => \Illuminate\Foundation\Console\Kernel::class, 'Illuminate\Contracts\Debug\ExceptionHandler' => \NunoMaduro\Collision\Adapters\Laravel\ExceptionHandler::class, 'Illuminate\Contracts\Foundation\ExceptionRenderer' => \Spatie\LaravelIgnition\Renderers\IgnitionExceptionRenderer::class, @@ -536,7 +536,7 @@ 'Illuminate\Console\Scheduling\ScheduleTestCommand' => \Illuminate\Console\Scheduling\ScheduleTestCommand::class, 'Illuminate\Console\Scheduling\ScheduleWorkCommand' => \Illuminate\Console\Scheduling\ScheduleWorkCommand::class, 'Illuminate\Contracts\Auth\Access\Gate' => \Illuminate\Auth\Access\Gate::class, - 'Illuminate\Contracts\Broadcasting\Broadcaster' => \Illuminate\Broadcasting\Broadcasters\NullBroadcaster::class, + 'Illuminate\Contracts\Broadcasting\Broadcaster' => \Illuminate\Broadcasting\Broadcasters\LogBroadcaster::class, 'Illuminate\Contracts\Console\Kernel' => \Illuminate\Foundation\Console\Kernel::class, 'Illuminate\Contracts\Debug\ExceptionHandler' => \NunoMaduro\Collision\Adapters\Laravel\ExceptionHandler::class, 'Illuminate\Contracts\Foundation\ExceptionRenderer' => \Spatie\LaravelIgnition\Renderers\IgnitionExceptionRenderer::class, @@ -778,7 +778,7 @@ 'Illuminate\Console\Scheduling\ScheduleTestCommand' => \Illuminate\Console\Scheduling\ScheduleTestCommand::class, 'Illuminate\Console\Scheduling\ScheduleWorkCommand' => \Illuminate\Console\Scheduling\ScheduleWorkCommand::class, 'Illuminate\Contracts\Auth\Access\Gate' => \Illuminate\Auth\Access\Gate::class, - 'Illuminate\Contracts\Broadcasting\Broadcaster' => \Illuminate\Broadcasting\Broadcasters\NullBroadcaster::class, + 'Illuminate\Contracts\Broadcasting\Broadcaster' => \Illuminate\Broadcasting\Broadcasters\LogBroadcaster::class, 'Illuminate\Contracts\Console\Kernel' => \Illuminate\Foundation\Console\Kernel::class, 'Illuminate\Contracts\Debug\ExceptionHandler' => \NunoMaduro\Collision\Adapters\Laravel\ExceptionHandler::class, 'Illuminate\Contracts\Foundation\ExceptionRenderer' => \Spatie\LaravelIgnition\Renderers\IgnitionExceptionRenderer::class, @@ -1020,7 +1020,7 @@ 'Illuminate\Console\Scheduling\ScheduleTestCommand' => \Illuminate\Console\Scheduling\ScheduleTestCommand::class, 'Illuminate\Console\Scheduling\ScheduleWorkCommand' => \Illuminate\Console\Scheduling\ScheduleWorkCommand::class, 'Illuminate\Contracts\Auth\Access\Gate' => \Illuminate\Auth\Access\Gate::class, - 'Illuminate\Contracts\Broadcasting\Broadcaster' => \Illuminate\Broadcasting\Broadcasters\NullBroadcaster::class, + 'Illuminate\Contracts\Broadcasting\Broadcaster' => \Illuminate\Broadcasting\Broadcasters\LogBroadcaster::class, 'Illuminate\Contracts\Console\Kernel' => \Illuminate\Foundation\Console\Kernel::class, 'Illuminate\Contracts\Debug\ExceptionHandler' => \NunoMaduro\Collision\Adapters\Laravel\ExceptionHandler::class, 'Illuminate\Contracts\Foundation\ExceptionRenderer' => \Spatie\LaravelIgnition\Renderers\IgnitionExceptionRenderer::class, @@ -1262,7 +1262,7 @@ 'Illuminate\Console\Scheduling\ScheduleTestCommand' => \Illuminate\Console\Scheduling\ScheduleTestCommand::class, 'Illuminate\Console\Scheduling\ScheduleWorkCommand' => \Illuminate\Console\Scheduling\ScheduleWorkCommand::class, 'Illuminate\Contracts\Auth\Access\Gate' => \Illuminate\Auth\Access\Gate::class, - 'Illuminate\Contracts\Broadcasting\Broadcaster' => \Illuminate\Broadcasting\Broadcasters\NullBroadcaster::class, + 'Illuminate\Contracts\Broadcasting\Broadcaster' => \Illuminate\Broadcasting\Broadcasters\LogBroadcaster::class, 'Illuminate\Contracts\Console\Kernel' => \Illuminate\Foundation\Console\Kernel::class, 'Illuminate\Contracts\Debug\ExceptionHandler' => \NunoMaduro\Collision\Adapters\Laravel\ExceptionHandler::class, 'Illuminate\Contracts\Foundation\ExceptionRenderer' => \Spatie\LaravelIgnition\Renderers\IgnitionExceptionRenderer::class, @@ -1504,7 +1504,7 @@ 'Illuminate\Console\Scheduling\ScheduleTestCommand' => \Illuminate\Console\Scheduling\ScheduleTestCommand::class, 'Illuminate\Console\Scheduling\ScheduleWorkCommand' => \Illuminate\Console\Scheduling\ScheduleWorkCommand::class, 'Illuminate\Contracts\Auth\Access\Gate' => \Illuminate\Auth\Access\Gate::class, - 'Illuminate\Contracts\Broadcasting\Broadcaster' => \Illuminate\Broadcasting\Broadcasters\NullBroadcaster::class, + 'Illuminate\Contracts\Broadcasting\Broadcaster' => \Illuminate\Broadcasting\Broadcasters\LogBroadcaster::class, 'Illuminate\Contracts\Console\Kernel' => \Illuminate\Foundation\Console\Kernel::class, 'Illuminate\Contracts\Debug\ExceptionHandler' => \NunoMaduro\Collision\Adapters\Laravel\ExceptionHandler::class, 'Illuminate\Contracts\Foundation\ExceptionRenderer' => \Spatie\LaravelIgnition\Renderers\IgnitionExceptionRenderer::class, @@ -1746,7 +1746,7 @@ 'Illuminate\Console\Scheduling\ScheduleTestCommand' => \Illuminate\Console\Scheduling\ScheduleTestCommand::class, 'Illuminate\Console\Scheduling\ScheduleWorkCommand' => \Illuminate\Console\Scheduling\ScheduleWorkCommand::class, 'Illuminate\Contracts\Auth\Access\Gate' => \Illuminate\Auth\Access\Gate::class, - 'Illuminate\Contracts\Broadcasting\Broadcaster' => \Illuminate\Broadcasting\Broadcasters\NullBroadcaster::class, + 'Illuminate\Contracts\Broadcasting\Broadcaster' => \Illuminate\Broadcasting\Broadcasters\LogBroadcaster::class, 'Illuminate\Contracts\Console\Kernel' => \Illuminate\Foundation\Console\Kernel::class, 'Illuminate\Contracts\Debug\ExceptionHandler' => \NunoMaduro\Collision\Adapters\Laravel\ExceptionHandler::class, 'Illuminate\Contracts\Foundation\ExceptionRenderer' => \Spatie\LaravelIgnition\Renderers\IgnitionExceptionRenderer::class, @@ -1988,7 +1988,7 @@ 'Illuminate\Console\Scheduling\ScheduleTestCommand' => \Illuminate\Console\Scheduling\ScheduleTestCommand::class, 'Illuminate\Console\Scheduling\ScheduleWorkCommand' => \Illuminate\Console\Scheduling\ScheduleWorkCommand::class, 'Illuminate\Contracts\Auth\Access\Gate' => \Illuminate\Auth\Access\Gate::class, - 'Illuminate\Contracts\Broadcasting\Broadcaster' => \Illuminate\Broadcasting\Broadcasters\NullBroadcaster::class, + 'Illuminate\Contracts\Broadcasting\Broadcaster' => \Illuminate\Broadcasting\Broadcasters\LogBroadcaster::class, 'Illuminate\Contracts\Console\Kernel' => \Illuminate\Foundation\Console\Kernel::class, 'Illuminate\Contracts\Debug\ExceptionHandler' => \NunoMaduro\Collision\Adapters\Laravel\ExceptionHandler::class, 'Illuminate\Contracts\Foundation\ExceptionRenderer' => \Spatie\LaravelIgnition\Renderers\IgnitionExceptionRenderer::class, @@ -2230,7 +2230,7 @@ 'Illuminate\Console\Scheduling\ScheduleTestCommand' => \Illuminate\Console\Scheduling\ScheduleTestCommand::class, 'Illuminate\Console\Scheduling\ScheduleWorkCommand' => \Illuminate\Console\Scheduling\ScheduleWorkCommand::class, 'Illuminate\Contracts\Auth\Access\Gate' => \Illuminate\Auth\Access\Gate::class, - 'Illuminate\Contracts\Broadcasting\Broadcaster' => \Illuminate\Broadcasting\Broadcasters\NullBroadcaster::class, + 'Illuminate\Contracts\Broadcasting\Broadcaster' => \Illuminate\Broadcasting\Broadcasters\LogBroadcaster::class, 'Illuminate\Contracts\Console\Kernel' => \Illuminate\Foundation\Console\Kernel::class, 'Illuminate\Contracts\Debug\ExceptionHandler' => \NunoMaduro\Collision\Adapters\Laravel\ExceptionHandler::class, 'Illuminate\Contracts\Foundation\ExceptionRenderer' => \Spatie\LaravelIgnition\Renderers\IgnitionExceptionRenderer::class, @@ -2472,7 +2472,7 @@ 'Illuminate\Console\Scheduling\ScheduleTestCommand' => \Illuminate\Console\Scheduling\ScheduleTestCommand::class, 'Illuminate\Console\Scheduling\ScheduleWorkCommand' => \Illuminate\Console\Scheduling\ScheduleWorkCommand::class, 'Illuminate\Contracts\Auth\Access\Gate' => \Illuminate\Auth\Access\Gate::class, - 'Illuminate\Contracts\Broadcasting\Broadcaster' => \Illuminate\Broadcasting\Broadcasters\NullBroadcaster::class, + 'Illuminate\Contracts\Broadcasting\Broadcaster' => \Illuminate\Broadcasting\Broadcasters\LogBroadcaster::class, 'Illuminate\Contracts\Console\Kernel' => \Illuminate\Foundation\Console\Kernel::class, 'Illuminate\Contracts\Debug\ExceptionHandler' => \NunoMaduro\Collision\Adapters\Laravel\ExceptionHandler::class, 'Illuminate\Contracts\Foundation\ExceptionRenderer' => \Spatie\LaravelIgnition\Renderers\IgnitionExceptionRenderer::class, diff --git a/app/Actions/Notifications/SendGotifyTestNotification.php b/app/Actions/Notifications/SendGotifyTestNotification.php index fdd6405de..7a261ce2a 100644 --- a/app/Actions/Notifications/SendGotifyTestNotification.php +++ b/app/Actions/Notifications/SendGotifyTestNotification.php @@ -3,34 +3,54 @@ namespace App\Actions\Notifications; use Filament\Notifications\Notification; +use Gotify\Auth\Token; +use Gotify\Endpoint\Message; +use Gotify\Exception\EndpointException; +use Gotify\Exception\GotifyException; +use Gotify\Server; use Lorisleiva\Actions\Concerns\AsAction; -use Spatie\WebhookServer\WebhookCall; class SendGotifyTestNotification { use AsAction; - public function handle(array $webhooks) + public function handle(array $webhooks, string $token) { - if (! count($webhooks)) { + if (empty($webhooks)) { Notification::make() - ->title('You need to add Gotify urls!') + ->title('You need to add Gotify URLs!') ->warning() ->send(); return; } - foreach ($webhooks as $webhook) { - WebhookCall::create() - ->url($webhook['url']) - ->payload(['message' => '👋 Testing the Gotify notification channel.']) - ->doNotSign() - ->dispatch(); + foreach ($webhooks as $url) { + try { + // Set up the server and token + $server = new Server($url); + $auth = new Token($token); + $message = new Message($server, $auth); + + // Send message + $details = $message->create( + title: 'Test Notification', + message: '👋 Testing the Gotify notification channel', + ); + + // Optionally, you can log the sent message details + // echo 'Id: ' . $details->id . PHP_EOL; + + } catch (EndpointException|GotifyException $err) { + Notification::make() + ->title('Error sending Gotify notification: '.$err->getMessage()) + ->danger() + ->send(); + } } Notification::make() - ->title('Test Gotify notification sent.') + ->title('Test Gotify notifications sent.') ->success() ->send(); } diff --git a/app/Actions/Notifications/SendNtfyTestNotification.php b/app/Actions/Notifications/SendNtfyTestNotification.php index 8975febaa..19dd640c2 100644 --- a/app/Actions/Notifications/SendNtfyTestNotification.php +++ b/app/Actions/Notifications/SendNtfyTestNotification.php @@ -4,7 +4,13 @@ use Filament\Notifications\Notification; use Lorisleiva\Actions\Concerns\AsAction; -use Spatie\WebhookServer\WebhookCall; +use Ntfy\Auth\Token; +use Ntfy\Auth\User; +use Ntfy\Client; +use Ntfy\Exception\EndpointException; +use Ntfy\Exception\NtfyException; +use Ntfy\Message; +use Ntfy\Server; class SendNtfyTestNotification { @@ -14,7 +20,7 @@ public function handle(array $webhooks) { if (! count($webhooks)) { Notification::make() - ->title('You need to add ntfy urls!') + ->title('You need to add ntfy URLs!') ->warning() ->send(); @@ -22,28 +28,38 @@ public function handle(array $webhooks) } foreach ($webhooks as $webhook) { - $webhookCall = WebhookCall::create() - ->url($webhook['url']) - ->payload([ - 'topic' => $webhook['topic'], - 'message' => '👋 Testing the ntfy notification channel.', - ]) - ->doNotSign(); - - // Only add authentication if username and password are provided - if (! empty($webhook['username']) && ! empty($webhook['password'])) { - $authHeader = 'Basic '.base64_encode($webhook['username'].':'.$webhook['password']); - $webhookCall->withHeaders([ - 'Authorization' => $authHeader, - ]); - } + try { + // Set server + $server = new Server($webhook['url']); - $webhookCall->dispatch(); - } + // Create a new message + $message = new Message(); + $message->topic($webhook['topic']); + $message->title('Test Notification'); + $message->body('👋 Testing the ntfy notification channel.'); + + $auth = null; + if (! empty($webhook['token'])) { + $auth = new Token($webhook['token']); + } elseif (! empty($webhook['username']) && ! empty($webhook['password'])) { + $auth = new User($webhook['username'], $webhook['password']); + } + + // Create a client with optional authentication + $client = new Client($server, $auth); + $response = $client->send($message); - Notification::make() - ->title('Test ntfy notification sent.') - ->success() - ->send(); + Notification::make() + ->title("Test ntfy notification sent to {$webhook['topic']}.") + ->success() + ->send(); + + } catch (EndpointException|NtfyException $err) { + Notification::make() + ->title("Failed to send notification to {$webhook['topic']}.") + ->warning() + ->send(); + } + } } } diff --git a/app/Filament/Pages/Settings/NotificationPage.php b/app/Filament/Pages/Settings/NotificationPage.php index bd7df5902..c9d88b8cb 100755 --- a/app/Filament/Pages/Settings/NotificationPage.php +++ b/app/Filament/Pages/Settings/NotificationPage.php @@ -218,12 +218,25 @@ public function form(Form $form): Form ->maxLength(2000) ->required() ->url(), + Forms\Components\TextInput::make('token') + ->placeholder('App token here') + ->maxLength(2000) + ->required() + ->password(), ]) ->columnSpanFull(), Forms\Components\Actions::make([ Forms\Components\Actions\Action::make('test gotify') ->label('Test Gotify webhook') - ->action(fn (Forms\Get $get) => SendgotifyTestNotification::run(webhooks: $get('gotify_webhooks'))) + ->action(function (Forms\Get $get) { + $webhooks = $get('gotify_webhooks'); + foreach ($webhooks as $webhook) { + SendGotifyTestNotification::run( + webhooks: [$webhook['url']], // Pass a single URL as an array + token: $webhook['token'] // Pass the token as a string + ); + } + }) ->hidden(fn (Forms\Get $get) => ! count($get('gotify_webhooks'))), ]), ]), @@ -299,7 +312,9 @@ public function form(Form $form): Form ->columnSpanFull(), ]), Forms\Components\Repeater::make('ntfy_webhooks') - ->label('Webhooks') + ->label('ntfy servers') + ->collapsed() + ->itemLabel(fn (array $state): ?string => $state['topic'] ?? null) ->schema([ Forms\Components\TextInput::make('url') ->maxLength(2000) @@ -320,6 +335,11 @@ public function form(Form $form): Form ->placeholder('Password for Basic Auth (optional)') ->password() ->maxLength(200), + Forms\Components\TextInput::make('token') + ->label('Token') + ->placeholder('Token for Token Auth (optional)') + ->password() + ->maxLength(200), ]) ->columnSpanFull(), Forms\Components\Actions::make([ diff --git a/app/Listeners/Gotify/SendSpeedtestCompletedNotification.php b/app/Listeners/Gotify/SendSpeedtestCompletedNotification.php index 8265426c9..c39be2cdd 100644 --- a/app/Listeners/Gotify/SendSpeedtestCompletedNotification.php +++ b/app/Listeners/Gotify/SendSpeedtestCompletedNotification.php @@ -3,14 +3,24 @@ namespace App\Listeners\Gotify; use App\Events\SpeedtestCompleted; -use App\Helpers\Number; +use App\Services\SpeedtestCompletedNotificationPayload; use App\Settings\NotificationSettings; +use Gotify\Auth\Token; +use Gotify\Endpoint\Message; +use Gotify\Exception\EndpointException; +use Gotify\Exception\GotifyException; +use Gotify\Server; use Illuminate\Support\Facades\Log; -use Illuminate\Support\Str; -use Spatie\WebhookServer\WebhookCall; class SendSpeedtestCompletedNotification { + protected $payloadService; + + public function __construct(SpeedtestCompletedNotificationPayload $payloadService) + { + $this->payloadService = $payloadService; + } + /** * Handle the event. */ @@ -27,33 +37,31 @@ public function handle(SpeedtestCompleted $event): void } if (! count($notificationSettings->gotify_webhooks)) { - Log::warning('Gotify urls not found, check Gotify notification channel settings.'); + Log::warning('Gotify URLs not found, check Gotify notification channel settings.'); return; } - $payload = [ - 'message' => view('gotify.speedtest-completed', [ - 'id' => $event->result->id, - 'service' => Str::title($event->result->service), - 'serverName' => $event->result->server_name, - 'serverId' => $event->result->server_id, - 'isp' => $event->result->isp, - 'ping' => round($event->result->ping).' ms', - 'download' => Number::toBitRate(bits: $event->result->download_bits, precision: 2), - 'upload' => Number::toBitRate(bits: $event->result->upload_bits, precision: 2), - 'packetLoss' => $event->result->packet_loss, - 'speedtest_url' => $event->result->result_url, - 'url' => url('/admin/results'), - ])->render(), + $payload = $this->payloadService->generateSpeedtestPayload($event); + $extras = [ + 'client::display' => [ + 'contentType' => 'text/markdown', + ], ]; + foreach ($notificationSettings->gotify_webhooks as $webhook) { + try { + $server = new Server($webhook['url']); + $auth = new Token($webhook['token']); + $message = new Message($server, $auth); + $message->create( + title: 'Speedtest Completed', + message: $payload, + extras: $extras, + ); - foreach ($notificationSettings->gotify_webhooks as $url) { - WebhookCall::create() - ->url($url['url']) - ->payload($payload) - ->doNotSign() - ->dispatch(); + } catch (EndpointException|GotifyException $err) { + Log::error('Failed to send Gotify notification: '.$err->getMessage()); + } } } } diff --git a/app/Listeners/Gotify/SendSpeedtestThresholdNotification.php b/app/Listeners/Gotify/SendSpeedtestThresholdNotification.php index 8da2daedf..7386cddb9 100644 --- a/app/Listeners/Gotify/SendSpeedtestThresholdNotification.php +++ b/app/Listeners/Gotify/SendSpeedtestThresholdNotification.php @@ -4,14 +4,25 @@ use App\Events\SpeedtestCompleted; use App\Helpers\Number; +use App\Services\SpeedtestThresholdNotificationPayload; use App\Settings\NotificationSettings; use App\Settings\ThresholdSettings; +use Gotify\Auth\Token; +use Gotify\Endpoint\Message; +use Gotify\Exception\EndpointException; +use Gotify\Exception\GotifyException; +use Gotify\Server; use Illuminate\Support\Facades\Log; -use Illuminate\Support\Str; -use Spatie\WebhookServer\WebhookCall; class SendSpeedtestThresholdNotification { + protected $payloadService; + + public function __construct(SpeedtestThresholdNotificationPayload $payloadService) + { + $this->payloadService = $payloadService; + } + /** * Handle the event. */ @@ -28,7 +39,7 @@ public function handle(SpeedtestCompleted $event): void } if (! count($notificationSettings->gotify_webhooks)) { - Log::warning('Gotify urls not found, check gotify notification channel settings.'); + Log::warning('Gotify URLs not found, check Gotify notification channel settings.'); return; } @@ -39,52 +50,34 @@ public function handle(SpeedtestCompleted $event): void return; } - $failed = []; - - if ($thresholdSettings->absolute_download > 0) { - array_push($failed, $this->absoluteDownloadThreshold(event: $event, thresholdSettings: $thresholdSettings)); - } - - if ($thresholdSettings->absolute_upload > 0) { - array_push($failed, $this->absoluteUploadThreshold(event: $event, thresholdSettings: $thresholdSettings)); - } - - if ($thresholdSettings->absolute_ping > 0) { - array_push($failed, $this->absolutePingThreshold(event: $event, thresholdSettings: $thresholdSettings)); - } - - $failed = array_filter($failed); - - if (! count($failed)) { - Log::warning('Failed Gotify thresholds not found, won\'t send notification.'); - - return; - } - - $payload = [ - 'message' => view('gotify.speedtest-threshold', [ - 'id' => $event->result->id, - 'service' => Str::title($event->result->service), - 'serverName' => $event->result->server_name, - 'serverId' => $event->result->server_id, - 'isp' => $event->result->isp, - 'metrics' => $failed, - 'speedtest_url' => $event->result->result_url, - 'url' => url('/admin/results'), - ])->render(), + $payload = $this->payloadService->generateThresholdPayload($event, $thresholdSettings); + $extras = [ + 'client::display' => [ + 'contentType' => 'text/markdown', + ], ]; - foreach ($notificationSettings->gotify_webhooks as $url) { - WebhookCall::create() - ->url($url['url']) - ->payload($payload) - ->doNotSign() - ->dispatch(); + foreach ($notificationSettings->gotify_webhooks as $webhook) { + try { + $server = new Server($webhook['url']); + $auth = new Token($webhook['token']); + $message = new Message($server, $auth); + + $message->create( + title: 'Speedtest Threshold Alert', + message: $payload, + priority: Message::PRIORITY_HIGH, + extras: $extras, + ); + + } catch (EndpointException|GotifyException $err) { + Log::error('Failed to send Gotify notification: '.$err->getMessage()); + } } } /** - * Build gotify notification if absolute download threshold is breached. + * Build Gotify notification if absolute download threshold is breached. */ protected function absoluteDownloadThreshold(SpeedtestCompleted $event, ThresholdSettings $thresholdSettings): bool|array { @@ -100,7 +93,7 @@ protected function absoluteDownloadThreshold(SpeedtestCompleted $event, Threshol } /** - * Build gotify notification if absolute upload threshold is breached. + * Build Gotify notification if absolute upload threshold is breached. */ protected function absoluteUploadThreshold(SpeedtestCompleted $event, ThresholdSettings $thresholdSettings): bool|array { @@ -116,7 +109,7 @@ protected function absoluteUploadThreshold(SpeedtestCompleted $event, ThresholdS } /** - * Build gotify notification if absolute ping threshold is breached. + * Build Gotify notification if absolute ping threshold is breached. */ protected function absolutePingThreshold(SpeedtestCompleted $event, ThresholdSettings $thresholdSettings): bool|array { diff --git a/app/Listeners/Ntfy/SendSpeedtestCompletedNotification.php b/app/Listeners/Ntfy/SendSpeedtestCompletedNotification.php index f63cdcd13..652a4d09a 100644 --- a/app/Listeners/Ntfy/SendSpeedtestCompletedNotification.php +++ b/app/Listeners/Ntfy/SendSpeedtestCompletedNotification.php @@ -3,14 +3,26 @@ namespace App\Listeners\Ntfy; use App\Events\SpeedtestCompleted; -use App\Helpers\Number; +use App\Services\SpeedtestCompletedNotificationPayload; use App\Settings\NotificationSettings; use Illuminate\Support\Facades\Log; -use Illuminate\Support\Str; -use Spatie\WebhookServer\WebhookCall; +use Ntfy\Auth\Token; +use Ntfy\Auth\User; +use Ntfy\Client; +use Ntfy\Exception\EndpointException; +use Ntfy\Exception\NtfyException; +use Ntfy\Message; +use Ntfy\Server; class SendSpeedtestCompletedNotification { + protected $payloadService; + + public function __construct(SpeedtestCompletedNotificationPayload $payloadService) + { + $this->payloadService = $payloadService; + } + /** * Handle the event. */ @@ -27,43 +39,39 @@ public function handle(SpeedtestCompleted $event): void } if (! count($notificationSettings->ntfy_webhooks)) { - Log::warning('Ntfy urls not found, check Ntfy notification channel settings.'); + Log::warning('Ntfy URLs not found, check Ntfy notification channel settings.'); return; } - $payload = - view('ntfy.speedtest-completed', [ - 'id' => $event->result->id, - 'service' => Str::title($event->result->service), - 'serverName' => $event->result->server_name, - 'serverId' => $event->result->server_id, - 'isp' => $event->result->isp, - 'ping' => round($event->result->ping).' ms', - 'download' => Number::toBitRate(bits: $event->result->download_bits, precision: 2), - 'upload' => Number::toBitRate(bits: $event->result->upload_bits, precision: 2), - 'packetLoss' => $event->result->packet_loss, - 'speedtest_url' => $event->result->result_url, - 'url' => url('/admin/results'), - ])->render(); + $payload = $this->payloadService->generateSpeedtestPayload($event); foreach ($notificationSettings->ntfy_webhooks as $url) { - $webhookCall = WebhookCall::create() - ->url($url['url']) - ->payload([ - 'topic' => $url['topic'], - 'message' => $payload, - ]) - ->doNotSign(); + try { + // Set server + $server = new Server($url['url']); + + // Create a new message + $message = new Message(); + $message->topic($url['topic']); + $message->title('Speedtest Completed'); + $message->markdownBody($payload); + + // Set authentication if username/password or token is provided + $auth = null; + if (! empty($url['token'])) { + $auth = new Token($url['token']); + } elseif (! empty($url['username']) && ! empty($url['password'])) { + $auth = new User($url['username'], $url['password']); + } + + // Create a client with optional authentication + $client = new Client($server, $auth); + $client->send($message); - // Only add authentication if username and password are provided - if (! empty($url['username']) && ! empty($url['password'])) { - $authHeader = 'Basic '.base64_encode($url['username'].':'.$url['password']); - $webhookCall->withHeaders([ - 'Authorization' => $authHeader, - ]); + } catch (EndpointException|NtfyException $err) { + Log::error('Failed to send notification: '.$err->getMessage()); } - $webhookCall->dispatch(); } } } diff --git a/app/Listeners/Ntfy/SendSpeedtestThresholdNotification.php b/app/Listeners/Ntfy/SendSpeedtestThresholdNotification.php index 2ca1a93e1..f01f4eb8e 100644 --- a/app/Listeners/Ntfy/SendSpeedtestThresholdNotification.php +++ b/app/Listeners/Ntfy/SendSpeedtestThresholdNotification.php @@ -3,15 +3,27 @@ namespace App\Listeners\Ntfy; use App\Events\SpeedtestCompleted; -use App\Helpers\Number; +use App\Services\SpeedtestThresholdNotificationPayload; use App\Settings\NotificationSettings; use App\Settings\ThresholdSettings; use Illuminate\Support\Facades\Log; -use Illuminate\Support\Str; -use Spatie\WebhookServer\WebhookCall; +use Ntfy\Auth\Token; +use Ntfy\Auth\User; +use Ntfy\Client; +use Ntfy\Exception\EndpointException; +use Ntfy\Exception\NtfyException; +use Ntfy\Message; +use Ntfy\Server; class SendSpeedtestThresholdNotification { + protected $payloadService; + + public function __construct(SpeedtestThresholdNotificationPayload $payloadService) + { + $this->payloadService = $payloadService; + } + /** * Handle the event. */ @@ -28,7 +40,7 @@ public function handle(SpeedtestCompleted $event): void } if (! count($notificationSettings->ntfy_webhooks)) { - Log::warning('Ntfy urls not found, check Ntfy notification channel settings.'); + Log::warning('Ntfy URLs not found, check Ntfy notification channel settings.'); return; } @@ -39,106 +51,41 @@ public function handle(SpeedtestCompleted $event): void return; } - $failed = []; + $payload = $this->payloadService->generateThresholdPayload($event, $thresholdSettings); - if ($thresholdSettings->absolute_download > 0) { - array_push($failed, $this->absoluteDownloadThreshold(event: $event, thresholdSettings: $thresholdSettings)); - } - - if ($thresholdSettings->absolute_upload > 0) { - array_push($failed, $this->absoluteUploadThreshold(event: $event, thresholdSettings: $thresholdSettings)); - } - - if ($thresholdSettings->absolute_ping > 0) { - array_push($failed, $this->absolutePingThreshold(event: $event, thresholdSettings: $thresholdSettings)); - } - - $failed = array_filter($failed); - - if (! count($failed)) { + if (empty($payload)) { Log::warning('Failed ntfy thresholds not found, won\'t send notification.'); return; } - $payload = - view('ntfy.speedtest-threshold', [ - 'id' => $event->result->id, - 'service' => Str::title($event->result->service), - 'serverName' => $event->result->server_name, - 'serverId' => $event->result->server_id, - 'isp' => $event->result->isp, - 'metrics' => $failed, - 'speedtest_url' => $event->result->result_url, - 'url' => url('/admin/results'), - ])->render(); - foreach ($notificationSettings->ntfy_webhooks as $url) { - $webhookCall = WebhookCall::create() - ->url($url['url']) - ->payload([ - 'topic' => $url['topic'], - 'message' => $payload, - ]) - ->doNotSign(); - - // Only add authentication if username and password are provided - if (! empty($url['username']) && ! empty($url['password'])) { - $authHeader = 'Basic '.base64_encode($url['username'].':'.$url['password']); - $webhookCall->withHeaders([ - 'Authorization' => $authHeader, - ]); + try { + // Set server + $server = new Server($url['url']); + + // Create a new message + $message = new Message(); + $message->topic($url['topic']); + $message->title('Speedtest Threshold Alert'); + $message->markdownBody($payload); + $message->priority(Message::PRIORITY_HIGH); + + // Set authentication if username/password or token is provided + $auth = null; + if (! empty($url['token'])) { + $auth = new Token($url['token']); + } elseif (! empty($url['username']) && ! empty($url['password'])) { + $auth = new User($url['username'], $url['password']); + } + + // Create a client with optional authentication + $client = new Client($server, $auth); + $client->send($message); + + } catch (EndpointException|NtfyException $err) { + Log::error('Failed to send notification: '.$err->getMessage()); } - - $webhookCall->dispatch(); - } - } - - /** - * Build Ntfy notification if absolute download threshold is breached. - */ - protected function absoluteDownloadThreshold(SpeedtestCompleted $event, ThresholdSettings $thresholdSettings): bool|array - { - if (! absoluteDownloadThresholdFailed($thresholdSettings->absolute_download, $event->result->download)) { - return false; - } - - return [ - 'name' => 'Download', - 'threshold' => $thresholdSettings->absolute_download.' Mbps', - 'value' => Number::toBitRate(bits: $event->result->download_bits, precision: 2), - ]; - } - - /** - * Build Ntfy notification if absolute upload threshold is breached. - */ - protected function absoluteUploadThreshold(SpeedtestCompleted $event, ThresholdSettings $thresholdSettings): bool|array - { - if (! absoluteUploadThresholdFailed($thresholdSettings->absolute_upload, $event->result->upload)) { - return false; } - - return [ - 'name' => 'Upload', - 'threshold' => $thresholdSettings->absolute_upload.' Mbps', - 'value' => Number::toBitRate(bits: $event->result->upload_bits, precision: 2), - ]; - } - - /** - * Build Ntfy notification if absolute ping threshold is breached. - */ - protected function absolutePingThreshold(SpeedtestCompleted $event, ThresholdSettings $thresholdSettings): bool|array - { - if (! absolutePingThresholdFailed($thresholdSettings->absolute_ping, $event->result->ping)) { - return false; - } - - return [ - 'name' => 'Ping', - 'threshold' => $thresholdSettings->absolute_ping.' ms', - 'value' => round($event->result->ping, 2).' ms', - ]; } } diff --git a/app/Services/SpeedtestCompletedNotificationPayload.php b/app/Services/SpeedtestCompletedNotificationPayload.php new file mode 100644 index 000000000..213c4e9a1 --- /dev/null +++ b/app/Services/SpeedtestCompletedNotificationPayload.php @@ -0,0 +1,30 @@ + $event->result->id, + 'service' => Str::title($event->result->service), + 'serverName' => $event->result->server_name, + 'serverId' => $event->result->server_id, + 'isp' => $event->result->isp, + 'ping' => round($event->result->ping).' ms', + 'download' => Number::toBitRate(bits: $event->result->download_bits, precision: 2), + 'upload' => Number::toBitRate(bits: $event->result->upload_bits, precision: 2), + 'packetLoss' => $event->result->packet_loss, + 'speedtest_url' => $event->result->result_url, + 'url' => url('/admin/results'), + ])->render(); + } +} diff --git a/app/Services/SpeedtestThresholdNotificationPayload.php b/app/Services/SpeedtestThresholdNotificationPayload.php new file mode 100644 index 000000000..085f56cb6 --- /dev/null +++ b/app/Services/SpeedtestThresholdNotificationPayload.php @@ -0,0 +1,83 @@ +absolute_download > 0) { + $failed[] = $this->absoluteDownloadThreshold($event, $thresholdSettings); + } + + if ($thresholdSettings->absolute_upload > 0) { + $failed[] = $this->absoluteUploadThreshold($event, $thresholdSettings); + } + + if ($thresholdSettings->absolute_ping > 0) { + $failed[] = $this->absolutePingThreshold($event, $thresholdSettings); + } + + $failed = array_filter($failed); + + return view('notifications.speedtest-threshold', [ + 'id' => $event->result->id, + 'service' => Str::title($event->result->service), + 'serverName' => $event->result->server_name, + 'serverId' => $event->result->server_id, + 'isp' => $event->result->isp, + 'metrics' => $failed, + 'speedtest_url' => $event->result->result_url, + 'url' => url('/admin/results'), + ])->render(); + } + + protected function absoluteDownloadThreshold(SpeedtestCompleted $event, ThresholdSettings $thresholdSettings): bool|array + { + if (! absoluteDownloadThresholdFailed($thresholdSettings->absolute_download, $event->result->download)) { + return false; + } + + return [ + 'name' => 'Download', + 'threshold' => $thresholdSettings->absolute_download.' Mbps', + 'value' => Number::toBitRate(bits: $event->result->download_bits, precision: 2), + ]; + } + + protected function absoluteUploadThreshold(SpeedtestCompleted $event, ThresholdSettings $thresholdSettings): bool|array + { + if (! absoluteUploadThresholdFailed($thresholdSettings->absolute_upload, $event->result->upload)) { + return false; + } + + return [ + 'name' => 'Upload', + 'threshold' => $thresholdSettings->absolute_upload.' Mbps', + 'value' => Number::toBitRate(bits: $event->result->upload_bits, precision: 2), + ]; + } + + protected function absolutePingThreshold(SpeedtestCompleted $event, ThresholdSettings $thresholdSettings): bool|array + { + if (! absolutePingThresholdFailed($thresholdSettings->absolute_ping, $event->result->ping)) { + return false; + } + + return [ + 'name' => 'Ping', + 'threshold' => $thresholdSettings->absolute_ping.' ms', + 'value' => round($event->result->ping, 2).' ms', + ]; + } +} diff --git a/composer.json b/composer.json index 851bb090c..e04748d9d 100644 --- a/composer.json +++ b/composer.json @@ -27,7 +27,9 @@ "maennchen/zipstream-php": "^2.4", "spatie/laravel-settings": "^3.3.2", "spatie/laravel-webhook-server": "^3.8.1", - "timokoerber/laravel-one-time-operations": "^1.4.2" + "timokoerber/laravel-one-time-operations": "^1.4.2", + "verifiedjoseph/gotify-api-php": "^1.9", + "verifiedjoseph/ntfy-php-library": "^4.6" }, "require-dev": { "barryvdh/laravel-ide-helper": "^3.1", diff --git a/composer.lock b/composer.lock index 4ceb0fa92..b0584df45 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "0b1b064aa394c00a4c3aba46d92a76b3", + "content-hash": "5548136a2fe01d566521f25978af8be4", "packages": [ { "name": "anourvalar/eloquent-serialize", @@ -9068,6 +9068,110 @@ }, "time": "2024-04-04T11:16:58+00:00" }, + { + "name": "verifiedjoseph/gotify-api-php", + "version": "v1.9.0", + "source": { + "type": "git", + "url": "https://github.com/VerifiedJoseph/gotify-api-php.git", + "reference": "4295dc71bdca2c5e1d549b002b96e6daa9255d56" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/VerifiedJoseph/gotify-api-php/zipball/4295dc71bdca2c5e1d549b002b96e6daa9255d56", + "reference": "4295dc71bdca2c5e1d549b002b96e6daa9255d56", + "shasum": "" + }, + "require": { + "ext-curl": "*", + "ext-json": "*", + "guzzlehttp/guzzle": "^7.4.5", + "php": "^8.1" + }, + "require-dev": { + "phpstan/phpstan": "^1.0", + "phpunit/phpunit": "^10.5", + "squizlabs/php_codesniffer": "^3.7" + }, + "type": "library", + "autoload": { + "psr-4": { + "Gotify\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "VerifiedJoseph", + "homepage": "https://github.com/VerifiedJoseph" + } + ], + "description": "PHP library for interacting with a Gotify server using the Gotify REST-API.", + "homepage": "https://github.com/VerifiedJoseph/gotify-api-php", + "keywords": [ + "gotify" + ], + "support": { + "issues": "https://github.com/VerifiedJoseph/gotify-api-php/issues", + "source": "https://github.com/VerifiedJoseph/gotify-api-php/tree/v1.9.0" + }, + "time": "2024-08-01T16:21:35+00:00" + }, + { + "name": "verifiedjoseph/ntfy-php-library", + "version": "v4.6.2", + "source": { + "type": "git", + "url": "https://github.com/VerifiedJoseph/ntfy-php-library.git", + "reference": "0e5c22be5e1633534e41a5835a8975bec5ff4cef" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/VerifiedJoseph/ntfy-php-library/zipball/0e5c22be5e1633534e41a5835a8975bec5ff4cef", + "reference": "0e5c22be5e1633534e41a5835a8975bec5ff4cef", + "shasum": "" + }, + "require": { + "ext-curl": "*", + "ext-json": "*", + "guzzlehttp/guzzle": "^7.4", + "php": "^8.1" + }, + "require-dev": { + "phpstan/phpstan": "^1.0", + "phpunit/phpunit": "^10.5", + "squizlabs/php_codesniffer": "^3.7" + }, + "type": "library", + "autoload": { + "psr-4": { + "Ntfy\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "VerifiedJoseph", + "homepage": "https://github.com/VerifiedJoseph" + } + ], + "description": "PHP library for interacting with a Ntfy server", + "homepage": "https://github.com/VerifiedJoseph/ntfy-php-library", + "keywords": [ + "Ntfy" + ], + "support": { + "issues": "https://github.com/VerifiedJoseph/ntfy-php-library/issues", + "source": "https://github.com/VerifiedJoseph/ntfy-php-library/tree/v4.6.2" + }, + "time": "2024-08-01T12:43:09+00:00" + }, { "name": "vlucas/phpdotenv", "version": "v5.6.1", diff --git a/resources/views/notifications/speedtest-completed.blade.php b/resources/views/notifications/speedtest-completed.blade.php new file mode 100644 index 000000000..023fa9464 --- /dev/null +++ b/resources/views/notifications/speedtest-completed.blade.php @@ -0,0 +1,13 @@ +**Speedtest Completed - #{{ $id }}** + +A new speedtest was completed using **{{ $service }}**. + +- **Server name:** {{ $serverName }} +- **Server ID:** {{ $serverId }} +- **ISP:** {{ $isp }} +- **Ping:** {{ $ping }} +- **Download:** {{ $download }} +- **Upload:** {{ $upload }} +- **Packet Loss:** {{ $packetLoss }} **%** +- **Ookla Speedtest:** {{ $speedtest_url }} +- **URL:** {{ $url }} diff --git a/resources/views/notifications/speedtest-threshold.blade.php b/resources/views/notifications/speedtest-threshold.blade.php new file mode 100644 index 000000000..dc38dd40c --- /dev/null +++ b/resources/views/notifications/speedtest-threshold.blade.php @@ -0,0 +1,9 @@ +**Speedtest Threshold Breached - #{{ $id }}** + +A new speedtest was completed using **{{ $service }}** on **{{ $isp }}** but a threshold was breached. + +@foreach ($metrics as $item) +- **{{ $item['name'] }}** {{ $item['threshold'] }}: {{ $item['value'] }} +@endforeach +- **Ookla Speedtest:** {{ $speedtest_url }} +- **URL:** {{ $url }} diff --git a/resources/views/ntfy/speedtest-completed.blade.php b/resources/views/ntfy/speedtest-completed.blade.php deleted file mode 100644 index 5976b28d4..000000000 --- a/resources/views/ntfy/speedtest-completed.blade.php +++ /dev/null @@ -1,13 +0,0 @@ -Speedtest Completed - #{{ $id }} - -A new speedtest was completed using {{ $service }}. - -Server name: {{ $serverName }} -Server ID: {{ $serverId }} -ISP: {{ $isp }} -Ping: {{ $ping }} -Download: {{ $download }} -Upload: {{ $upload }} -Packet Loss: {{ $packetLoss }} % -Ookla Speedtest: {{ $speedtest_url }} -URL: {{ $url }} diff --git a/resources/views/ntfy/speedtest-threshold.blade.php b/resources/views/ntfy/speedtest-threshold.blade.php deleted file mode 100644 index 4a7fe325e..000000000 --- a/resources/views/ntfy/speedtest-threshold.blade.php +++ /dev/null @@ -1,9 +0,0 @@ -Speedtest Threshold Breached - #{{ $id }} - -A new speedtest was completed using {{ $service }} on {{ $isp }} but a threshold was breached. - -@foreach ($metrics as $item) -- {{ $item['name'] }} {{ $item['threshold'] }}: {{ $item['value'] }} -@endforeach -- Ookla Speedtest: {{ $speedtest_url }} -- URL: {{ $url }} From 4ff015d7b0778205266c3e971c02ea22df7a4015 Mon Sep 17 00:00:00 2001 From: svenvg93 Date: Mon, 23 Sep 2024 22:57:24 +0200 Subject: [PATCH 14/15] commit --- .../views/gotify/speedtest-completed.blade.php | 13 ------------- .../views/gotify/speedtest-threshold.blade.php | 9 --------- 2 files changed, 22 deletions(-) delete mode 100644 resources/views/gotify/speedtest-completed.blade.php delete mode 100644 resources/views/gotify/speedtest-threshold.blade.php diff --git a/resources/views/gotify/speedtest-completed.blade.php b/resources/views/gotify/speedtest-completed.blade.php deleted file mode 100644 index ee50f07e3..000000000 --- a/resources/views/gotify/speedtest-completed.blade.php +++ /dev/null @@ -1,13 +0,0 @@ -Speedtest Completed - #{{ $id }} - -A new speedtest was completed using {{ $service }}. - -- Server name: {{ $serverName }} -- Server ID: {{ $serverId }} -- ISP: {{ $isp }} -- Ping: {{ $ping }} -- Download: {{ $download }} -- Upload: {{ $upload }} -- Packet Loss: {{ $packetLoss }} % -- Ookla Speedtest:{{ $speedtest_url }} -- URL: {{ $url }} diff --git a/resources/views/gotify/speedtest-threshold.blade.php b/resources/views/gotify/speedtest-threshold.blade.php deleted file mode 100644 index 4a7fe325e..000000000 --- a/resources/views/gotify/speedtest-threshold.blade.php +++ /dev/null @@ -1,9 +0,0 @@ -Speedtest Threshold Breached - #{{ $id }} - -A new speedtest was completed using {{ $service }} on {{ $isp }} but a threshold was breached. - -@foreach ($metrics as $item) -- {{ $item['name'] }} {{ $item['threshold'] }}: {{ $item['value'] }} -@endforeach -- Ookla Speedtest: {{ $speedtest_url }} -- URL: {{ $url }} From adba12c9c3a591b58cd6860e738f4c96316fbcc9 Mon Sep 17 00:00:00 2001 From: svenvg93 Date: Wed, 25 Sep 2024 15:29:11 +0200 Subject: [PATCH 15/15] commit --- .../SendPushoverTestNotification.php | 58 +++++++++---- .../Pages/Settings/NotificationPage.php | 12 +-- .../SendSpeedtestCompletedNotification.php | 6 +- .../SendSpeedtestThresholdNotification.php | 4 +- .../SendSpeedtestCompletedNotification.php | 5 +- .../SendSpeedtestThresholdNotification.php | 5 +- .../SendSpeedtestCompletedNotification.php | 81 +++++++++-------- .../SendSpeedtestThresholdNotification.php | 87 +++++++++---------- .../SpeedtestCompletedNotificationPayload.php | 4 +- .../SpeedtestThresholdNotificationPayload.php | 4 +- composer.json | 1 + composer.lock | 60 ++++++++++++- .../pushover/speedtest-completed.blade.php | 22 ++--- .../pushover/speedtest-threshold.blade.php | 10 +-- 14 files changed, 225 insertions(+), 134 deletions(-) diff --git a/app/Actions/Notifications/SendPushoverTestNotification.php b/app/Actions/Notifications/SendPushoverTestNotification.php index d37b0594d..ae5bf4e77 100644 --- a/app/Actions/Notifications/SendPushoverTestNotification.php +++ b/app/Actions/Notifications/SendPushoverTestNotification.php @@ -2,9 +2,12 @@ namespace App\Actions\Notifications; -use Filament\Notifications\Notification; +use Filament\Notifications\Notification as FilamentNotification; use Lorisleiva\Actions\Concerns\AsAction; -use Spatie\WebhookServer\WebhookCall; +use Serhiy\Pushover\Api\Message\Message; +use Serhiy\Pushover\Api\Message\Notification as PushoverNotification; +use Serhiy\Pushover\Application; +use Serhiy\Pushover\Recipient; class SendPushoverTestNotification { @@ -13,8 +16,8 @@ class SendPushoverTestNotification public function handle(array $webhooks) { if (! count($webhooks)) { - Notification::make() - ->title('You need to add Pushover URLs!') + FilamentNotification::make() + ->title('You need to add Pushover credentials!') ->warning() ->send(); @@ -22,20 +25,39 @@ public function handle(array $webhooks) } foreach ($webhooks as $webhook) { - WebhookCall::create() - ->url($webhook['url']) - ->payload([ - 'token' => $webhook['api_token'], - 'user' => $webhook['user_key'], - 'message' => '👋 Testing the Pushover notification channel.', - ]) - ->doNotSign() - ->dispatch(); - } + try { + // Create Application and Recipient objects + $application = new Application($webhook['api_token']); + $recipient = new Recipient($webhook['user_key']); + + // Compose the message with title and body + $message = new Message('👋 Testing the Pushover notification channel.', 'Speedtest Tracker Test Notification'); + + // Create a notification with the application, recipient, and message + $pushoverNotification = new PushoverNotification($application, $recipient, $message); - Notification::make() - ->title('Test Pushover notification sent.') - ->success() - ->send(); + // Push the notification + /** @var \Serhiy\Pushover\Client\Response\MessageResponse $response */ + $response = $pushoverNotification->push(); + + // Check response status + if ($response->isSuccessful()) { + FilamentNotification::make() + ->title('Test Pushover notification sent.') + ->success() + ->send(); + } else { + FilamentNotification::make() + ->title('Failed to send Pushover notification: '.$response->getMessage()) + ->danger() + ->send(); + } + } catch (\Exception $e) { + FilamentNotification::make() + ->title('An error occurred: '.$e->getMessage()) + ->danger() + ->send(); + } + } } } diff --git a/app/Filament/Pages/Settings/NotificationPage.php b/app/Filament/Pages/Settings/NotificationPage.php index c9d88b8cb..02dacb7d1 100755 --- a/app/Filament/Pages/Settings/NotificationPage.php +++ b/app/Filament/Pages/Settings/NotificationPage.php @@ -110,14 +110,8 @@ public function form(Form $form): Form ->columnSpanFull(), ]), Forms\Components\Repeater::make('pushover_webhooks') - ->label('Pushover Webhooks') + ->label('Devices') ->schema([ - Forms\Components\TextInput::make('url') - ->label('URL') - ->placeholder('http://api.pushover.net/1/messages.json') - ->maxLength(2000) - ->required() - ->url(), Forms\Components\TextInput::make('user_key') ->label('User Key') ->placeholder('Your Pushover User Key') @@ -211,7 +205,7 @@ public function form(Form $form): Form ->columnSpanFull(), ]), Forms\Components\Repeater::make('gotify_webhooks') - ->label('Webhooks') + ->label('Application') ->schema([ Forms\Components\TextInput::make('url') ->placeholder('https://example.com/message?token=') @@ -312,7 +306,7 @@ public function form(Form $form): Form ->columnSpanFull(), ]), Forms\Components\Repeater::make('ntfy_webhooks') - ->label('ntfy servers') + ->label('Ntfy Servers') ->collapsed() ->itemLabel(fn (array $state): ?string => $state['topic'] ?? null) ->schema([ diff --git a/app/Listeners/Gotify/SendSpeedtestCompletedNotification.php b/app/Listeners/Gotify/SendSpeedtestCompletedNotification.php index c39be2cdd..b28cab97e 100644 --- a/app/Listeners/Gotify/SendSpeedtestCompletedNotification.php +++ b/app/Listeners/Gotify/SendSpeedtestCompletedNotification.php @@ -41,8 +41,12 @@ public function handle(SpeedtestCompleted $event): void return; } + // Define the view name directly + $viewName = 'notifications.speedtest-completed'; + + // Generate the payload using the specified view + $payload = $this->payloadService->generateSpeedtestPayload($event, $viewName); - $payload = $this->payloadService->generateSpeedtestPayload($event); $extras = [ 'client::display' => [ 'contentType' => 'text/markdown', diff --git a/app/Listeners/Gotify/SendSpeedtestThresholdNotification.php b/app/Listeners/Gotify/SendSpeedtestThresholdNotification.php index 7386cddb9..31093b108 100644 --- a/app/Listeners/Gotify/SendSpeedtestThresholdNotification.php +++ b/app/Listeners/Gotify/SendSpeedtestThresholdNotification.php @@ -49,8 +49,10 @@ public function handle(SpeedtestCompleted $event): void if (! $thresholdSettings->absolute_enabled) { return; } + // Define the view name directly + $viewName = 'notifications.speedtest-threshold'; - $payload = $this->payloadService->generateThresholdPayload($event, $thresholdSettings); + $payload = $this->payloadService->generateThresholdPayload($event, $thresholdSettings, $viewName); $extras = [ 'client::display' => [ 'contentType' => 'text/markdown', diff --git a/app/Listeners/Ntfy/SendSpeedtestCompletedNotification.php b/app/Listeners/Ntfy/SendSpeedtestCompletedNotification.php index 652a4d09a..7cf60053a 100644 --- a/app/Listeners/Ntfy/SendSpeedtestCompletedNotification.php +++ b/app/Listeners/Ntfy/SendSpeedtestCompletedNotification.php @@ -43,8 +43,11 @@ public function handle(SpeedtestCompleted $event): void return; } + // Define the view name directly + $viewName = 'notifications.speedtest-completed'; - $payload = $this->payloadService->generateSpeedtestPayload($event); + // Generate the payload using the specified view + $payload = $this->payloadService->generateSpeedtestPayload($event, $viewName); foreach ($notificationSettings->ntfy_webhooks as $url) { try { diff --git a/app/Listeners/Ntfy/SendSpeedtestThresholdNotification.php b/app/Listeners/Ntfy/SendSpeedtestThresholdNotification.php index f01f4eb8e..ebe2d4aef 100644 --- a/app/Listeners/Ntfy/SendSpeedtestThresholdNotification.php +++ b/app/Listeners/Ntfy/SendSpeedtestThresholdNotification.php @@ -51,7 +51,10 @@ public function handle(SpeedtestCompleted $event): void return; } - $payload = $this->payloadService->generateThresholdPayload($event, $thresholdSettings); + // Define the view name directly + $viewName = 'notifications.speedtest-threshold'; + + $payload = $this->payloadService->generateThresholdPayload($event, $thresholdSettings, $viewName); if (empty($payload)) { Log::warning('Failed ntfy thresholds not found, won\'t send notification.'); diff --git a/app/Listeners/Pushover/SendSpeedtestCompletedNotification.php b/app/Listeners/Pushover/SendSpeedtestCompletedNotification.php index 465c98f9d..45ed80901 100644 --- a/app/Listeners/Pushover/SendSpeedtestCompletedNotification.php +++ b/app/Listeners/Pushover/SendSpeedtestCompletedNotification.php @@ -3,14 +3,23 @@ namespace App\Listeners\Pushover; use App\Events\SpeedtestCompleted; -use App\Helpers\Number; +use App\Services\SpeedtestCompletedNotificationPayload; use App\Settings\NotificationSettings; use Illuminate\Support\Facades\Log; -use Illuminate\Support\Str; -use Spatie\WebhookServer\WebhookCall; +use Serhiy\Pushover\Api\Message\Message; +use Serhiy\Pushover\Api\Message\Notification as PushoverNotification; +use Serhiy\Pushover\Application; +use Serhiy\Pushover\Recipient; class SendSpeedtestCompletedNotification { + protected $payloadService; + + public function __construct(SpeedtestCompletedNotificationPayload $payloadService) + { + $this->payloadService = $payloadService; + } + /** * Handle the event. */ @@ -18,46 +27,48 @@ public function handle(SpeedtestCompleted $event): void { $notificationSettings = new NotificationSettings(); - if (! $notificationSettings->pushover_enabled) { - return; - } - - if (! $notificationSettings->pushover_on_speedtest_run) { + // Check if Pushover notifications are enabled + if (! $notificationSettings->pushover_enabled || ! $notificationSettings->pushover_on_speedtest_run) { return; } + // Check if there are any Pushover webhooks if (! count($notificationSettings->pushover_webhooks)) { - Log::warning('Pushover urls not found, check Pushover notification channel settings.'); + Log::warning('Pushover URLs not found, check Pushover notification channel settings.'); return; } - $payload = [ - view('pushover.speedtest-completed', [ - 'id' => $event->result->id, - 'service' => Str::title($event->result->service), - 'serverName' => $event->result->server_name, - 'serverId' => $event->result->server_id, - 'isp' => $event->result->isp, - 'ping' => round($event->result->ping).' ms', - 'download' => Number::toBitRate(bits: $event->result->download_bits, precision: 2), - 'upload' => Number::toBitRate(bits: $event->result->upload_bits, precision: 2), - 'packetLoss' => $event->result->packet_loss, - 'speedtest_url' => $event->result->result_url, - 'url' => url('/admin/results'), - ])->render(), - ]; - - foreach ($notificationSettings->pushover_webhooks as $url) { - WebhookCall::create() - ->url($url['url']) - ->payload([ - 'token' => $url['api_token'], - 'user' => $url['user_key'], - 'message' => $payload, - ]) - ->doNotSign() - ->dispatch(); + // Define the view name directly + $viewName = 'pushover.speedtest-completed'; + + // Generate the payload using the specified view + $payload = $this->payloadService->generateSpeedtestPayload($event, $viewName); + + foreach ($notificationSettings->pushover_webhooks as $webhook) { + try { + // Create Application and Recipient objects + $application = new Application($webhook['api_token']); + $recipient = new Recipient($webhook['user_key']); + + // Compose the message with the payload as the body and a title + $message = new Message($payload, 'Speedtest Completed Notification'); + $message->setIsHtml(true); + + // Create a notification with the application, recipient, and message + $pushoverNotification = new PushoverNotification($application, $recipient, $message); + + // Push the notification + /** @var \Serhiy\Pushover\Client\Response\MessageResponse $response */ + $response = $pushoverNotification->push(); + + // Check response status + if (! $response->isSuccessful()) { + Log::error('Failed to send Pushover notification: '.$response->getMessage()); + } + } catch (\Exception $e) { + Log::error('An error occurred while sending Pushover notification: '.$e->getMessage()); + } } } } diff --git a/app/Listeners/Pushover/SendSpeedtestThresholdNotification.php b/app/Listeners/Pushover/SendSpeedtestThresholdNotification.php index 7643702f8..8d39878f9 100644 --- a/app/Listeners/Pushover/SendSpeedtestThresholdNotification.php +++ b/app/Listeners/Pushover/SendSpeedtestThresholdNotification.php @@ -4,14 +4,24 @@ use App\Events\SpeedtestCompleted; use App\Helpers\Number; +use App\Services\SpeedtestThresholdNotificationPayload; use App\Settings\NotificationSettings; use App\Settings\ThresholdSettings; use Illuminate\Support\Facades\Log; -use Illuminate\Support\Str; -use Spatie\WebhookServer\WebhookCall; +use Serhiy\Pushover\Api\Message\Message; +use Serhiy\Pushover\Api\Message\Notification as PushoverNotification; +use Serhiy\Pushover\Application; +use Serhiy\Pushover\Recipient; class SendSpeedtestThresholdNotification { + protected $payloadService; + + public function __construct(SpeedtestThresholdNotificationPayload $payloadService) + { + $this->payloadService = $payloadService; + } + /** * Handle the event. */ @@ -19,71 +29,54 @@ public function handle(SpeedtestCompleted $event): void { $notificationSettings = new NotificationSettings(); - if (! $notificationSettings->pushover_enabled) { - return; - } - - if (! $notificationSettings->pushover_on_threshold_failure) { + // Check if Pushover notifications are enabled and the threshold failure setting is enabled + if (! $notificationSettings->pushover_enabled || ! $notificationSettings->pushover_on_threshold_failure) { return; } + // Check if there are any Pushover webhooks if (! count($notificationSettings->pushover_webhooks)) { - Log::warning('Pushover urls not found, check Pushover notification channel settings.'); + Log::warning('Pushover URLs not found, check Pushover notification channel settings.'); return; } + // Get the threshold settings $thresholdSettings = new ThresholdSettings(); if (! $thresholdSettings->absolute_enabled) { return; } - $failed = []; + // Define the view name directly + $viewName = 'pushover.speedtest-threshold'; - if ($thresholdSettings->absolute_download > 0) { - array_push($failed, $this->absoluteDownloadThreshold(event: $event, thresholdSettings: $thresholdSettings)); - } + $payload = $this->payloadService->generateThresholdPayload($event, $thresholdSettings, $viewName); - if ($thresholdSettings->absolute_upload > 0) { - array_push($failed, $this->absoluteUploadThreshold(event: $event, thresholdSettings: $thresholdSettings)); - } - - if ($thresholdSettings->absolute_ping > 0) { - array_push($failed, $this->absolutePingThreshold(event: $event, thresholdSettings: $thresholdSettings)); - } + // Send the Pushover notification using the webhooks + foreach ($notificationSettings->pushover_webhooks as $webhook) { + try { + // Create Application and Recipient objects + $application = new Application($webhook['api_token']); + $recipient = new Recipient($webhook['user_key']); - $failed = array_filter($failed); + // Create a message with the payload as the body and a title + $message = new Message($payload, 'Speedtest Threshold Notification'); + $message->setIsHtml(true); - if (! count($failed)) { - Log::warning('Failed Pushover thresholds not found, won\'t send notification.'); + // Create and send the Pushover notification + $pushoverNotification = new PushoverNotification($application, $recipient, $message); - return; - } - - $payload = [ - view('pushover.speedtest-threshold', [ - 'id' => $event->result->id, - 'service' => Str::title($event->result->service), - 'serverName' => $event->result->server_name, - 'serverId' => $event->result->server_id, - 'isp' => $event->result->isp, - 'metrics' => $failed, - 'speedtest_url' => $event->result->result_url, - 'url' => url('/admin/results'), - ])->render(), - ]; + /** @var \Serhiy\Pushover\Client\Response\MessageResponse $response */ + $response = $pushoverNotification->push(); - foreach ($notificationSettings->pushover_webhooks as $url) { - WebhookCall::create() - ->url($url['url']) - ->payload([ - 'token' => $url['api_token'], - 'user' => $url['user_key'], - 'message' => $payload, - ]) - ->doNotSign() - ->dispatch(); + // Log if the notification failed + if (! $response->isSuccessful()) { + Log::error('Failed to send Pushover notification: '.$response->getMessage()); + } + } catch (\Exception $e) { + Log::error('An error occurred while sending Pushover notification: '.$e->getMessage()); + } } } diff --git a/app/Services/SpeedtestCompletedNotificationPayload.php b/app/Services/SpeedtestCompletedNotificationPayload.php index 213c4e9a1..26f5378c8 100644 --- a/app/Services/SpeedtestCompletedNotificationPayload.php +++ b/app/Services/SpeedtestCompletedNotificationPayload.php @@ -11,9 +11,9 @@ class SpeedtestCompletedNotificationPayload /** * Generate the payload for the speedtest completed notification. */ - public function generateSpeedtestPayload(SpeedtestCompleted $event): string + public function generateSpeedtestPayload(SpeedtestCompleted $event, string $viewName): string { - return view('notifications.speedtest-completed', [ + return view($viewName, [ 'id' => $event->result->id, 'service' => Str::title($event->result->service), 'serverName' => $event->result->server_name, diff --git a/app/Services/SpeedtestThresholdNotificationPayload.php b/app/Services/SpeedtestThresholdNotificationPayload.php index 085f56cb6..7804f8584 100644 --- a/app/Services/SpeedtestThresholdNotificationPayload.php +++ b/app/Services/SpeedtestThresholdNotificationPayload.php @@ -12,7 +12,7 @@ class SpeedtestThresholdNotificationPayload /** * Generate the payload for the speedtest threshold notification. */ - public function generateThresholdPayload(SpeedtestCompleted $event, ThresholdSettings $thresholdSettings): string + public function generateThresholdPayload(SpeedtestCompleted $event, ThresholdSettings $thresholdSettings, string $viewName): string { $failed = []; @@ -30,7 +30,7 @@ public function generateThresholdPayload(SpeedtestCompleted $event, ThresholdSet $failed = array_filter($failed); - return view('notifications.speedtest-threshold', [ + return view($viewName, [ 'id' => $event->result->id, 'service' => Str::title($event->result->service), 'serverName' => $event->result->server_name, diff --git a/composer.json b/composer.json index e04748d9d..75849f11b 100644 --- a/composer.json +++ b/composer.json @@ -25,6 +25,7 @@ "livewire/livewire": "^3.5.4", "lorisleiva/laravel-actions": "^2.8.1", "maennchen/zipstream-php": "^2.4", + "serhiy/pushover": "^1.6", "spatie/laravel-settings": "^3.3.2", "spatie/laravel-webhook-server": "^3.8.1", "timokoerber/laravel-one-time-operations": "^1.4.2", diff --git a/composer.lock b/composer.lock index b0584df45..763c82097 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "5548136a2fe01d566521f25978af8be4", + "content-hash": "c8530017d648dec5a6b6f440cfb08fcc", "packages": [ { "name": "anourvalar/eloquent-serialize", @@ -6115,6 +6115,64 @@ ], "time": "2024-02-26T18:08:49+00:00" }, + { + "name": "serhiy/pushover", + "version": "v1.6.0", + "source": { + "type": "git", + "url": "https://github.com/slunak/pushover-php.git", + "reference": "b7cc7ffbb04d9558ccac02f882ee6bde3e8e81e9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/slunak/pushover-php/zipball/b7cc7ffbb04d9558ccac02f882ee6bde3e8e81e9", + "reference": "b7cc7ffbb04d9558ccac02f882ee6bde3e8e81e9", + "shasum": "" + }, + "require": { + "ext-curl": "*", + "ext-json": "*", + "php": ">=7.4" + }, + "require-dev": { + "ergebnis/composer-normalize": "^2.43", + "ergebnis/php-cs-fixer-config": "^6.34", + "friendsofphp/php-cs-fixer": "^3.61", + "phpstan/phpstan": "^1.11", + "phpunit/phpunit": "*", + "rector/rector": "^1.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "Serhiy\\Pushover\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Serhiy Lunak", + "email": "serhiy.lunak@gmail.com", + "role": "Developer" + } + ], + "description": "Light, simple and fast, yet comprehensive wrapper for the Pushover API.", + "homepage": "https://github.com/slunak/pushover-php", + "keywords": [ + "client", + "pushover", + "pushover.net", + "wrapper" + ], + "support": { + "issues": "https://github.com/slunak/pushover-php/issues", + "source": "https://github.com/slunak/pushover-php/tree/v1.6.0" + }, + "time": "2024-08-29T08:23:58+00:00" + }, { "name": "spatie/color", "version": "1.5.3", diff --git a/resources/views/pushover/speedtest-completed.blade.php b/resources/views/pushover/speedtest-completed.blade.php index 2a209023c..38e362f40 100644 --- a/resources/views/pushover/speedtest-completed.blade.php +++ b/resources/views/pushover/speedtest-completed.blade.php @@ -1,13 +1,13 @@ -Speedtest Completed - #{{ $id }} +Speedtest Completed - #{{ $id }} -A new speedtest was completed using {{ $service }}. +A new speedtest was completed using {{ $service }}. -- Server name: {{ $serverName }} -- Server ID: {{ $serverId }} -- ISP: {{ $isp }} -- Ping: {{ $ping }} -- Download: {{ $download }} -- Upload: {{ $upload }} -- Packet Loss: {{ $packetLoss }} % -- Ookla Speedtest: {{ $speedtest_url }} -- URL: {{ $url }} +- Server name: {{ $serverName }} +- Server ID: {{ $serverId }} +- ISP: {{ $isp }} +- Ping: {{ $ping }} +- Download: {{ $download }} +- Upload: {{ $upload }} +- Packet Loss: {{ $packetLoss }} % +- Ookla Speedtest: {{ $speedtest_url }} +- URL: {{ $url }} diff --git a/resources/views/pushover/speedtest-threshold.blade.php b/resources/views/pushover/speedtest-threshold.blade.php index 4a7fe325e..d2931b67c 100644 --- a/resources/views/pushover/speedtest-threshold.blade.php +++ b/resources/views/pushover/speedtest-threshold.blade.php @@ -1,9 +1,9 @@ -Speedtest Threshold Breached - #{{ $id }} +Speedtest Threshold Breached - #{{ $id }} -A new speedtest was completed using {{ $service }} on {{ $isp }} but a threshold was breached. +A new speedtest was completed using {{ $service }} on {{ $isp }} but a threshold was breached. @foreach ($metrics as $item) -- {{ $item['name'] }} {{ $item['threshold'] }}: {{ $item['value'] }} +- {{ $item['name'] }} {{ $item['threshold'] }}: {{ $item['value'] }} @endforeach -- Ookla Speedtest: {{ $speedtest_url }} -- URL: {{ $url }} +- Ookla Speedtest: {{ $speedtest_url }} +- URL: {{ $url }}