Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 62 additions & 0 deletions app/Actions/LatencyTests/RunScheduledLatencyTests.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<?php

namespace App\Actions\LatencyTests;

use App\Jobs\Latency\ExecuteLatencyTest;
use App\Settings\LatencySettings;
use Cron\CronExpression;
use Illuminate\Support\Facades\Log;
use Lorisleiva\Actions\Concerns\AsAction;

class RunScheduledLatencyTests
{
use AsAction;

public function handle(): void
{
$settings = $this->getSettings();

// Check if latency tests are enabled
if (! $settings->latency_enabled) {
Log::info('Latency tests are disabled in the settings. Exiting.');

return;
}

// Proceed with scheduling checks if enabled
$cronExpression = new CronExpression($settings->latency_schedule);
$now = now()->timezone(config('app.display_timezone'));

Log::info('Checking if latency test is due.', [
'current_time' => $now,
'is_due' => $cronExpression->isDue($now),
]);

if (! $cronExpression->isDue($now)) {
Log::info('Latency test is not due. Exiting.');

return;
}

$urls = $settings->target_url;
Log::info('Running latency tests for URLs', ['urls' => $urls]);

foreach ($urls as $urlItem) {
if (is_array($urlItem) && isset($urlItem['url']) && is_string($urlItem['url'])) {
$url = trim($urlItem['url']);
$target_name = $urlItem['target_name'] ?? 'Unnamed'; // Default to 'Unnamed' if no name is provided
if ($url) {
Log::info('Dispatching latency test', ['url' => $url, 'name' => $target_name]);
ExecuteLatencyTest::dispatch($url, $target_name);
}
} else {
Log::warning('Skipping invalid URL entry', ['urlItem' => $urlItem]);
}
}
}

protected function getSettings(): LatencySettings
{
return app(LatencySettings::class);
}
}
31 changes: 31 additions & 0 deletions app/Enums/ThresholdBreached.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

namespace App\Enums;

use Filament\Support\Contracts\HasColor;
use Filament\Support\Contracts\HasLabel;

