Skip to content
Merged
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
58 changes: 0 additions & 58 deletions app/Filament/Resources/Results/Tables/ResultTable.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
use App\Enums\ResultStatus;
use App\Filament\Exports\ResultExporter;
use App\Helpers\Number;
use App\Jobs\TruncateResults;
use App\Models\Result;
use Filament\Actions\Action;
use Filament\Actions\ActionGroup;
Expand Down Expand Up @@ -102,26 +101,6 @@ public static function table(Table $table): Table
return number_format((float) $state, 0, '.', '').' ms';
}),

TextColumn::make('data.download.latency.high')
->label(__('results.download_latency_high'))
->toggleable(isToggledHiddenByDefault: true)
->sortable(query: function (Builder $query, string $direction): Builder {
return $query->orderBy('data->download->latency->high', $direction);
})
->formatStateUsing(function ($state) {
return number_format((float) $state, 0, '.', '').' ms';
}),

TextColumn::make('data.download.latency.low')
->label(__('results.download_latency_low'))
->toggleable(isToggledHiddenByDefault: true)
->sortable(query: function (Builder $query, string $direction): Builder {
return $query->orderBy('data->download->latency->low', $direction);
})
->formatStateUsing(function ($state) {
return number_format((float) $state, 0, '.', '').' ms';
}),

TextColumn::make('data.upload.latency.jitter')
->label(__('results.upload_latency_jitter'))
->toggleable(isToggledHiddenByDefault: true)
Expand All @@ -132,26 +111,6 @@ public static function table(Table $table): Table
return number_format((float) $state, 0, '.', '').' ms';
}),

TextColumn::make('data.upload.latency.high')
->label(__('results.upload_latency_high'))
->toggleable(isToggledHiddenByDefault: true)
->sortable(query: function (Builder $query, string $direction): Builder {
return $query->orderBy('data->upload->latency->high', $direction);
})
->formatStateUsing(function ($state) {
return number_format((float) $state, 0, '.', '').' ms';
}),

TextColumn::make('data.upload.latency.low')
->label(__('results.upload_latency_low'))
->toggleable(isToggledHiddenByDefault: true)
->sortable(query: function (Builder $query, string $direction): Builder {
return $query->orderBy('data->upload->latency->low', $direction);
})
->formatStateUsing(function ($state) {
return number_format((float) $state, 0, '.', '').' ms';
}),

IconColumn::make('healthy')
->label(__('general.healthy'))
->boolean()
Expand All @@ -175,8 +134,6 @@ public static function table(Table $table): Table
->toggleable(isToggledHiddenByDefault: true)
->sortable(),
])
->deferFilters(false)
->deferColumnManager(false)
->filters([
Filter::make('created_at')
->label(__('general.created_at'))
Expand Down Expand Up @@ -293,30 +250,15 @@ public static function table(Table $table): Table
])
->toolbarActions([
DeleteBulkAction::make(),
])
->headerActions([
ExportAction::make()
->exporter(ResultExporter::class)
->columnMapping(false)
->modalHeading(__('results.export_all_results'))
->modalDescription(__('results.export_all_results_description'))
->fileName(fn (): string => 'results-'.now()->timestamp),
ActionGroup::make([
Action::make('truncate')
->label(__('results.truncate_results'))
->action(fn () => TruncateResults::dispatch(Auth::user()))
->requiresConfirmation()
->modalHeading(__('results.truncate_results'))
->modalDescription(__('results.truncate_results_description'))
->color('danger')
->icon('heroicon-o-trash')
->hidden(fn (): bool => ! Auth::user()->is_admin),
])
->dropdownPlacement('left-start'),
])
->defaultSort('id', 'desc')
->paginationPageOptions([10, 25, 50])
->deferLoading()
->poll('60s');
}
}
48 changes: 0 additions & 48 deletions app/Jobs/TruncateResults.php

This file was deleted.

22 changes: 22 additions & 0 deletions app/Livewire/NextSpeedtestBanner.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

namespace App\Livewire;

use App\Services\ScheduledSpeedtestService;
use Carbon\Carbon;
use Livewire\Attributes\Computed;
use Livewire\Component;

class NextSpeedtestBanner extends Component
{
#[Computed]
public function nextSpeedtest(): ?Carbon
{
return ScheduledSpeedtestService::getNextScheduledTest();
}

public function render()
{
return view('livewire.next-speedtest-banner');
}
}
14 changes: 0 additions & 14 deletions app/Livewire/PlatformStats.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,12 @@

use App\Enums\ResultStatus;
use App\Models\Result;
use Carbon\Carbon;
use Cron\CronExpression;
use Illuminate\Support\Number;
use Livewire\Attributes\Computed;
use Livewire\Component;

