diff options
Diffstat (limited to '')
-rw-r--r-- | application/forms/EditNodeForm.php | 315 |
1 files changed, 315 insertions, 0 deletions
diff --git a/application/forms/EditNodeForm.php b/application/forms/EditNodeForm.php new file mode 100644 index 0000000..bd1592b --- /dev/null +++ b/application/forms/EditNodeForm.php @@ -0,0 +1,315 @@ +<?php + +namespace Icinga\Module\Businessprocess\Forms; + +use Icinga\Module\Businessprocess\BpConfig; +use Icinga\Module\Businessprocess\BpNode; +use Icinga\Module\Businessprocess\Modification\ProcessChanges; +use Icinga\Module\Businessprocess\Node; +use Icinga\Module\Businessprocess\ServiceNode; +use Icinga\Module\Businessprocess\Web\Form\Element\IplStateOverrides; +use Icinga\Module\Businessprocess\Web\Form\Validator\HostServiceTermValidator; +use Icinga\Module\Monitoring\Backend\MonitoringBackend; +use Icinga\Web\Session\SessionNamespace; +use ipl\Html\Attributes; +use ipl\Html\FormattedString; +use ipl\Html\HtmlElement; +use ipl\Html\ValidHtml; +use ipl\I18n\Translation; +use ipl\Web\Compat\CompatForm; +use ipl\Web\FormElement\TermInput\ValidatedTerm; +use ipl\Web\Url; + +class EditNodeForm extends CompatForm +{ + use Translation; + + /** @var ?BpConfig */ + protected $bp; + + /** @var ?Node */ + protected $node; + + /** @var ?BpNode */ + protected $parent; + + /** @var SessionNamespace */ + protected $session; + + /** + * Set the affected configuration + * + * @param BpConfig $bp + * + * @return $this + */ + public function setProcess(BpConfig $bp): self + { + $this->bp = $bp; + + return $this; + } + + /** + * Set the affected node + * + * @param Node $node + * + * @return $this + */ + public function setNode(Node $node): self + { + $this->node = $node; + + $this->populate([ + 'node-search' => $node->getName(), + 'node-label' => $node->getAlias() + ]); + + return $this; + } + + /** + * Set the affected sub-process + * + * @param ?BpNode $node + * + * @return $this + */ + public function setParentNode(BpNode $node = null): self + { + $this->parent = $node; + + if ($this->node !== null) { + $stateOverrides = $this->parent->getStateOverrides($this->node->getName()); + if (! empty($stateOverrides)) { + $this->populate([ + 'overrideStates' => 'y', + 'stateOverrides' => $stateOverrides + ]); + } + } + + return $this; + } + + /** + * Set the user's session + * + * @param SessionNamespace $session + * + * @return $this + */ + public function setSession(SessionNamespace $session): self + { + $this->session = $session; + + return $this; + } + + /** + * Identify and return the node the user has chosen + * + * @return Node + */ + protected function identifyChosenNode(): Node + { + $userInput = $this->getPopulatedValue('node'); + $nodeName = $this->getPopulatedValue('node-search'); + $nodeLabel = $this->getPopulatedValue('node-label'); + + if ($nodeName && $userInput === $nodeLabel) { + // User accepted a suggestion and didn't change it manually + $node = $this->bp->getNode($nodeName); + } elseif ($userInput && (! $nodeLabel || $userInput !== $nodeLabel)) { + // User didn't choose a suggestion or changed it manually + $node = $this->bp->getNode(BpConfig::joinNodeName($userInput, 'Hoststatus')); + } else { + // If the search and user input are both empty, it can only be the initial value + $node = $this->node; + } + + return $node; + } + + protected function assemble() + { + $this->addHtml(new HtmlElement('h2', null, FormattedString::create( + $this->translate('Modify "%s"'), + $this->node->getAlias() ?? $this->node->getName() + ))); + + if ($this->node instanceof ServiceNode) { + $this->assembleServiceElements(); + } else { + $this->assembleHostElements(); + } + + $this->addElement('submit', 'btn_submit', [ + 'label' => $this->translate('Save Changes') + ]); + } + + protected function assembleServiceElements(): void + { + if ($this->bp->getBackend() instanceof MonitoringBackend) { + $suggestionsPath = 'businessprocess/suggestions/monitoring-service'; + } else { + $suggestionsPath = 'businessprocess/suggestions/icingadb-service'; + } + + $node = $this->identifyChosenNode(); + + $this->addHtml($this->createSearchInput( + $this->translate('Service'), + $node->getAlias() ?? $node->getName(), + $suggestionsPath + )); + + $this->addElement('checkbox', 'overrideStates', [ + 'ignore' => true, + 'class' => 'autosubmit', + 'label' => $this->translate('Override Service State') + ]); + if ($this->getPopulatedValue('overrideStates') === 'y') { + $this->addElement(new IplStateOverrides('stateOverrides', [ + 'label' => $this->translate('State Overrides'), + 'options' => [ + 0 => $this->translate('OK'), + 1 => $this->translate('WARNING'), + 2 => $this->translate('CRITICAL'), + 3 => $this->translate('UNKNOWN'), + 99 => $this->translate('PENDING'), + ] + ])); + } + } + + protected function assembleHostElements(): void + { + if ($this->bp->getBackend() instanceof MonitoringBackend) { + $suggestionsPath = 'businessprocess/suggestions/monitoring-host'; + } else { + $suggestionsPath = 'businessprocess/suggestions/icingadb-host'; + } + + $node = $this->identifyChosenNode(); + + $this->addHtml($this->createSearchInput( + $this->translate('Host'), + $node->getAlias() ?? $node->getName(), + $suggestionsPath + )); + + $this->addElement('checkbox', 'overrideStates', [ + 'ignore' => true, + 'class' => 'autosubmit', + 'label' => $this->translate('Override Host State') + ]); + if ($this->getPopulatedValue('overrideStates') === 'y') { + $this->addElement(new IplStateOverrides('stateOverrides', [ + 'label' => $this->translate('State Overrides'), + 'options' => [ + 0 => $this->translate('UP'), + 1 => $this->translate('DOWN'), + 99 => $this->translate('PENDING') + ] + ])); + } + } + + protected function createSearchInput(string $label, string $value, string $suggestionsPath): ValidHtml + { + $userInput = $this->createElement('text', 'node', [ + 'ignore' => true, + 'required' => true, + 'autocomplete' => 'off', + 'label' => $label, + 'value' => $value, + 'data-enrichment-type' => 'completion', + 'data-term-suggestions' => '#node-suggestions', + 'data-suggest-url' => Url::fromPath($suggestionsPath, [ + 'node' => isset($this->parent) ? $this->parent->getName() : null, + 'config' => $this->bp->getName(), + 'showCompact' => true, + '_disableLayout' => true + ]), + 'validators' => ['callback' => function ($_, $validator) { + $newName = $this->identifyChosenNode()->getName(); + if ($newName === $this->node->getName()) { + return true; + } + + $term = new ValidatedTerm($newName); + + (new HostServiceTermValidator()) + ->setParent($this->parent) + ->isValid($term); + + if (! $term->isValid()) { + $validator->addMessage($term->getMessage()); + return false; + } + + return true; + }] + ]); + + $fieldset = new HtmlElement('fieldset'); + + $searchInput = $this->createElement('hidden', 'node-search', ['ignore' => true]); + $this->registerElement($searchInput); + $fieldset->addHtml($searchInput); + + $labelInput = $this->createElement('hidden', 'node-label', ['ignore' => true]); + $this->registerElement($labelInput); + $fieldset->addHtml($labelInput); + + $this->registerElement($userInput); + $this->decorate($userInput); + + $fieldset->addHtml( + $userInput, + new HtmlElement('div', Attributes::create([ + 'id' => 'node-suggestions', + 'class' => 'search-suggestions' + ])) + ); + + return $fieldset; + } + + protected function onSuccess() + { + $changes = ProcessChanges::construct($this->bp, $this->session); + + $children = $this->parent->getChildNames(); + $previousPos = array_search($this->node->getName(), $children, true); + $node = $this->identifyChosenNode(); + $nodeName = $node->getName(); + + $changes->deleteNode($this->node, $this->parent->getName()); + $changes->addChildrenToNode([$nodeName], $this->parent); + + $stateOverrides = $this->getValue('stateOverrides'); + if (! empty($stateOverrides)) { + $changes->modifyNode($this->parent, [ + 'stateOverrides' => array_merge($this->parent->getStateOverrides(), [ + $nodeName => $stateOverrides + ]) + ]); + } + + if ($this->bp->getMetadata()->isManuallyOrdered() && ($newPos = count($children) - 1) > $previousPos) { + $changes->moveNode( + $node, + $newPos, + $previousPos, + $this->parent->getName(), + $this->parent->getName() + ); + } + + unset($changes); + } +} |