enum ThresholdBreached: string implements HasColor, HasLabel
{
case Failed = 'Failed';
case Passed = 'Passed';
case NotChecked = 'NotChecked';

public function getColor(): ?string
{
return match ($this) {
self::Failed => 'danger',
self::Passed => 'success',
self::NotChecked => 'warning',
};
}

public function getLabel(): ?string
{
return match ($this) {
self::Failed => 'Failed',
self::Passed => 'Passed',
self::NotChecked => 'NotChecked',
};
}
}
5 changes: 5 additions & 0 deletions app/Filament/Exports/ResultExporter.php
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,11 @@ public static function getColumns(): array
}),
ExportColumn::make('comments')
->enabledByDefault(false),
ExportColumn::make('threshold_breached')
->enabledByDefault(false)
->state(function (Result $record): string {
return $record->threshold_breached;
}),
// ExportColumn::make('status'), // TODO: enable status when upgrading to PHP v8.3: https://php.watch/versions/8.3/dynamic-class-const-enum-member-syntax-support
ExportColumn::make('scheduled')
->state(function (Result $record): string {
Expand Down
30 changes: 16 additions & 14 deletions app/Filament/Pages/Dashboard.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,10 @@
namespace App\Filament\Pages;

use App\Actions\Speedtests\RunOoklaSpeedtest;
use App\Filament\Widgets\RecentDownloadChartWidget;
use App\Filament\Widgets\RecentDownloadLatencyChartWidget;
use App\Filament\Widgets\RecentJitterChartWidget;
use App\Filament\Widgets\RecentPingChartWidget;
use App\Filament\Widgets\RecentUploadChartWidget;
use App\Filament\Widgets\RecentUploadLatencyChartWidget;
use App\Filament\Widgets\StatsOverviewWidget;
use App\Filament\Widgets\Latency\DashboardLatencyChartWidget;
use App\Filament\Widgets\Speedtest\DashboardDownloadUploadChartWidget;
use App\Filament\Widgets\Speedtest\StatsOverviewWidget;
use App\Settings\LatencySettings;
use Carbon\Carbon;
use Cron\CronExpression;
use Filament\Actions\Action;
Expand Down Expand Up @@ -81,14 +78,19 @@ protected function getHeaderActions(): array

protected function getHeaderWidgets(): array
{
return [
$widgets = [
StatsOverviewWidget::make(),
RecentDownloadChartWidget::make(),
RecentUploadChartWidget::make(),
RecentPingChartWidget::make(),
RecentJitterChartWidget::make(),
RecentDownloadLatencyChartWidget::make(),
RecentUploadLatencyChartWidget::make(),
DashboardDownloadUploadChartWidget::make(),
];

// Get the settings instance
$settings = app(LatencySettings::class);

// Check if latency tests are enabled
if ($settings->latency_enabled) {
$widgets[] = DashboardLatencyChartWidget::make();
}

return $widgets;
}
}
71 changes: 71 additions & 0 deletions app/Filament/Pages/Latency/Latency.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
<?php

namespace App\Filament\Pages\Latency;

use App\Filament\Widgets\Latency\RecentLatencyChartWidget;
use App\Models\LatencyResult;
use App\Settings\LatencySettings;
use Carbon\Carbon;
use Cron\CronExpression;
use Filament\Pages\Page;

class Latency extends Page
{
protected static ?string $navigationIcon = 'heroicon-o-globe-alt';

protected static string $view = 'filament.pages.latency-results-page';

protected static ?string $navigationGroup = 'Latency';

protected static ?string $navigationLabel = 'Overview';

public function getSubheading(): ?string
{
$settings = app(LatencySettings::class);

if (! $settings->latency_enabled || blank($settings->latency_schedule)) {
return __('No latency tests scheduled.');
}

$cronExpression = new CronExpression($settings->latency_schedule);

$nextRunDate = Carbon::parse($cronExpression->getNextRunDate())
->setTimezone(config('app.display_timezone'))
->format(config('app.datetime_format'));

return 'Next latency test at: '.$nextRunDate;
}

public function getData()
{
// Retrieve distinct target names
$target_names = LatencyResult::distinct()->pluck('target_name');

return [
'target_names' => $target_names,
'filters' => $this->getFilters(),
];
}

protected function getFilters(): array
{
return [
'24h' => 'Last 24h',
'week' => 'Last week',
'month' => 'Last month',
];
}

protected function getHeaderWidgets(): array
{
$target_names = $this->getData()['target_names'];

$widgets = [];
foreach ($target_names as $target_name) {
$widget = RecentLatencyChartWidget::make(['target_name' => $target_name]); // Pass target_name during creation
$widgets[] = $widget;
}

return $widgets;
}
}
2 changes: 1 addition & 1 deletion app/Filament/Pages/Settings/InfluxDbPage.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class InfluxDbPage extends SettingsPage

protected static ?string $navigationGroup = 'Settings';

protected static ?int $navigationSort = 2;
protected static ?int $navigationSort = 5;

protected static ?string $title = 'InfluxDB';

Expand Down
123 changes: 123 additions & 0 deletions app/Filament/Pages/Settings/LatencySettingsPage.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
<?php

namespace App\Filament\Pages\Settings;

use App\Settings\LatencySettings;
use Filament\Forms;
use Filament\Forms\Form;
use Filament\Pages\SettingsPage;

class LatencySettingsPage extends SettingsPage
{
protected static ?string $navigationIcon = 'heroicon-o-cog';

protected static ?string $navigationGroup = 'Settings';

protected static ?int $navigationSort = 1;

protected static ?string $title = 'Latency Settings';

protected static ?string $navigationLabel = 'Latency Settings';

protected static string $settings = LatencySettings::class;

public static function canAccess(): bool
{
return auth()->user()->is_admin;
}

public static function shouldRegisterNavigation(): bool
{
return auth()->user()->is_admin;
}

public function form(Form $form): Form
{
return $form
->schema([
Forms\Components\Grid::make([
'default' => 1,
'md' => 3,
])
->schema([
Forms\Components\Grid::make([
'default' => 1,
])
->schema([
Forms\Components\Section::make('General')
->schema([
Forms\Components\Toggle::make('latency_enabled')
->label('Enable Latency Tests')
->default(false)
->reactive(),
Forms\Components\Grid::make([
'default' => 2,
])
->hidden(fn (Forms\Get $get) => $get('latency_enabled') !== true)
->schema([
Forms\Components\TextInput::make('ping_count')
->label('Ping Count')
->helperText('Number of pings to send during the test.')
->default(10)
->minValue(1)
->numeric()
->required(),
Forms\Components\TextInput::make('latency_schedule')
->label('Cron Expression')
->helperText('Specify the cron expression for scheduling tests.')
->required(),
Forms\Components\Select::make('latency_column_span')
->label('View')
->options([
'full' => 'List view',
'half' => 'Grid view',
])
->default('full')
->required(),
]),
])
->compact()
->columns([
'default' => 1,
'md' => 2,
]),

Forms\Components\Section::make('Targets')
->hidden(fn (Forms\Get $get) => $get('latency_enabled') !== true)
->collapsible()
->schema([
Forms\Components\Repeater::make('target_url')
->label('Targets')
->schema([
Forms\Components\TextInput::make('target_name')
->label('Display Name')
->placeholder('Enter a display name')
->maxLength(100)
->required(),
Forms\Components\TextInput::make('url')
->label('Target')
->placeholder('example.com')
->maxLength(2000)
->required(),
])
->columns([
'default' => 1,
'md' => 2,
]),
]),
])
->columnSpan([
'md' => 2,
]),

Forms\Components\Section::make()
->schema([
Forms\Components\View::make('filament.forms.latency-helptext'),
])
->columnSpan([
'md' => 1,
]),
]),
]);
}
}
2 changes: 1 addition & 1 deletion app/Filament/Pages/Settings/NotificationPage.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ class NotificationPage extends SettingsPage

protected static ?string $navigationGroup = 'Settings';

protected static ?int $navigationSort = 3;
protected static ?int $navigationSort = 2;

protected static ?string $title = 'Notifications';

Expand Down
2 changes: 1 addition & 1 deletion app/Filament/Pages/Settings/ThresholdsPage.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class ThresholdsPage extends SettingsPage

protected static ?string $navigationGroup = 'Settings';

protected static ?int $navigationSort = 4;
protected static ?int $navigationSort = 3;

protected static ?string $title = 'Thresholds';

Expand Down
Loading