diff --git a/examples/ServerManager/UI/ServerListTab.php b/examples/ServerManager/UI/ServerListTab.php index f8007cc..910a5c3 100644 --- a/examples/ServerManager/UI/ServerListTab.php +++ b/examples/ServerManager/UI/ServerListTab.php @@ -11,8 +11,8 @@ use PHPNative\Ui\Widget\Container; use PHPNative\Ui\Widget\Icon; use PHPNative\Ui\Widget\Label; use PHPNative\Ui\Widget\TabContainer; -use PHPNative\Ui\Widget\Table; use PHPNative\Ui\Widget\TextInput; +use PHPNative\Ui\Widget\VirtualListView; use ServerManager\Services\HetznerService; use ServerManager\UI\KanbanTab; use ServerManager\UI\LoadingIndicator; @@ -22,7 +22,7 @@ class ServerListTab private Settings $settings; private null|KanbanTab $kanbanTab; private Container $tab; - private Table $table; + private VirtualListView $table; private TextInput $searchInput; private Label $statusLabel; private Button $refreshButton; @@ -108,9 +108,12 @@ class ServerListTab ); $leftSide->addComponent($this->searchInput); - // Table - $this->table = new Table(style: ' flex-1'); - $this->table->setColumns([ + // Table container with header and virtual list + $tableContainer = new Container('flex flex-col flex-1 border border-gray-300 rounded'); + + // Table header + $headerContainer = new Container('flex flex-row w-full bg-gray-200 border-b-2 border-gray-400'); + $columns = [ [ 'key' => 'selected', 'title' => '', @@ -131,13 +134,13 @@ class ServerListTab [ 'key' => 'docker_status', 'title' => 'Docker', - 'width' => 100, + 'width' => 50, 'render' => [$this, 'renderDockerStatusCell'], ], [ 'key' => 'docker_running', - 'title' => 'Running', - 'width' => 100, + 'title' => 'R', + 'width' => 50, 'render' => [$this, 'renderDockerRunningCell'], ], [ @@ -150,25 +153,25 @@ class ServerListTab [ 'key' => 'root', 'title' => 'Root', - 'width' => 100, + 'width' => 50, 'render' => [$this, 'renderRootCell'], ], [ 'key' => 'data', 'title' => 'Data', - 'width' => 90, + 'width' => 50, 'render' => [$this, 'renderDataCell'], ], [ 'key' => 'needs_reboot', 'title' => 'Neustart', - 'width' => 110, + 'width' => 100, 'render' => [$this, 'renderNeedsRebootCell'], ], [ 'key' => 'updates_available', 'title' => 'Updates', - 'width' => 130, + 'width' => 100, 'render' => [$this, 'renderUpdatesCell'], ], [ @@ -177,16 +180,40 @@ class ServerListTab 'width' => 180, 'render' => [$this, 'renderLastBackupCell'], ], - ]); + ]; + + // Build header cells + foreach ($columns as $column) { + $title = $column['title'] ?? ''; + $width = $column['width'] ?? null; + + $style = 'px-4 py-2 text-black font-bold border-r border-gray-300'; + if ($width) { + $style .= ' w-' . ((int) ($width / 4)); + } else { + $style .= ' flex-1'; + } + + $headerLabel = new Label($title, $style); + $headerContainer->addComponent($headerLabel); + } + $tableContainer->addComponent($headerContainer); + + // Virtual List View (Performance-optimized) + $this->table = new VirtualListView('flex-1 bg-white'); + $this->table->setColumns($columns); // Load initial test data $this->currentServerData = HetznerService::generateTestData(); $this->table->setData($this->currentServerData); - $leftSide->addComponent($this->table); + $tableContainer->addComponent($this->table); + $leftSide->addComponent($tableContainer); // Right side: Detail panel - $detailPanel = new Container('flex flex-col gap-3 w-120 bg-white border-2 border-gray-300 rounded p-4 overflow-y-auto'); + $detailPanel = new Container( + 'flex flex-col gap-3 w-120 bg-white border-2 border-gray-300 rounded p-4 overflow-y-auto', + ); $detailTitle = new Label('Server Details', 'text-xl font-bold text-black mb-2'); $detailPanel->addComponent($detailTitle); @@ -368,7 +395,7 @@ class ServerListTab $searchTerm = strtolower(trim($value)); if (empty($searchTerm)) { - $serverListTab->table->setData($serverListTab->currentServerData, true); + $serverListTab->table->setData($serverListTab->currentServerData); } else { $filteredData = array_filter($serverListTab->currentServerData, function ($row) use ($searchTerm) { return ( @@ -378,7 +405,7 @@ class ServerListTab })) ); }); - $serverListTab->table->setData(array_values($filteredData), false); + $serverListTab->table->setData(array_values($filteredData)); } }); @@ -438,7 +465,7 @@ class ServerListTab 'last_backup' => 'unbekannt', ], $row), $result['servers']); - $serverListTab->table->setData($serverListTab->currentServerData, false); + $serverListTab->table->setData($serverListTab->currentServerData); $serverListTab->statusLabel->setText('Server geladen: ' . $result['count'] . ' gefunden'); // Kanban-Board aktualisieren, damit Servernamen in den Karten up-to-date sind @@ -732,7 +759,7 @@ class ServerListTab $serverListTab->currentServerData[$i]['docker'] = $dockerResult['docker']; $searchTerm = $serverListTab->searchInput->getValue(); if (empty($searchTerm)) { - $serverListTab->table->setData($serverListTab->currentServerData, true); + $serverListTab->table->setData($serverListTab->currentServerData); } else { $filteredData = array_filter( $serverListTab->currentServerData, @@ -747,7 +774,7 @@ class ServerListTab ); }, ); - $serverListTab->table->setData(array_values($filteredData), true); + $serverListTab->table->setData(array_values($filteredData)); } } @@ -1035,7 +1062,7 @@ class ServerListTab } $searchTerm = $serverListTab->searchInput->getValue(); if (empty($searchTerm)) { - $serverListTab->table->setData($serverListTab->currentServerData, true); + $serverListTab->table->setData($serverListTab->currentServerData); } else { $filteredData = array_filter($serverListTab->currentServerData, function ($row) use ( $searchTerm, @@ -1047,7 +1074,7 @@ class ServerListTab })) ); }); - $serverListTab->table->setData(array_values($filteredData), false); + $serverListTab->table->setData(array_values($filteredData)); } } @@ -1472,7 +1499,7 @@ class ServerListTab foreach ($serverListTab->currentServerData as $index => $row) { if (($row['id'] ?? null) === $rowId) { $serverListTab->currentServerData[$index]['selected'] = $checked; - $serverListTab->table->setData($serverListTab->currentServerData, true); + $serverListTab->table->setData($serverListTab->currentServerData); break; } }