isInConflictState() && !$server->retrieveStatus()->isOffline(); } protected function getData(): array { $previous = null; $period = auth()->user()->getCustomization()['console_graph_period'] ?? 30; $net = collect(cache()->get("servers.{$this->server->id}.network")) ->slice(-$period) ->map(function ($current, $timestamp) use (&$previous) { $net = null; if ($previous !== null) { $net = [ 'rx' => max(0, $current->rx_bytes - $previous->rx_bytes), 'tx' => max(0, $current->tx_bytes - $previous->tx_bytes), 'timestamp' => Carbon::createFromTimestamp($timestamp, auth()->user()->timezone ?? 'UTC')->format('H:i:s'), ]; } $previous = $current; return $net; }) ->all(); return [ 'datasets' => [ [ 'label' => 'Inbound', 'data' => array_column($net, 'rx'), 'backgroundColor' => [ 'rgba(100, 255, 105, 0.5)', ], 'tension' => '0.3', 'fill' => true, ], [ 'label' => 'Outbound', 'data' => array_column($net, 'tx'), 'backgroundColor' => [ 'rgba(96, 165, 250, 0.3)', ], 'tension' => '0.3', 'fill' => true, ], ], 'labels' => array_column($net, 'timestamp'), ]; } protected function getType(): string { return 'line'; } protected function getOptions(): RawJs { // TODO: use "panel.use_binary_prefix" config value return RawJs::make(<<<'JS' { scales: { x: { display: false, }, y: { min: 0, ticks: { display: true, callback(value) { const bytes = typeof value === 'string' ? parseInt(value, 10) : value; if (bytes < 1) return '0 Bytes'; const i = Math.floor(Math.log(bytes) / Math.log(1024)); const number = Number((bytes / Math.pow(1024, i)).toFixed(2)); return `${number} ${['Bytes', 'KiB', 'MiB', 'GiB', 'TiB'][i]}`; }, }, }, } } JS); } public function getHeading(): string { $lastData = collect(cache()->get("servers.{$this->server->id}.network"))->last(); return 'Network - ↓' . convert_bytes_to_readable($lastData->rx_bytes ?? 0) . ' - ↑' . convert_bytes_to_readable($lastData->tx_bytes ?? 0); } }