Backup
This commit is contained in:
parent
402ad74582
commit
2d631411cb
@ -66,7 +66,10 @@ $mainContainer = new Container('flex flex-col bg-gray-100');
|
|||||||
|
|
||||||
// Modal dialog setup (hidden by default)
|
// Modal dialog setup (hidden by default)
|
||||||
$apiKeyInput = new TextInput('API Key', 'w-full border border-gray-300 rounded px-3 py-2 bg-white text-black');
|
$apiKeyInput = new TextInput('API Key', 'w-full border border-gray-300 rounded px-3 py-2 bg-white text-black');
|
||||||
$privateKeyPathInput = new TextInput('Private Key Path', 'w-full border border-gray-300 rounded px-3 py-2 bg-white text-black');
|
$privateKeyPathInput = new TextInput(
|
||||||
|
'Private Key Path',
|
||||||
|
'w-full border border-gray-300 rounded px-3 py-2 bg-white text-black',
|
||||||
|
);
|
||||||
|
|
||||||
$modalDialog = new Container('bg-white rounded-lg p-6 flex flex-col w-96 gap-3');
|
$modalDialog = new Container('bg-white rounded-lg p-6 flex flex-col w-96 gap-3');
|
||||||
$modalDialog->addComponent(new Label('API Einstellungen', 'text-xl font-bold text-black'));
|
$modalDialog->addComponent(new Label('API Einstellungen', 'text-xl font-bold text-black'));
|
||||||
@ -115,7 +118,14 @@ $fileMenu->addItem('Beenden', function () use ($app) {
|
|||||||
|
|
||||||
// Settings Menu
|
// Settings Menu
|
||||||
$settingsMenu = new Menu(title: 'Einstellungen');
|
$settingsMenu = new Menu(title: 'Einstellungen');
|
||||||
$settingsMenu->addItem('Optionen', function () use ($menuBar, $modal, $apiKeyInput, $privateKeyPathInput, &$currentApiKey, &$currentPrivateKeyPath) {
|
$settingsMenu->addItem('Optionen', function () use (
|
||||||
|
$menuBar,
|
||||||
|
$modal,
|
||||||
|
$apiKeyInput,
|
||||||
|
$privateKeyPathInput,
|
||||||
|
&$currentApiKey,
|
||||||
|
&$currentPrivateKeyPath,
|
||||||
|
) {
|
||||||
$menuBar->closeAllMenus();
|
$menuBar->closeAllMenus();
|
||||||
$apiKeyInput->setValue($currentApiKey);
|
$apiKeyInput->setValue($currentApiKey);
|
||||||
$privateKeyPathInput->setValue($currentPrivateKeyPath);
|
$privateKeyPathInput->setValue($currentPrivateKeyPath);
|
||||||
@ -147,6 +157,10 @@ $refreshButton->setIcon($refreshIcon);
|
|||||||
|
|
||||||
$leftSide->addComponent($refreshButton);
|
$leftSide->addComponent($refreshButton);
|
||||||
|
|
||||||
|
// Search input field
|
||||||
|
$searchInput = new TextInput('Suche...', 'w-full border border-gray-300 rounded px-3 py-2 bg-white text-black mb-2');
|
||||||
|
$leftSide->addComponent($searchInput);
|
||||||
|
|
||||||
$table = new Table(style: ' flex-1'); // flex-1 to fill available height but not expand infinitely
|
$table = new Table(style: ' flex-1'); // flex-1 to fill available height but not expand infinitely
|
||||||
|
|
||||||
$table->setColumns([
|
$table->setColumns([
|
||||||
@ -168,7 +182,26 @@ for ($i = 1; $i <= 63; $i++) {
|
|||||||
'ipv4' => sprintf('192.168.%d.%d', floor($i / 255), $i % 255),
|
'ipv4' => sprintf('192.168.%d.%d', floor($i / 255), $i % 255),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
$table->setData($testData);
|
|
||||||
|
// Store current server data (will be updated when API loads servers)
|
||||||
|
$currentServerData = $testData;
|
||||||
|
$table->setData($currentServerData);
|
||||||
|
|
||||||
|
// Add search functionality
|
||||||
|
$searchInput->setOnChange(function ($value) use ($table, &$currentServerData) {
|
||||||
|
$searchTerm = strtolower(trim($value));
|
||||||
|
|
||||||
|
if (empty($searchTerm)) {
|
||||||
|
// Show all data if search is empty
|
||||||
|
$table->setData($currentServerData);
|
||||||
|
} else {
|
||||||
|
// Filter by name
|
||||||
|
$filteredData = array_filter($currentServerData, function ($row) use ($searchTerm) {
|
||||||
|
return str_contains(strtolower($row['name']), $searchTerm);
|
||||||
|
});
|
||||||
|
$table->setData(array_values($filteredData));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
$leftSide->addComponent($table);
|
$leftSide->addComponent($table);
|
||||||
$tab1->addComponent($leftSide);
|
$tab1->addComponent($leftSide);
|
||||||
@ -197,11 +230,71 @@ $detailPanel->addComponent(new Label('IPv4:', 'text-xs text-gray-500 mt-2'));
|
|||||||
$detailPanel->addComponent($detailIpv4);
|
$detailPanel->addComponent($detailIpv4);
|
||||||
|
|
||||||
// SFTP Manager Button
|
// SFTP Manager Button
|
||||||
$sftpButton = new Button('SFTP Manager öffnen', 'w-full mt-4 px-4 py-2 bg-green-600 text-white rounded hover:bg-green-700 flex items-center justify-center');
|
$sftpButton = new Button(
|
||||||
|
'SFTP Manager öffnen',
|
||||||
|
'w-full mt-4 px-4 py-2 bg-green-600 text-white rounded hover:bg-green-700 flex items-center justify-center',
|
||||||
|
);
|
||||||
$sftpIcon = new Icon(IconName::home, 18, 'text-white mr-2');
|
$sftpIcon = new Icon(IconName::home, 18, 'text-white mr-2');
|
||||||
$sftpButton->setIcon($sftpIcon);
|
$sftpButton->setIcon($sftpIcon);
|
||||||
|
|
||||||
|
// Add synchronous click handler to switch tab immediately
|
||||||
|
$sftpButton->setOnClick(function () use ($tabContainer) {
|
||||||
|
$tabContainer->setActiveTab(3); // Switch to SFTP Manager tab immediately
|
||||||
|
});
|
||||||
|
|
||||||
$detailPanel->addComponent($sftpButton);
|
$detailPanel->addComponent($sftpButton);
|
||||||
|
|
||||||
|
// SSH Terminal Button
|
||||||
|
$sshTerminalButton = new Button(
|
||||||
|
'SSH Terminal öffnen',
|
||||||
|
'w-full mt-2 px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700 flex items-center justify-center',
|
||||||
|
);
|
||||||
|
$sshTerminalIcon = new Icon(IconName::home, 18, 'text-white mr-2');
|
||||||
|
$sshTerminalButton->setIcon($sshTerminalIcon);
|
||||||
|
|
||||||
|
// Add click handler to open SSH terminal
|
||||||
|
$sshTerminalButton->setOnClick(function () use (&$selectedServer, &$currentPrivateKeyPath, &$statusLabel) {
|
||||||
|
if ($selectedServer === null) {
|
||||||
|
$statusLabel->setText('Kein Server ausgewählt');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($currentPrivateKeyPath) || !file_exists($currentPrivateKeyPath)) {
|
||||||
|
$statusLabel->setText('Private Key Pfad nicht konfiguriert');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build SSH command with private key
|
||||||
|
$host = $selectedServer['ipv4'];
|
||||||
|
$keyPath = escapeshellarg($currentPrivateKeyPath);
|
||||||
|
$sshCommand = "ssh -i {$keyPath} root@{$host}";
|
||||||
|
|
||||||
|
// Try to open terminal with SSH connection
|
||||||
|
// Different terminal emulators for different systems
|
||||||
|
$terminals = [
|
||||||
|
'gnome-terminal -- ' . $sshCommand,
|
||||||
|
'konsole -e ' . $sshCommand,
|
||||||
|
'xterm -e ' . $sshCommand,
|
||||||
|
'x-terminal-emulator -e ' . $sshCommand,
|
||||||
|
];
|
||||||
|
|
||||||
|
$opened = false;
|
||||||
|
foreach ($terminals as $terminalCmd) {
|
||||||
|
exec($terminalCmd . ' > /dev/null 2>&1 &', $output, $returnCode);
|
||||||
|
if ($returnCode === 0) {
|
||||||
|
$opened = true;
|
||||||
|
$statusLabel->setText('SSH Terminal geöffnet für ' . $selectedServer['name']);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$opened) {
|
||||||
|
$statusLabel->setText('Konnte kein Terminal öffnen. SSH Befehl: ' . $sshCommand);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$detailPanel->addComponent($sshTerminalButton);
|
||||||
|
|
||||||
$tab1->addComponent($detailPanel);
|
$tab1->addComponent($detailPanel);
|
||||||
|
|
||||||
// Row selection handler - update detail panel
|
// Row selection handler - update detail panel
|
||||||
@ -209,7 +302,15 @@ $statusLabel = new Label(
|
|||||||
text: 'Fenster: ' . $window->getViewport()->windowWidth . 'x' . $window->getViewport()->windowHeight,
|
text: 'Fenster: ' . $window->getViewport()->windowWidth . 'x' . $window->getViewport()->windowHeight,
|
||||||
style: 'basis-4/8 text-black',
|
style: 'basis-4/8 text-black',
|
||||||
);
|
);
|
||||||
$table->setOnRowSelect(function ($index, $row) use (&$statusLabel, &$selectedServer, $detailId, $detailName, $detailStatus, $detailType, $detailIpv4) {
|
$table->setOnRowSelect(function ($index, $row) use (
|
||||||
|
&$statusLabel,
|
||||||
|
&$selectedServer,
|
||||||
|
$detailId,
|
||||||
|
$detailName,
|
||||||
|
$detailStatus,
|
||||||
|
$detailType,
|
||||||
|
$detailIpv4,
|
||||||
|
) {
|
||||||
if ($row) {
|
if ($row) {
|
||||||
$statusLabel->setText("Server: {$row['name']} - {$row['status']} ({$row['ipv4']})");
|
$statusLabel->setText("Server: {$row['name']} - {$row['status']} ({$row['ipv4']})");
|
||||||
|
|
||||||
@ -260,14 +361,29 @@ $loadServersAsync = function () use ($currentApiKey) {
|
|||||||
// Configure refresh button to load servers asynchronously
|
// Configure refresh button to load servers asynchronously
|
||||||
$refreshButton->setOnClickAsync(
|
$refreshButton->setOnClickAsync(
|
||||||
$loadServersAsync,
|
$loadServersAsync,
|
||||||
function ($result) use ($table, $statusLabel) {
|
function ($result) use ($table, $statusLabel, &$currentServerData, $searchInput) {
|
||||||
// Handle the result in the main thread (can access objects here)
|
// Handle the result in the main thread (can access objects here)
|
||||||
if (is_array($result)) {
|
if (is_array($result)) {
|
||||||
if (isset($result['error'])) {
|
if (isset($result['error'])) {
|
||||||
$statusLabel->setText('Fehler: ' . $result['error']);
|
$statusLabel->setText('Fehler: ' . $result['error']);
|
||||||
echo "Error: {$result['error']}\n";
|
echo "Error: {$result['error']}\n";
|
||||||
} elseif (isset($result['success'], $result['servers'])) {
|
} elseif (isset($result['success'], $result['servers'])) {
|
||||||
$table->setData($result['servers']);
|
// Update current server data
|
||||||
|
$currentServerData = $result['servers'];
|
||||||
|
|
||||||
|
// Check if search is active
|
||||||
|
$searchTerm = strtolower(trim($searchInput->getValue()));
|
||||||
|
if (empty($searchTerm)) {
|
||||||
|
// No search, show all servers
|
||||||
|
$table->setData($currentServerData);
|
||||||
|
} else {
|
||||||
|
// Apply search filter to new data
|
||||||
|
$filteredData = array_filter($currentServerData, function ($row) use ($searchTerm) {
|
||||||
|
return str_contains(strtolower($row['name']), $searchTerm);
|
||||||
|
});
|
||||||
|
$table->setData(array_values($filteredData));
|
||||||
|
}
|
||||||
|
|
||||||
$statusLabel->setText('Server geladen: ' . $result['count'] . ' gefunden');
|
$statusLabel->setText('Server geladen: ' . $result['count'] . ' gefunden');
|
||||||
echo "Success: {$result['count']} servers loaded\n";
|
echo "Success: {$result['count']} servers loaded\n";
|
||||||
}
|
}
|
||||||
@ -282,19 +398,7 @@ $refreshButton->setOnClickAsync(
|
|||||||
|
|
||||||
$tabContainer->addTab('Server', $tab1);
|
$tabContainer->addTab('Server', $tab1);
|
||||||
|
|
||||||
// Tab 2: Some info
|
// Tab 2: SFTP Manager (will be populated dynamically when server is selected)
|
||||||
$tab2 = new Container('flex flex-col p-4');
|
|
||||||
$tab2->addComponent(new Label('Dies ist Tab 2', 'text-xl font-bold mb-4'));
|
|
||||||
$tab2->addComponent(new Label('Hier könnte weiterer Inhalt stehen...', ''));
|
|
||||||
$tabContainer->addTab('Info', $tab2);
|
|
||||||
|
|
||||||
// Tab 3: Settings
|
|
||||||
$tab3 = new Container('flex flex-col p-4');
|
|
||||||
$tab3->addComponent(new Label('Einstellungen', 'text-xl font-bold mb-4'));
|
|
||||||
$tab3->addComponent(new Label('Konfigurationsoptionen...', ''));
|
|
||||||
$tabContainer->addTab('Einstellungen', $tab3);
|
|
||||||
|
|
||||||
// Tab 4: SFTP Manager (will be populated dynamically when server is selected)
|
|
||||||
$sftpTab = new Container('flex flex-row p-4 gap-4 bg-gray-50');
|
$sftpTab = new Container('flex flex-row p-4 gap-4 bg-gray-50');
|
||||||
|
|
||||||
// Left side: Local file browser
|
// Left side: Local file browser
|
||||||
@ -318,6 +422,80 @@ $sftpTab->addComponent($remoteBrowserContainer);
|
|||||||
|
|
||||||
$tabContainer->addTab('SFTP Manager', $sftpTab);
|
$tabContainer->addTab('SFTP Manager', $sftpTab);
|
||||||
|
|
||||||
|
// Remote FileBrowser navigation handler - load directory asynchronously
|
||||||
|
$remoteFileBrowser->setOnFileSelect(function ($path, $row) use (
|
||||||
|
$remoteFileBrowser,
|
||||||
|
&$selectedServer,
|
||||||
|
&$currentPrivateKeyPath,
|
||||||
|
&$statusLabel,
|
||||||
|
) {
|
||||||
|
if (!isset($row['isDir']) || !$row['isDir']) {
|
||||||
|
return; // Only handle directories
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load directory asynchronously via Button with async handler
|
||||||
|
$loadButton = new Button('Load', '');
|
||||||
|
$loadButton->setOnClickAsync(
|
||||||
|
function () use ($path, &$selectedServer, &$currentPrivateKeyPath) {
|
||||||
|
if ($selectedServer === null || empty($currentPrivateKeyPath)) {
|
||||||
|
return ['error' => 'Not connected'];
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$sftp = new \phpseclib3\Net\SFTP($selectedServer['ipv4']);
|
||||||
|
$key = \phpseclib3\Crypt\PublicKeyLoader::load(file_get_contents($currentPrivateKeyPath));
|
||||||
|
|
||||||
|
if (!$sftp->login('root', $key)) {
|
||||||
|
return ['error' => 'SFTP Login failed'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$files = $sftp->nlist($path);
|
||||||
|
if ($files === false) {
|
||||||
|
return ['error' => 'Cannot read directory'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$fileList = [];
|
||||||
|
foreach ($files as $file) {
|
||||||
|
if ($file === '.' || $file === '..') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$fullPath = rtrim($path, '/') . '/' . $file;
|
||||||
|
$stat = $sftp->stat($fullPath);
|
||||||
|
$fileList[] = [
|
||||||
|
'name' => $file,
|
||||||
|
'path' => $fullPath,
|
||||||
|
'isDir' => ($stat['type'] ?? 0) === 2,
|
||||||
|
'size' => $stat['size'] ?? 0,
|
||||||
|
'mtime' => $stat['mtime'] ?? 0,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return ['success' => true, 'path' => $path, 'files' => $fileList];
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return ['error' => $e->getMessage()];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
function ($result) use ($remoteFileBrowser, &$statusLabel) {
|
||||||
|
if (isset($result['error'])) {
|
||||||
|
$statusLabel->setText('SFTP Fehler: ' . $result['error']);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($result['success'])) {
|
||||||
|
$remoteFileBrowser->setPath($result['path']);
|
||||||
|
$remoteFileBrowser->setFileData($result['files']);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
function ($error) use (&$statusLabel) {
|
||||||
|
$errorMsg = is_string($error) ? $error : 'Unknown error';
|
||||||
|
$statusLabel->setText('SFTP Error: ' . $errorMsg);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
// Trigger the async load
|
||||||
|
$loadButton->handleMouseClick(0, 0, 0);
|
||||||
|
});
|
||||||
|
|
||||||
// SFTP Button Click Handler - Connect to server and load remote files
|
// SFTP Button Click Handler - Connect to server and load remote files
|
||||||
$sftpButton->setOnClickAsync(
|
$sftpButton->setOnClickAsync(
|
||||||
function () use (&$selectedServer, &$currentPrivateKeyPath) {
|
function () use (&$selectedServer, &$currentPrivateKeyPath) {
|
||||||
@ -382,7 +560,9 @@ $sftpButton->setOnClickAsync(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (isset($result['success']) && $result['success']) {
|
if (isset($result['success']) && $result['success']) {
|
||||||
$connectionStatusLabel->setText('Verbunden mit: ' . $result['server']['name'] . ' (' . $result['server']['ipv4'] . ')');
|
$connectionStatusLabel->setText(
|
||||||
|
'Verbunden mit: ' . $result['server']['name'] . ' (' . $result['server']['ipv4'] . ')',
|
||||||
|
);
|
||||||
$statusLabel->setText('SFTP Verbindung erfolgreich zu ' . $result['server']['name']);
|
$statusLabel->setText('SFTP Verbindung erfolgreich zu ' . $result['server']['name']);
|
||||||
|
|
||||||
// Populate remote file browser with the file list
|
// Populate remote file browser with the file list
|
||||||
@ -390,11 +570,13 @@ $sftpButton->setOnClickAsync(
|
|||||||
$remoteFileBrowser->setFileData($result['files']);
|
$remoteFileBrowser->setFileData($result['files']);
|
||||||
|
|
||||||
// Switch to SFTP Manager tab
|
// Switch to SFTP Manager tab
|
||||||
$tabContainer->setActiveTab(3); // Index 3 = SFTP Manager tab
|
$tabContainer->setActiveTab(1); // Index 3 = SFTP Manager tab
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
function ($error) use (&$statusLabel) {
|
function ($error) use (&$statusLabel) {
|
||||||
$errorMsg = is_string($error) ? $error : (is_object($error) && method_exists($error, 'getMessage') ? $error->getMessage() : 'Unbekannter Fehler');
|
$errorMsg = is_string($error)
|
||||||
|
? $error
|
||||||
|
: (is_object($error) && method_exists($error, 'getMessage') ? $error->getMessage() : 'Unbekannter Fehler');
|
||||||
$statusLabel->setText('SFTP Async Fehler: ' . $errorMsg);
|
$statusLabel->setText('SFTP Async Fehler: ' . $errorMsg);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@ -424,7 +606,16 @@ $cancelButton->setOnClick(function () use ($menuBar, $modal) {
|
|||||||
$modal->setVisible(false);
|
$modal->setVisible(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
$saveButton->setOnClick(function () use ($settings, &$currentApiKey, &$currentPrivateKeyPath, $apiKeyInput, $privateKeyPathInput, $menuBar, $modal, &$statusLabel) {
|
$saveButton->setOnClick(function () use (
|
||||||
|
$settings,
|
||||||
|
&$currentApiKey,
|
||||||
|
&$currentPrivateKeyPath,
|
||||||
|
$apiKeyInput,
|
||||||
|
$privateKeyPathInput,
|
||||||
|
$menuBar,
|
||||||
|
$modal,
|
||||||
|
&$statusLabel,
|
||||||
|
) {
|
||||||
$currentApiKey = trim($apiKeyInput->getValue());
|
$currentApiKey = trim($apiKeyInput->getValue());
|
||||||
$currentPrivateKeyPath = trim($privateKeyPathInput->getValue());
|
$currentPrivateKeyPath = trim($privateKeyPathInput->getValue());
|
||||||
|
|
||||||
|
|||||||
30
src/Ui/Widget/ClickableHeaderLabel.php
Normal file
30
src/Ui/Widget/ClickableHeaderLabel.php
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace PHPNative\Ui\Widget;
|
||||||
|
|
||||||
|
class ClickableHeaderLabel extends Label
|
||||||
|
{
|
||||||
|
private string $columnKey;
|
||||||
|
private Table $table;
|
||||||
|
|
||||||
|
public function __construct(string $columnKey, Table $table, string $title, string $style)
|
||||||
|
{
|
||||||
|
$this->columnKey = $columnKey;
|
||||||
|
$this->table = $table;
|
||||||
|
parent::__construct($title, $style);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handleMouseClick(float $mouseX, float $mouseY, int $button): bool
|
||||||
|
{
|
||||||
|
if (
|
||||||
|
$mouseX >= $this->viewport->x &&
|
||||||
|
$mouseX <= ($this->viewport->x + $this->viewport->width) &&
|
||||||
|
$mouseY >= $this->viewport->y &&
|
||||||
|
$mouseY <= ($this->viewport->y + $this->viewport->height)
|
||||||
|
) {
|
||||||
|
$this->table->sortByColumn($this->columnKey);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return parent::handleMouseClick($mouseX, $mouseY, $button);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -269,5 +269,34 @@ class FileBrowser extends Container
|
|||||||
}
|
}
|
||||||
|
|
||||||
$this->fileTable->setData($tableData);
|
$this->fileTable->setData($tableData);
|
||||||
|
|
||||||
|
// Set up row selection handler AFTER data is set (for remote browsers)
|
||||||
|
// This needs to be done every time because setData might reset handlers
|
||||||
|
$this->setupRemoteNavigationHandler();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setup navigation handler for remote file browser
|
||||||
|
*/
|
||||||
|
private function setupRemoteNavigationHandler(): void
|
||||||
|
{
|
||||||
|
if (!$this->isRemote) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$fileBrowser = $this;
|
||||||
|
$this->fileTable->setOnRowSelect(function ($index, $row) use ($fileBrowser) {
|
||||||
|
if ($row && isset($row['isDir']) && $row['isDir'] && !empty($row['path'])) {
|
||||||
|
// Trigger the external callback for directory navigation
|
||||||
|
if ($fileBrowser->onFileSelect !== null) {
|
||||||
|
($fileBrowser->onFileSelect)($row['path'], $row);
|
||||||
|
}
|
||||||
|
} elseif ($row && isset($row['path']) && !empty($row['path']) && !($row['isDir'] ?? false)) {
|
||||||
|
// File selected
|
||||||
|
if ($fileBrowser->onFileSelect !== null) {
|
||||||
|
($fileBrowser->onFileSelect)($row['path'], $row);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -48,17 +48,18 @@ class Table extends Container
|
|||||||
$this->headerContainer->clearChildren();
|
$this->headerContainer->clearChildren();
|
||||||
|
|
||||||
foreach ($columns as $column) {
|
foreach ($columns as $column) {
|
||||||
$title = $column['title'] ?? $column['key'];
|
$key = $column['key'];
|
||||||
|
$title = $column['title'] ?? $key;
|
||||||
$width = $column['width'] ?? null;
|
$width = $column['width'] ?? null;
|
||||||
|
|
||||||
$style = 'px-4 py-2 text-black font-bold border-r border-gray-300';
|
$style = 'px-4 py-2 text-black font-bold border-r border-gray-300 hover:bg-gray-300 cursor-pointer';
|
||||||
if ($width) {
|
if ($width) {
|
||||||
$style .= ' w-' . ((int) ($width / 4));
|
$style .= ' w-' . ((int) ($width / 4));
|
||||||
} else {
|
} else {
|
||||||
$style .= ' flex-1';
|
$style .= ' flex-1';
|
||||||
}
|
}
|
||||||
|
|
||||||
$headerLabel = new Label($title, $style);
|
$headerLabel = new ClickableHeaderLabel($key, $this, $title, $style);
|
||||||
$this->headerContainer->addComponent($headerLabel);
|
$this->headerContainer->addComponent($headerLabel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user