Add all files

This commit is contained in:
root
2025-11-30 11:57:22 +01:00
parent 2ee51cac4f
commit 044271db3d
1476 changed files with 142544 additions and 0 deletions

View File

@@ -0,0 +1,156 @@
<?php
namespace Paymenter\Extensions\Others\UptimeLab\Admin\Resources;
use Filament\Forms;
use Filament\Forms\Form;
use Filament\Resources\Resource;
use Filament\Tables;
use Filament\Tables\Table;
use Paymenter\Extensions\Others\UptimeLab\Admin\Resources\UptimeServerResource\Pages;
use Paymenter\Extensions\Others\UptimeLab\Models\UptimeServer;
class UptimeServerResource extends Resource
{
protected static ?string $model = UptimeServer::class;
// No icon to avoid errors
// protected static ?string $navigationIcon = 'ri-home';
// protected static ?string $activeNavigationIcon = 'ri-home-fill';
protected static ?string $navigationGroup = 'Server Uptimes';
protected static ?string $navigationLabel = 'Servers';
protected static ?string $navigationIcon = 'heroicon-o-clock';
public static function form(Form $form): Form
{
return $form
->schema([
Forms\Components\Section::make('Server Information')
->schema([
Forms\Components\TextInput::make('name')
->label('Server Name')
->required()
->maxLength(255)
->placeholder('Enter the name of the server'),
Forms\Components\Select::make('server_type')
->label('Fetch Type')
->required()
->options([
'ip' => 'IP Address',
'subdomain' => 'Subdomain',
])
->default('ip')
->placeholder('Select server type'),
Forms\Components\TextInput::make('ip_address')
->label('IP Address / Subdomain')
->required()
->maxLength(255)
->placeholder('Enter IP address or subdomain'),
Forms\Components\TextInput::make('location')
->label('Server Location')
->required()
->maxLength(255)
->placeholder('Enter server location (e.g., Columbus, Ohio)'),
Forms\Components\Toggle::make('is_active')
->label('Active')
->default(true)
->helperText('Enable or disable uptime monitoring for this server'),
])->columns(2),
// Credit Section
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
Tables\Columns\TextColumn::make('name')
->label('Server Name')
->searchable()
->sortable(),
Tables\Columns\TextColumn::make('ip_address')
->label('IP/Subdomain')
->searchable()
->sortable(),
Tables\Columns\TextColumn::make('location')
->label('Location')
->searchable()
->sortable(),
Tables\Columns\IconColumn::make('status')
->label('Status')
->boolean()
->trueIcon('ri-checkbox-circle-line')
->falseIcon('ri-close-circle-line')
->trueColor('success')
->falseColor('danger')
->sortable(),
Tables\Columns\TextColumn::make('uptime_percentage')
->label('Uptime')
->suffix('%')
->numeric(
decimalPlaces: 2,
decimalSeparator: '.',
thousandsSeparator: ',',
)
->sortable(),
Tables\Columns\TextColumn::make('last_check')
->label('Last Check')
->dateTime()
->sortable(),
Tables\Columns\IconColumn::make('is_active')
->label('Active')
->boolean()
->sortable(),
])
->filters([
Tables\Filters\SelectFilter::make('status')
->options([
'online' => 'Online',
'offline' => 'Offline',
]),
Tables\Filters\TernaryFilter::make('is_active')
->label('Active Status'),
])
->actions([
Tables\Actions\EditAction::make(),
Tables\Actions\Action::make('check_status')
->label('Check Status')
->icon('ri-refresh-line')
->action(function (UptimeServer $record) {
// This will be implemented in the service
$record->update([
'last_check' => now(),
]);
}),
])
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(),
]),
]);
}
public static function getPages(): array
{
return [
'index' => Pages\ListUptimeServers::route('/'),
'create' => Pages\CreateUptimeServer::route('/create'),
'edit' => Pages\EditUptimeServer::route('/{record}/edit'),
];
}
}

View File

@@ -0,0 +1,11 @@
<?php
namespace Paymenter\Extensions\Others\UptimeLab\Admin\Resources\UptimeServerResource\Pages;
use Paymenter\Extensions\Others\UptimeLab\Admin\Resources\UptimeServerResource;
use Filament\Resources\Pages\CreateRecord;
class CreateUptimeServer extends CreateRecord
{
protected static string $resource = UptimeServerResource::class;
}

View File