class PlatformStats extends Component
{
#[Computed]
public function nextSpeedtest(): ?Carbon
{
if ($schedule = config('speedtest.schedule')) {
$cronExpression = new CronExpression($schedule);

return Carbon::parse(time: $cronExpression->getNextRunDate(timeZone: config('app.display_timezone')));
}

return null;
}

#[Computed]
public function platformStats(): array
{
Expand Down
29 changes: 29 additions & 0 deletions app/Services/ScheduledSpeedtestService.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

namespace App\Services;

use Carbon\Carbon;
use Cron\CronExpression;

class ScheduledSpeedtestService
{
/**
* Assess if there are scheduled speedtests and return the next scheduled time.
*
* @return Carbon|null Returns null if no tests are scheduled, or Carbon instance with next scheduled test
*/
public static function getNextScheduledTest(): ?Carbon
{
$schedule = config('speedtest.schedule');

if (blank($schedule) || $schedule === false) {
return null;
}

$cronExpression = new CronExpression($schedule);

return Carbon::parse(
time: $cronExpression->getNextRunDate(timeZone: config('app.display_timezone'))
);
}
}
4 changes: 2 additions & 2 deletions config/speedtest.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
/**
* General settings.
*/
'build_date' => Carbon::parse('2025-12-05'),
'build_date' => Carbon::parse('2025-12-06'),

'build_version' => 'v1.12.0',
'build_version' => 'v1.12.1',

'content_width' => env('CONTENT_WIDTH', '7xl'),

Expand Down
3 changes: 0 additions & 3 deletions lang/en/results.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,6 @@

// Actions
'update_comments' => 'Update comments',
'truncate_results' => 'Truncate results',
'truncate_results_description' => 'Are you sure you want to truncate all results? This action is irreversible.',
'truncate_results_success' => 'Results table truncated!',
'view_on_speedtest_net' => 'View on Speedtest.net',

// Notifications
Expand Down
6 changes: 5 additions & 1 deletion resources/views/dashboard.blade.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
<x-app-layout title="Dashboard">
<div class="space-y-6 md:space-y-12 dashboard-page">
<livewire:platform-stats />
<livewire:next-speedtest-banner />

@auth
<livewire:platform-stats />
@endauth

<livewire:latest-result-stats />

Expand Down
2 changes: 2 additions & 0 deletions resources/views/filament/pages/dashboard.blade.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<x-filament-panels::page class="dashboard-page">
<div class="space-y-6 md:space-y-12">
<livewire:next-speedtest-banner />

<livewire:platform-stats />

<livewire:latest-result-stats />
Expand Down
26 changes: 16 additions & 10 deletions resources/views/livewire/latest-result-stats.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,14 @@
@filled($downloadBenchmark)
<x-slot name="afterHeader">
<span @class([
'inline-flex items-center gap-x-1.5 text-xs font-medium underline decoration-dotted decoration-1 decoration-zinc-500 underline-offset-4',
'text-zinc-700 dark:text-zinc-300' => $downloadBenchmarkPassed,
'inline-flex items-center gap-x-1 text-xs font-medium underline decoration-dotted decoration-1 decoration-zinc-500 underline-offset-4',
'text-green-500 dark:text-green-400' => $downloadBenchmarkPassed,
'text-amber-500 dark:text-amber-400' => ! $downloadBenchmarkPassed,
]) title="Benchmark {{ $downloadBenchmarkPassed ? 'passed' : 'failed' }}">
@if (! $downloadBenchmarkPassed)
<x-tabler-alert-triangle class="size-4" />
@if ($downloadBenchmarkPassed)
<x-tabler-circle-check class="size-4" />
@else
<x-tabler-alert-circle class="size-4" />
@endif
{{ Arr::get($downloadBenchmark, 'value').' '.str(Arr::get($downloadBenchmark, 'unit'))->title() }}
</span>
Expand Down Expand Up @@ -74,11 +76,13 @@
@filled($uploadBenchmark)
<x-slot name="afterHeader">
<span @class([
'inline-flex items-center gap-x-1.5 text-xs font-medium underline decoration-dotted decoration-1 decoration-zinc-500 underline-offset-4',
'text-zinc-700 dark:text-zinc-300' => $uploadBenchmarkPassed,
'inline-flex items-center gap-x-1 text-xs font-medium underline decoration-dotted decoration-1 decoration-zinc-500 underline-offset-4',
'text-green-500 dark:text-green-400' => $uploadBenchmarkPassed,
'text-amber-500 dark:text-amber-400' => ! $uploadBenchmarkPassed,
]) title="Benchmark {{ $uploadBenchmarkPassed ? 'passed' : 'failed' }}">
@if (! $uploadBenchmarkPassed)
@if ($uploadBenchmarkPassed)
<x-tabler-circle-check class="size-4" />
@else
<x-tabler-alert-triangle class="size-4" />
@endif
{{ Arr::get($uploadBenchmark, 'value').' '.str(Arr::get($uploadBenchmark, 'unit'))->title() }}
Expand Down Expand Up @@ -111,11 +115,13 @@
@filled($pingBenchmark)
<x-slot name="afterHeader">
<span @class([
'inline-flex items-center gap-x-1.5 text-xs font-medium underline decoration-dotted decoration-1 decoration-zinc-500 underline-offset-4',
'text-zinc-700 dark:text-zinc-300' => $pingBenchmarkPassed,
'inline-flex items-center gap-x-1 text-xs font-medium underline decoration-dotted decoration-1 decoration-zinc-500 underline-offset-4',
'text-green-500 dark:text-green-400' => $pingBenchmarkPassed,
'text-amber-500 dark:text-amber-400' => ! $pingBenchmarkPassed,
]) title="Benchmark {{ $pingBenchmarkPassed ? 'passed' : 'failed' }}">
@if (! $pingBenchmarkPassed)
@if ($pingBenchmarkPassed)
<x-tabler-circle-check class="size-4" />
@else
<x-tabler-alert-triangle class="size-4" />
@endif
{{ Arr::get($pingBenchmark, 'value').' '.str(Arr::get($pingBenchmark, 'unit')) }}
Expand Down
17 changes: 17 additions & 0 deletions resources/views/livewire/next-speedtest-banner.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<div wire:poll.60s>
@if ($this->nextSpeedtest)
<div class="rounded-md bg-blue-50 dark:bg-blue-500/10 p-4 outline outline-blue-500/20">
<div class="flex">
<div class="shrink-0">
<x-tabler-info-circle class="size-5 text-blue-400" />
</div>

<div class="ml-3 flex-1">
<p class="text-sm text-blue-700 dark:text-blue-300">
Next scheduled test at <span class="font-medium">{{ $this->nextSpeedtest->timezone(config('app.display_timezone'))->format('F jS, Y, g:i a') }}</span>.
</p>
</div>
</div>
</div>
@endif
</div>
26 changes: 4 additions & 22 deletions resources/views/livewire/platform-stats.blade.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<div wire:poll.60s>
<div class="grid grid-cols-1 md:grid-cols-4 gap-6">
<div class="grid grid-cols-1 md:grid-cols-3 gap-6">
<h2 class="flex items-center gap-x-2 text-base md:text-lg font-semibold text-zinc-900 dark:text-zinc-100 col-span-full">
<x-tabler-chart-bar class="size-5" />
{{ __('general.statistics') }}
Expand All @@ -23,41 +23,23 @@
</div>
</x-filament::section> --}}

