로그인
KO
games/xencenter-xenadmin-xcp-jumphp / src / Form / NewPoolForm.php · commit fb1b7c9
<?phpnamespace App\Form;use App\Feature\Pools\PoolCommands;use App\Model\Connection;use App\Model\Session;use JumPHP\Gui\Button;use JumPHP\Gui\CheckBox;use JumPHP\Gui\ComboBox;use JumPHP\Gui\Container;use JumPHP\Gui\Form;use JumPHP\Gui\Label;use JumPHP\Gui\TextBox;/** * New Pool (mode 'new': a name, a master among the connected standalone servers, the others that join it) and Add Server (mode * 'add': servers that join the selected pool), as XenCenter's New Pool wizard and Add Server menu. Closes with * ['newPool' => [name, description, master, members]] or ['joinPool' => [pool, members]] (servers by their profile key); * Feature\Pools\PoolActions makes the XAPI calls. * * @property Label $heading * @property Label $where * @property Label $nameLabel * @property TextBox $name * @property Label $descriptionLabel * @property TextBox $description * @property Label $masterLabel * @property ComboBox $master * @property Label $membersLabel * @property Container $servers * @property Label $note * @property Label $error * @property Button $ok * @property Button $cancel */final class NewPoolForm extends Form{    public function __construct(private Session $session)    {        parent::__construct();    }    /** XAPI's answers, events and the console go on while this dialog is open. */    protected function tick(float $dt): void    {        $this->session->tick($dt);    }    private array $params = [];    /** @var array<string, CheckBox> server key => its box */    public array $boxes = [];    /** @return list<array{key: string, name: string, address: string, reason: string}> */    private static function servers(Session $session, ?Connection $except = null): array    {        return array_map(fn (Connection $c) => ['key' => $c->profile->key(), 'name' => $c->name(), 'address' => $c->profile->host, 'reason' => PoolCommands::cannotJoin($c)],            PoolCommands::standalone($session, $except));    }    /** @return array<string, mixed> */    public static function paramsForNew(Session $session): array    {        return ['mode' => 'new', 'servers' => self::servers($session)];    }    /** @return array<string, mixed> */    public static function paramsForAdd(Session $session, Connection $pool): array    {        return ['mode' => 'add', 'pool' => $pool->profile->key(), 'poolName' => $pool->name(), 'servers' => self::servers($session, $pool)];    }    protected function loaded(array $params = []): void    {        $this->params = $params;        $new = ($params['mode'] ?? 'new') === 'new';        $this->heading->text = $new ? 'New Pool' : "Add Server to pool '" . ($params['poolName'] ?? '') . "'";        $this->where->text = $new ? 'A pool shares storage and networks between servers; VMs move between them.' : 'The servers below are connected and in no pool.';        foreach ([$this->nameLabel, $this->name, $this->descriptionLabel, $this->description, $this->masterLabel, $this->master] as $w) {            $w->visible = $new;        }        $this->name->text = '';        $this->description->text = '';        $this->error->text = '';        $this->ok->text = $new ? 'Create Pool' : 'Add';        $servers = (array)($params['servers'] ?? []);        $this->master->items = array_map(fn (array $s) => $s['name'] . ' (' . $s['address'] . ')', $servers);        $this->master->selected = $servers === [] ? -1 : 0;        $this->membersLabel->text = $new ? 'Other servers that join the pool:' : 'Servers that join the pool:';        $this->boxes();        $this->setFocus($new ? $this->name : null);    }    /** The master's server key (mode 'new'). */    private function masterKey(): ?string    {        $servers = (array)($this->params['servers'] ?? []);        return ($this->params['mode'] ?? 'new') === 'new' ? ($servers[$this->master->selected]['key'] ?? null) : null;    }    /** One box per server that may join (not the master); a server that cannot says why. */    private function boxes(): void    {        $checked = array_map(fn (CheckBox $b) => (bool)$b->checked, $this->boxes);        $this->servers->clear();        $this->boxes = [];        $master = $this->masterKey();        foreach ((array)($this->params['servers'] ?? []) as $s) {            if ($s['key'] === $master) {                continue;            }            $box = new CheckBox(['text' => $s['name'] . ' (' . $s['address'] . ')' . ($s['reason'] !== '' ? ' — cannot join: ' . $s['reason'] : ''),                'checked' => $s['reason'] === '' && ($checked[$s['key']] ?? ($this->params['mode'] ?? 'new') === 'add'), 'enabled' => $s['reason'] === '']);            $this->boxes[$s['key']] = $box;            $this->servers->add($box);        }        if ($this->boxes === []) {            $this->servers->add(new Label(['text' => ($this->params['mode'] ?? 'new') === 'new' ? 'No other server: the pool has the master alone (add servers later).'                : 'No connected server is in no pool: add one first (File > Add New Server…).', 'style' => 'muted', 'wrap' => true]));        }    }    public function onMasterChange(ComboBox $sender, int $index, string $text): void    {        $this->boxes();    }    /** @return list<string> the keys of the ticked servers */    public function members(): array    {        return array_keys(array_filter($this->boxes, fn (CheckBox $b) => (bool)$b->checked && $b->isEnabled()));    }    public function onOkClick(Button $sender): void    {        if (($this->params['mode'] ?? 'new') === 'add') {            if ($this->members() === []) {                $this->error->text = 'Tick at least one server.';                return;            }            $this->close(['joinPool' => ['pool' => (string)$this->params['pool'], 'members' => $this->members()]]);            return;        }        if (trim($this->name->text) === '') {            $this->error->text = 'Enter a name for the pool.';            return;        }        if ($this->masterKey() === null) {            $this->error->text = 'Choose the master.';            return;        }        $this->close(['newPool' => ['name' => trim($this->name->text), 'description' => trim($this->description->text), 'master' => $this->masterKey(), 'members' => $this->members()]]);    }    public function onCancelClick(Button $sender): void    {        $this->close();    }}