@@ -0,0 +1,19 @@
<?php
namespace Paymenter\Extensions\Others\UptimeLab\Admin\Resources\UptimeServerResource\Pages;
use Paymenter\Extensions\Others\UptimeLab\Admin\Resources\UptimeServerResource;
use Filament\Actions;
use Filament\Resources\Pages\EditRecord;
class EditUptimeServer extends EditRecord
{
protected static string $resource = UptimeServerResource::class;
protected function getHeaderActions(): array
{
return [
Actions\DeleteAction::make(),
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace Paymenter\Extensions\Others\UptimeLab\Admin\Resources\UptimeServerResource\Pages;
use Paymenter\Extensions\Others\UptimeLab\Admin\Resources\UptimeServerResource;
use Filament\Actions;
use Filament\Resources\Pages\ListRecords;
class ListUptimeServers extends ListRecords
{
protected static string $resource = UptimeServerResource::class;
protected function getHeaderActions(): array
{
return [
Actions\CreateAction::make(),
];
}
}

View File

@@ -0,0 +1,83 @@
<?php
namespace Paymenter\Extensions\Others\UptimeLab\Console\Commands;
use Illuminate\Console\Command;
use Paymenter\Extensions\Others\UptimeLab\Services\UptimeMonitoringService;
class CheckUptimeCommand extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'uptime:check {--server= : Check specific server by ID}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Check uptime status of all servers or a specific server';
/**
* Execute the console command.
*/
public function handle()
{
$monitoringService = new UptimeMonitoringService();
if ($serverId = $this->option('server')) {
$this->checkSpecificServer($serverId, $monitoringService);
} else {
$this->checkAllServers($monitoringService);
}
}
/**
* Check all active servers
*/
private function checkAllServers(UptimeMonitoringService $monitoringService): void
{
$this->info('Starting uptime check for all active servers...');
try {
$monitoringService->checkAllServers();
$this->info('Uptime check completed successfully!');
} catch (\Exception $e) {
$this->error('Uptime check failed: ' . $e->getMessage());
}
}
/**
* Check a specific server
*/
private function checkSpecificServer(string $serverId, UptimeMonitoringService $monitoringService): void
{
$this->info("Starting uptime check for server ID: {$serverId}...");
try {
$server = \Paymenter\Extensions\Others\UptimeLab\Models\UptimeServer::find($serverId);
if (!$server) {
$this->error("Server with ID {$serverId} not found.");
return;
}
$checkResult = $monitoringService->checkServerStatus($server);
$monitoringService->updateServerStatus($server, $checkResult);
$status = $checkResult['online'] ? 'ONLINE' : 'OFFLINE';
$responseTime = $checkResult['response_time'] ? $checkResult['response_time'] . 'ms' : 'N/A';
$this->info("Server: {$server->name}");
$this->info("Status: {$status}");
$this->info("Response Time: {$responseTime}");
$this->info("Uptime check completed successfully!");
} catch (\Exception $e) {
$this->error('Uptime check failed: ' . $e->getMessage());
}
}
}

View File

@@ -0,0 +1,170 @@
<?php
namespace Paymenter\Extensions\Others\UptimeLab\Console\Commands;
use Illuminate\Console\Command;
use Paymenter\Extensions\Others\UptimeLab\Models\UptimeServer;
use Paymenter\Extensions\Others\UptimeLab\Services\UptimeMonitoringService;
class TestUptimeCommand extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'uptime:test {--server= : Test specific server by ID}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Test uptime monitoring functionality';
/**
* Execute the console command.
*/
public function handle()
{
$this->info('=== Uptime Lab Extension Test ===');
// Test database connection
$this->testDatabaseConnection();
// Test server models
$this->testServerModels();
// Test monitoring service
$this->testMonitoringService();
$this->info('=== Test completed ===');
}
/**
* Test database connection and tables
*/
private function testDatabaseConnection(): void
{
$this->info('Testing database connection...');
try {
$count = UptimeServer::count();
$this->info("✓ Database connected. Found {$count} servers.");
} catch (\Exception $e) {
$this->error('✗ Database connection failed: ' . $e->getMessage());
}
}
/**
* Test server models
*/
private function testServerModels(): void
{
$this->info('Testing server models...');
try {
$servers = UptimeServer::all();
if ($servers->count() > 0) {
$this->info('✓ Server models working correctly.');
$this->table(
['ID', 'Name', 'IP', 'Status', 'Uptime'],
$servers->map(function ($server) {
return [
$server->id,
$server->name,
$server->ip_address,
$server->status,
$server->uptime_percentage . '%'
];
})
);
} else {
$this->warn('⚠ No servers found in database.');
}
} catch (\Exception $e) {
$this->error('✗ Server models test failed: ' . $e->getMessage());
}
}
/**
* Test monitoring service
*/
private function testMonitoringService(): void
{
$this->info('Testing monitoring service...');
try {
$monitoringService = new UptimeMonitoringService();
if ($serverId = $this->option('server')) {
$server = UptimeServer::find($serverId);
if ($server) {
$this->testSpecificServer($server, $monitoringService);
} else {
$this->error("Server with ID {$serverId} not found.");
}
} else {
$this->testAllServers($monitoringService);
}
$this->info('✓ Monitoring service working correctly.');
} catch (\Exception $e) {
$this->error('✗ Monitoring service test failed: ' . $e->getMessage());
}
}
/**
* Test a specific server
*/
private function testSpecificServer(UptimeServer $server, UptimeMonitoringService $monitoringService): void
{
$this->info("Testing server: {$server->name} ({$server->ip_address})");
$checkResult = $monitoringService->checkServerStatus($server);
$this->table(
['Property', 'Value'],
[
['Status', $checkResult['online'] ? 'Online' : 'Offline'],
['Response Time', $checkResult['response_time'] ? $checkResult['response_time'] . 'ms' : 'N/A'],
['Check Time', $checkResult['check_time'] ? $checkResult['check_time'] . 'ms' : 'N/A'],
]
);
}
/**
* Test all servers
*/
private function testAllServers(UptimeMonitoringService $monitoringService): void
{
$this->info('Testing all active servers...');
$servers = UptimeServer::where('is_active', true)->get();
if ($servers->count() > 0) {
$this->info("Found {$servers->count()} active servers to test.");
$progressBar = $this->output->createProgressBar($servers->count());
$progressBar->start();
foreach ($servers as $server) {
try {
$checkResult = $monitoringService->checkServerStatus($server);
$monitoringService->updateServerStatus($server, $checkResult);
} catch (\Exception $e) {
$this->error("\nError checking server {$server->name}: " . $e->getMessage());
}
$progressBar->advance();
}
$progressBar->finish();
$this->newLine();
$this->info('✓ All servers tested successfully.');
} else {
$this->warn('⚠ No active servers found to test.');
}
}
}

View File

@@ -0,0 +1,52 @@
<?php
namespace Paymenter\Extensions\Others\UptimeLab\Livewire\Uptime;
use Livewire\Component;
use Paymenter\Extensions\Others\UptimeLab\Models\UptimeServer;
use Paymenter\Extensions\Others\UptimeLab\Services\UptimeMonitoringService;
class Index extends Component
{
public $servers = [];
public $isRefreshing = false;
public function mount()
{
$this->loadServers();
}
public function loadServers()
{
$this->servers = UptimeServer::where('is_active', true)
->orderBy('name')
->get();
}
public function refreshStatus()
{
$this->isRefreshing = true;
try {
$monitoringService = new UptimeMonitoringService();
$monitoringService->checkAllServers();
$this->loadServers();
$this->dispatch('status-refreshed');
} catch (\Exception $e) {
// Handle error
} finally {
$this->isRefreshing = false;
}
}
public function render()
{
return view('uptime-lab::index', [
'servers' => $this->servers,
])->layoutData([
'sidebar' => true,
]);
}
}

View File

@@ -0,0 +1,61 @@
<?php
namespace Paymenter\Extensions\Others\UptimeLab\Models;
use Illuminate\Database\Eloquent\Model;
use Carbon\Carbon;
class UptimeServer extends Model
{
protected $table = 'ext_uptime_servers';
protected $fillable = [
'name',
'ip_address',
'server_type',
'location',
'is_active',
'status',
'uptime_percentage',
'last_online',
'last_offline',
'last_check',
'response_time',
];
protected $casts = [
'is_active' => 'boolean',
'last_online' => 'datetime',
'last_offline' => 'datetime',
'last_check' => 'datetime',
'uptime_percentage' => 'decimal:2',
];
public function getFormattedLastOnlineAttribute()
{
if (!$this->last_online) {
return 'Never';
}
return $this->last_online->diffForHumans();
}
public function getFormattedLastOfflineAttribute()
{
if (!$this->last_offline) {
return 'Never';
}
return $this->last_offline->diffForHumans();
}
public function getStatusColorAttribute()
{
return $this->status === 'online' ? 'green' : 'red';
}
public function getStatusIconAttribute()
{
return $this->status === 'online' ? 'ri-checkbox-circle-line' : 'ri-close-circle-line';
}
}

View File

@@ -0,0 +1,57 @@
<?php
namespace Paymenter\Extensions\Others\UptimeLab\Providers;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\Route;
use Illuminate\Support\Facades\View;
use Livewire\Livewire;
use Paymenter\Extensions\Others\UptimeLab\Livewire\Uptime\Index;
use Paymenter\Extensions\Others\UptimeLab\Console\Commands\CheckUptimeCommand;
use Paymenter\Extensions\Others\UptimeLab\Console\Commands\TestUptimeCommand;
class UptimeLabServiceProvider extends ServiceProvider
{
/**
* Register services.
*/
public function register(): void
{
//
}
/**
* Bootstrap services.
*/
public function boot(): void
{
// Load routes
$this->loadRoutesFrom(__DIR__ . '/../routes/web.php');
// Load views
$this->loadViewsFrom(__DIR__ . '/../resources/views', 'uptime');
// Load language files
$this->loadTranslationsFrom(__DIR__ . '/../lang', 'uptime');
// Register Livewire components
Livewire::component('uptime.index', Index::class);
// Register console commands
if ($this->app->runningInConsole()) {
$this->commands([
CheckUptimeCommand::class,
TestUptimeCommand::class,
]);
}
// Publish assets if needed
$this->publishes([
__DIR__ . '/../resources/views' => resource_path('views/vendor/uptime'),
], 'uptime-views');
$this->publishes([
__DIR__ . '/../lang' => resource_path('lang/vendor/uptime'),
], 'uptime-lang');
}
}

View File

@@ -0,0 +1,311 @@
<?php
namespace Paymenter\Extensions\Others\UptimeLab\Services;
use Paymenter\Extensions\Others\UptimeLab\Models\UptimeServer;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
class UptimeMonitoringService
{
/**
* Check the status of a server
*/
public function checkServerStatus(UptimeServer $server): array
{
$startTime = microtime(true);
$isOnline = false;
$responseTime = null;
try {
if ($server->server_type === 'ip') {
$result = $this->pingServer($server->ip_address);
$isOnline = $result['online'];
$responseTime = $result['response_time'];
} else {
// For subdomains, try HTTP first, then fallback to ping if HTTP fails
$result = $this->httpCheck($server->ip_address);
$isOnline = $result['online'];
$responseTime = $result['response_time'];
// If HTTP fails, try ping as fallback for subdomains
if (!$isOnline) {
Log::info('HTTP check failed for subdomain, trying ping as fallback: ' . $server->ip_address);
$pingResult = $this->pingServer($server->ip_address);
if ($pingResult['online']) {
$isOnline = true;
$responseTime = $pingResult['response_time'];
Log::info('Ping fallback successful for subdomain: ' . $server->ip_address);
}
}
}
$endTime = microtime(true);
$totalTime = round(($endTime - $startTime) * 1000, 2);
return [
'online' => $isOnline,
'response_time' => $responseTime,
'check_time' => $totalTime,
];
} catch (\Exception $e) {
Log::error('Uptime check failed for server: ' . $server->name, [
'error' => $e->getMessage(),
'server_id' => $server->id,
'server_type' => $server->server_type,
'ip_address' => $server->ip_address,
]);
return [
'online' => false,
'response_time' => null,
'check_time' => null,
];
}
}
/**
* Ping an IP address or domain
*/
private function pingServer(string $ip): array
{
$command = "ping -c 1 -W 5 " . escapeshellarg($ip) . " 2>&1";
$output = shell_exec($command);
if (preg_match('/time=(\d+\.?\d*)\s*ms/', $output, $matches)) {
return [
'online' => true,
'response_time' => (int) $matches[1],
];
}
return [
'online' => false,
'response_time' => null,
];
}
/**
* Check HTTP response for subdomains
*/
private function httpCheck(string $domain): array
{
try {
// Remove any protocol prefix if present
$cleanDomain = preg_replace('/^https?:\/\//', '', $domain);
// Try HTTP first
$response = Http::timeout(10)
->withHeaders([
'User-Agent' => 'Paymenter-UptimeLab/1.0',
'Accept' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
])
->get('http://' . $cleanDomain);
if ($response->successful()) {
$responseTime = $this->calculateResponseTime($response);
return [
'online' => true,
'response_time' => $responseTime,
];
}
// If HTTP fails, try HTTPS
$httpsResponse = Http::timeout(10)
->withHeaders([
'User-Agent' => 'Paymenter-UptimeLab/1.0',
'Accept' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
])
->get('https://' . $cleanDomain);
if ($httpsResponse->successful()) {
$responseTime = $this->calculateResponseTime($httpsResponse);
return [
'online' => true,
'response_time' => $responseTime,
];
}
// If both HTTP and HTTPS fail, check if domain resolves
if (gethostbyname($cleanDomain) !== $cleanDomain) {
// Domain resolves but HTTP/HTTPS failed
return [
'online' => false,
'response_time' => null,
];
}
// Domain doesn't resolve
return [
'online' => false,
'response_time' => null,
];
} catch (\Exception $e) {
Log::warning('HTTP check failed for domain: ' . $domain, [
'error' => $e->getMessage(),
'domain' => $domain,
]);
// Try DNS resolution as fallback
if (gethostbyname($cleanDomain) !== $cleanDomain) {
return [
'online' => false, // Domain resolves but HTTP failed
'response_time' => null,
];
}
return [
'online' => false,
'response_time' => null,
];
}
}
/**
* Calculate response time from HTTP response
*/
private function calculateResponseTime($response): ?int
{
try {
// Try to get response time from handler stats
if (method_exists($response, 'handlerStats')) {
$stats = $response->handlerStats();
if (isset($stats['total_time_us'])) {
return (int) ($stats['total_time_us'] / 1000); // Convert to milliseconds
}
}
// Fallback: estimate response time based on current time
return null;
} catch (\Exception $e) {
return null;
}
}
/**
* Update server status
*/
public function updateServerStatus(UptimeServer $server, array $checkResult): void
{
$wasOnline = $server->status === 'online';
$isOnline = $checkResult['online'];
$server->update([
'status' => $isOnline ? 'online' : 'offline',
'last_check' => now(),
'response_time' => $checkResult['response_time'],
]);
// Update last online/offline timestamps
if ($isOnline && !$wasOnline) {
$server->update(['last_online' => now()]);
} elseif (!$isOnline && $wasOnline) {
$server->update(['last_offline' => now()]);
}
// Calculate uptime percentage (simplified calculation)
$this->calculateUptimePercentage($server);
}
/**
* Calculate uptime percentage
*/
private function calculateUptimePercentage(UptimeServer $server): void
{
// Calculate uptime based on server status and monitoring history
$now = now();
$uptimePercentage = 0;
if ($server->status === 'online') {
// Server is currently online
if ($server->last_offline) {
// Server has been offline before, calculate based on recent performance
$lastOfflineTime = $server->last_offline;
$timeSinceOffline = $now->diffInHours($lastOfflineTime);
if ($timeSinceOffline > 24) {
// If server has been online for more than 24 hours, give high uptime
$uptimePercentage = 99.5;
} elseif ($timeSinceOffline > 12) {
// If server has been online for more than 12 hours
$uptimePercentage = 98.0;
} elseif ($timeSinceOffline > 6) {
// If server has been online for more than 6 hours
$uptimePercentage = 96.0;
} elseif ($timeSinceOffline > 1) {
// If server has been online for more than 1 hour
$uptimePercentage = 92.0;
} else {
// Server just came back online
$uptimePercentage = 85.0;
}
} else {
// Server has never been offline (new server or always online)
$uptimePercentage = 99.9;
}
} else {
// Server is currently offline
if ($server->last_online) {
// Server was online before, calculate based on downtime
$lastOnlineTime = $server->last_online;
$timeSinceOnline = $now->diffInHours($lastOnlineTime);
if ($timeSinceOnline < 1) {
// Server just went offline
$uptimePercentage = 95.0;
} elseif ($timeSinceOnline < 6) {
// Server has been offline for a few hours
$uptimePercentage = 85.0;
} elseif ($timeSinceOnline < 24) {
// Server has been offline for a day
$uptimePercentage = 70.0;
} else {
// Server has been offline for a long time
$uptimePercentage = 50.0;
}
} else {
// Server has never been online
$uptimePercentage = 0.0;
}
}
// Ensure percentage is between 0 and 100
$uptimePercentage = max(0, min(100, $uptimePercentage));
$server->update([
'uptime_percentage' => round($uptimePercentage, 2),
]);
}
/**
* Check all active servers
*/
public function checkAllServers(): void
{
$servers = UptimeServer::where('is_active', true)->get();
foreach ($servers as $server) {
try {
$checkResult = $this->checkServerStatus($server);
$this->updateServerStatus($server, $checkResult);
Log::info('Server status checked', [
'server' => $server->name,
'status' => $checkResult['online'] ? 'online' : 'offline',
'response_time' => $checkResult['response_time'],
'server_type' => $server->server_type,
]);
} catch (\Exception $e) {
Log::error('Failed to check server: ' . $server->name, [
'error' => $e->getMessage(),
'server_id' => $server->id,
]);
}
// Add a small delay between checks to avoid overwhelming the system
usleep(200000); // 0.1 second delay
}
}
}

View File

@@ -0,0 +1,101 @@
<?php
namespace Paymenter\Extensions\Others\UptimeLab;
use App\Classes\Extension\Extension;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Facades\View;
use Illuminate\Support\HtmlString;
use Paymenter\Extensions\Others\UptimeLab\Admin\Resources\UptimeServerResource;
use Paymenter\Extensions\Others\UptimeLab\Models\UptimeServer;
use Illuminate\Support\Facades\Blade;
class UptimeLab extends Extension
{
/**
* Get all the configuration for the extension
*
* @param array $values
* @return array
*/
public function getConfig($values = [])
{
try {
return [
[
'name' => 'Uptime Monitoring',
'type' => 'placeholder',
'label' => new HtmlString('Uptime Lab extension is now active. You can manage servers in the <a class="text-primary-600" href="' . UptimeServerResource::getUrl() . '">Uptime Lab</a> admin section.'),
],
];
} catch (\Exception $e) {
return [
[
'name' => 'Uptime Monitoring',
'type' => 'placeholder',
'label' => new HtmlString('Uptime Lab extension is now active. You\'ll need to enable this extension above to get started.'),
],
];
}
}
/**
* Called when the extension is enabled
*/
public function enabled()
{
// Run migrations
Artisan::call('migrate', ['--path' => 'extensions/Others/UptimeLab/database/migrations/2025_01_01_000001_create_ext_uptime_servers_table.php', '--force' => true]);
// Run seeder to populate sample data
try {
Artisan::call('db:seed', ['--class' => 'Paymenter\\Extensions\\Others\\UptimeLab\\Database\\Seeders\\UptimeServerSeeder', '--force' => true]);
} catch (\Exception $e) {
// Seeder might fail if data already exists, which is fine
}
}
/**
* Called when the extension is booted
*/
public function boot()
{
// Register routes
require __DIR__ . '/routes/web.php';
View::addNamespace('uptime-lab', __DIR__ . '/resources/views');
// Register Livewire components
\Livewire\Livewire::component('uptime.index', \Paymenter\Extensions\Others\UptimeLab\Livewire\Uptime\Index::class);
// Add navigation menu item to dashboard - no icon to avoid errors
Event::listen('navigation.dashboard', function () {
return [
'name' => new HtmlString('
<span class="relative" style="left: -2px;"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 122.88 99.54" style="width:20px;height:20px;vertical-align:middle; " >
<style type="text/css"><![CDATA[
.st0{fill:currentcolor;}
.st1{fill-rule:evenodd;clip-rule:evenodd;fill:#6BBE66;}
]]></style>
<g>
<path class="st0" d="M73.12,0c6.73,0,13.16,1.34,19.03,3.77c6.09,2.52,11.57,6.22,16.16,10.81l0,0c4.58,4.58,8.28,10.06,10.8,16.17 c2.43,5.87,3.77,12.3,3.77,19.02c0,6.73-1.34,13.16-3.77,19.03c-2.52,6.09-6.22,11.57-10.81,16.16l0,0 c-4.58,4.58-10.06,8.28-16.17,10.8c-5.87,2.43-12.3,3.77-19.02,3.77c-6.73,0-13.16-1.34-19.03-3.77 c-6.09-2.52-11.57-6.22-16.15-10.8l-0.01-0.01c-4.59-4.59-8.28-10.07-10.8-16.15c-0.78-1.89-1.45-3.83-2-5.82 c1.04,0.1,2.1,0.15,3.17,0.15c2.03,0,4.01-0.18,5.94-0.53c0.32,0.96,0.67,1.91,1.05,2.84c2.07,5,5.11,9.5,8.89,13.28 c3.78,3.78,8.29,6.82,13.28,8.89c4.81,1.99,10.1,3.1,15.66,3.1s10.84-1.1,15.66-3.1c5-2.07,9.5-5.11,13.28-8.89 c3.78-3.78,6.82-8.29,8.89-13.28c1.99-4.81,3.1-10.1,3.1-15.66s-1.1-10.84-3.1-15.66c-2.07-5-5.11-9.5-8.89-13.28 s-8.29-6.82-13.28-8.89c-4.81-1.99-10.1-3.1-15.66-3.1s-10.84,1.1-15.66,3.1c-0.43,0.18-0.86,0.37-1.28,0.56 c-1.64-2.58-3.62-4.92-5.89-6.95c1.24-0.64,2.51-1.23,3.8-1.77C59.97,1.34,66.39,0,73.12,0L73.12,0L73.12,0z M67.41,26.11 c0-1.22,0.5-2.32,1.29-3.12c0.8-0.8,1.9-1.29,3.12-1.29c1.22,0,2.32,0.49,3.12,1.29c0.8,0.8,1.29,1.9,1.29,3.12v23.22l17.35,10.29 c1.04,0.62,1.74,1.61,2.02,2.7c0.28,1.09,0.15,2.29-0.47,3.33v0.01l0,0c-0.62,1.04-1.61,1.74-2.7,2.02s-2.29,0.15-3.33-0.47h-0.01 l0,0L69.68,55.7c-0.67-0.37-1.22-0.91-1.62-1.55c-0.41-0.67-0.65-1.46-0.65-2.3V26.11L67.41,26.11L67.41,26.11z"/>
</g>
</svg></span></span><span>
Uptime</span>
'),
'route' => 'uptime.index',
'priority' => 32,
'spa' => true,
'params' => [],
'active' => request()->routeIs('uptime.index'),
];
});
// Add admin navigation - no icon to avoid errors
Event::listen('admin.navigation', function () {
return [
'name' => 'Uptime Lab',
'group' => 'Extensions',
'priority' => 10,
];
});
}
}

View File

@@ -0,0 +1,32 @@
{
"name": "paymenter/uptime-lab",
"description": "A comprehensive server uptime monitoring extension for Paymenter",
"type": "library",
"license": "MIT",
"authors": [
{
"name": "Paymenter Team",
"email": "support@paymenter.org"
}
],
"require": {
"php": "^8.0",
"laravel/framework": "^10.0",
"filament/filament": "^3.0",
"livewire/livewire": "^3.0"
},
"autoload": {
"psr-4": {
"Paymenter\\Extensions\\Others\\UptimeLab\\": ""
}
},
"extra": {
"laravel": {
"providers": [
"Paymenter\\Extensions\\Others\\UptimeLab\\Providers\\UptimeLabServiceProvider"
]
}
},
"minimum-stability": "stable",
"prefer-stable": true
}

View File

@@ -0,0 +1,39 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('ext_uptime_servers', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('ip_address');
$table->string('server_type')->default('ip'); // ip or subdomain
$table->string('location');
$table->string('type')->default('Production'); // Production, Staging, Development
$table->boolean('is_active')->default(true);
$table->string('status')->default('offline'); // online, offline
$table->decimal('uptime_percentage', 5, 2)->default(0.00);
$table->timestamp('last_online')->nullable();
$table->timestamp('last_offline')->nullable();
$table->timestamp('last_check')->nullable();
$table->integer('response_time')->nullable(); // in milliseconds
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('ext_uptime_servers');
}
};

View File

@@ -0,0 +1,74 @@
<?php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
use Paymenter\Extensions\Others\UptimeLab\Models\UptimeServer;
class UptimeServerSeeder extends Seeder
{
/**
* Run the database seeds.
*/
public function run(): void
{
$servers = [
[
'name' => 'Web Server 01',
'ip_address' => '192.168.1.10',
'server_type' => 'ip',
'location' => 'Jakarta, Indonesia',
'is_active' => true,
'status' => 'online',
'uptime_percentage' => 99.8,
'last_online' => now(),
'last_offline' => now()->subHours(6),
'last_check' => now(),
'response_time' => 15,
],
[
'name' => 'Main Database Server',
'ip_address' => '192.168.1.20',
'server_type' => 'ip',
'location' => 'Surabaya, Indonesia',
'is_active' => true,
'status' => 'offline',
'uptime_percentage' => 100.0,
'last_online' => now()->subHours(5),
'last_offline' => now(),
'last_check' => now(),
'response_time' => null,
],
[
'name' => 'API Gateway',
'ip_address' => 'api.example.com',
'server_type' => 'subdomain',
'location' => 'Bandung, Indonesia',
'is_active' => true,
'status' => 'online',
'uptime_percentage' => 99.9,
'last_online' => now()->subHours(6),
'last_offline' => now()->subHours(5),
'last_check' => now(),
'response_time' => 25,
],
[
'name' => 'Load Balancer',
'ip_address' => '192.168.1.40',
'server_type' => 'ip',
'location' => 'Jakarta, Indonesia',
'is_active' => true,
'status' => 'online',
'uptime_percentage' => 99.99,
'last_online' => now(),
'last_offline' => now()->subHours(6),
'last_check' => now(),
'response_time' => 8,
],
];
foreach ($servers as $serverData) {
UptimeServer::create($serverData);
}
}
}

View File

@@ -0,0 +1,36 @@
<?php
return [
'dashboard' => 'Uptime',
'servers' => 'Servers',
'add_server' => 'Add Server',
'server_name' => 'Server Name',
'ip_address' => 'IP Address',
'subdomain' => 'Subdomain',
'server_type' => 'Server Type',
'location' => 'Location',
'status' => 'Status',
'online' => 'Online',
'offline' => 'Offline',
'uptime' => 'Uptime',
'last_check' => 'Last Check',
'last_online' => 'Last Online',
'last_offline' => 'Last Offline',
'response_time' => 'Response Time',
'active' => 'Active',
'inactive' => 'Inactive',
'view_details' => 'View Details',
'refresh' => 'Refresh',
'no_servers' => 'No servers configured',
'contact_admin' => 'Contact your administrator to add servers for monitoring.',
'auto_refresh' => 'Status updates automatically every 30 seconds',
'server_monitoring_dashboard' => 'SERVER MONITORING DASHBOARD',
'check_status' => 'Check Status',
'uptime_lab' => 'Uptime Lab',
'server_information' => 'Server Information',
'enter_server_name' => 'Enter the name of the server',
'select_server_type' => 'Select server type',
'enter_ip_subdomain' => 'Enter IP address or subdomain',
'enter_location' => 'Enter server location (e.g., Jakarta, Indonesia)',
'enable_disable_monitoring' => 'Enable or disable uptime monitoring for this server',
];

View File

@@ -0,0 +1,29 @@
<div class="text-center py-4">
<div class="inline-block">
<span class="text-lg font-bold bg-gradient-to-r from-blue-500 via-purple-500 to-blue-600 bg-clip-text text-transparent animate-gradient-x">
Created By Farrdevx
</span>
</div>
</div>
<style>
@keyframes gradient-x {
0%, 100% {
background-size: 200% 200%;
background-position: left center;
}
50% {
background-size: 200% 200%;
background-position: right center;
}
}
.animate-gradient-x {
animation: gradient-x 3s ease-in-out infinite;
background-size: 200% 200%;
}
.bg-gradient-to-r {
background: linear-gradient(to right, #3b82f6, #8b5cf6, #3b82f6);
}
</style>

View File

@@ -0,0 +1,167 @@
<div class="w-full">
<!-- Custom CSS for animations -->
<style>
@keyframes status-pulse {
0%, 100% {
opacity: 1;
transform: scale(1);
}
50% {
opacity: 0.7;
transform: scale(1.1);
}
}
@keyframes status-ping {
0% {
transform: scale(1);
opacity: 1;
}
75%, 100% {
transform: scale(1.5);
opacity: 0;
}
}
.status-online {
animation: status-pulse 2s ease-in-out infinite;
box-shadow: 0 0 10px rgba(34, 197, 94, 0.5);
}
.status-offline {
animation: status-ping 1.5s ease-in-out infinite;
box-shadow: 0 0 10px rgba(239, 68, 68, 0.5);
}
</style>
<!-- Header -->
<div class="flex flex-col sm:flex-row sm:items-center sm:justify-between mb-8">
<div>
<h1 class="text-3xl font-bold ">Services Availability</h1>
</div>
<div class="mt-4 sm:mt-0">
<button
wire:click="refreshStatus"
wire:loading.attr="disabled"
class="inline-flex items-center px-4 py-2 bg-gray-600 hover:bg-gray-700 text-white rounded-lg transition-colors duration-200 disabled:opacity-50"
>
<svg wire:loading.remove class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"></path>
</svg>
<svg wire:loading fill="currentColor" stroke="currentColor" viewBox="0 0 128 128" class="w-4 h-4 mr-2"><g><path stroke-width="5" d="M31.6 8.98a4.02 4.02 0 0 0 1.7 5.3l6.12 3.22a52.56 52.56 0 1 0 63.13 10.73L96 33.97a43.88 43.88 0 1 1-53-8.5l-3.65 7.4a4.02 4.02 0 0 0 1.72 5.3 3.73 3.73 0 0 0 5.13-1.67l7.66-15.63a4.18 4.18 0 0 0-1.75-5.4L36.74 7.32a3.73 3.73 0 0 0-5.13 1.66z" fill="currentColor" stroke="currentColor"/><animateTransform attributeName="transform" type="rotate" from="0 64 64" to="360 64 64" dur="1000ms" repeatCount="indefinite"></animateTransform></g></svg>
Refresh
</button>
</div>
</div>
<!-- Server Status Cards -->
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-3 gap-6">
@forelse($servers as $server)
<div class="bg-background-secondary rounded-lg p-6 px-6 py-8">
<!-- Server Header -->
<div class="flex items-start justify-between ">
<div class="flex items-center">
<div class="w-3 h-3 rounded-full {{ $server->status === 'online' ? 'bg-green-500' : 'bg-red-500' }} mr-3 {{ $server->status === 'online' ? 'status-online' : 'status-offline' }}"></div>
<div>
<h3 class=" font-semibold text-sm">{{ $server->name }}</h3>
</div>
</div>
<span class="px-3 py-1 rounded-full text-xs font-medium {{ $server->status === 'online' ? 'bg-green-600 text-white' : 'bg-red-600 text-white' }}">
{{ ucfirst($server->status) }}
</span>
</div>
<!-- Server Metrics -->
<!-- Last Status Updates -->
<div class="space-y-2" style="margin-top: .5rem;">
<div class="flex items-center text-sm" style="align-items: center; ">
<style>
.svgclock {
height: 4vh;
width: auto;
animation: upDown 1s ease-in-out infinite;
}
.loader-circle,
.loader-pointer,
.loader-line {
fill: none;
stroke-width: 5px;
stroke: #4d6565;
}
.loader-center {
fill: #4d6565;
}
.loader-pointer {
transform-origin: bottom center;
animation: spin 4s linear infinite;
}
.loader-line {
transform-origin: bottom center;
animation: spin 60s linear infinite;
}
@keyframes spin {
from { transform: rotate(0deg); transform-origin: 50% 50%; }
to { transform: rotate(360deg); transform-origin: 50% 50%; }
}
</style>
<svg class="svgclock" viewBox="0 0 240 240">
<line class="loader-pointer" x1="120" y1="120" x2="120" y2="97"/>
<line class="loader-line" x1="120" y1="120" x2="135" y2="120" />
<circle class="loader-circle" cx="120" cy="120" r="30" />
<circle class="loader-center" cx="120" cy="120" r="5" />
</svg>
<span>Updated:</span>
<span class="ml-2">
{{ \Carbon\Carbon::parse($server->last_check)->format('m/d/y H:i') }} -0 UTC (MM/DD/YY, HH:MM)
</span>
</div>
</div>
</div>
@empty
<div class="col-span-full text-center py-12">
<div class="mb-4">
<svg class="w-16 h-16 mx-auto" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"></path>
</svg>
</div>
<h3 class="text-xl font-medium mb-2">No servers configured</h3>
<p class="">Contact your administrator to add servers for monitoring.</p>
</div>
@endforelse
</div>
<!-- Auto-refresh indicator -->
<div class="mt-3 text-center text-gray-500 text-sm">
<p>Status updates automatically every 30 seconds</p>
</div>
</div>
<script>
// Auto-refresh every 30 seconds
setInterval(function() {
@this.refreshStatus();
}, 30000);
</script>

View File

@@ -0,0 +1,8 @@
<?php
use Illuminate\Support\Facades\Route;
use Paymenter\Extensions\Others\UptimeLab\Livewire\Uptime\Index;
Route::group(['middleware' => ['web', 'auth']], function () {
Route::get('/uptime', Index::class)->name('uptime.index');
});