@filled($this->nextSpeedtest)
<x-filament::section class="col-span-1">
<x-slot name="heading">
Next Speedtest in
</x-slot>

<p class="text-xl font-semibold tracking-tight text-zinc-900 dark:text-zinc-100" title="{{ $this->nextSpeedtest->format('F jS, Y g:i A') }}">{{ $this->nextSpeedtest->diffForHumans() }}</p>
</x-filament::section>
@else
<x-filament::section class="col-span-1 bg-zinc-100 shadow-none">
<x-slot name="heading">
Next Speedtest in
</x-slot>

<p class="text-xl font-semibold tracking-tight text-zinc-900 dark:text-zinc-100">No scheduled speedtests</p>
</x-filament::section>
@endfilled

<x-filament::section class="col-span-1">
<x-filament::section class="col-span-1" icon="tabler-hash">
<x-slot name="heading">
Total tests
</x-slot>

<p class="text-xl font-semibold tracking-tight text-zinc-900 dark:text-zinc-100">{{ $this->platformStats['total'] }}</p>
</x-filament::section>

<x-filament::section class="col-span-1">
<x-filament::section class="col-span-1" icon="tabler-circle-check">
<x-slot name="heading">
Total completed tests
</x-slot>

<p class="text-xl font-semibold tracking-tight text-zinc-900 dark:text-zinc-100">{{ $this->platformStats['completed'] }}</p>
</x-filament::section>

<x-filament::section class="col-span-1">
<x-filament::section class="col-span-1" icon="tabler-alert-circle">
<x-slot name="heading">
Total failed tests
</x-slot>
Expand Down
Loading
Loading