diff --git a/application/controllers/EventRuleController.php b/application/controllers/EventRuleController.php index 9208179bd..e190fe5f9 100644 --- a/application/controllers/EventRuleController.php +++ b/application/controllers/EventRuleController.php @@ -7,8 +7,8 @@ use Icinga\Module\Notifications\Common\Auth; use Icinga\Module\Notifications\Common\Database; use Icinga\Module\Notifications\Common\Links; -use Icinga\Module\Notifications\Forms\EventRuleForm; -use Icinga\Module\Notifications\Forms\SaveEventRuleForm; +use Icinga\Module\Notifications\Forms\EventRuleConfig\EventRuleForm; +use Icinga\Module\Notifications\Forms\EventRuleConfig\SaveEventRuleForm; use Icinga\Module\Notifications\Model\Incident; use Icinga\Module\Notifications\Model\ObjectExtraTag; use Icinga\Module\Notifications\Model\Rule; diff --git a/application/controllers/EventRulesController.php b/application/controllers/EventRulesController.php index 21e89a91a..73c998505 100644 --- a/application/controllers/EventRulesController.php +++ b/application/controllers/EventRulesController.php @@ -7,8 +7,8 @@ use Icinga\Exception\ProgrammingError; use Icinga\Module\Notifications\Common\Database; use Icinga\Module\Notifications\Common\Links; -use Icinga\Module\Notifications\Forms\EventRuleForm; -use Icinga\Module\Notifications\Forms\SaveEventRuleForm; +use Icinga\Module\Notifications\Forms\EventRuleConfig\EventRuleForm; +use Icinga\Module\Notifications\Forms\EventRuleConfig\SaveEventRuleForm; use Icinga\Module\Notifications\Model\ObjectExtraTag; use Icinga\Module\Notifications\Model\Rule; use Icinga\Module\Notifications\Web\Control\SearchBar\ObjectSuggestions; diff --git a/application/forms/AddEscalationForm.php b/application/forms/EventRuleConfig/AddEscalationForm.php similarity index 81% rename from application/forms/AddEscalationForm.php rename to application/forms/EventRuleConfig/AddEscalationForm.php index 44e2ba6ca..2ed11010a 100644 --- a/application/forms/AddEscalationForm.php +++ b/application/forms/EventRuleConfig/AddEscalationForm.php @@ -2,7 +2,7 @@ /* Icinga Notifications Web | (c) 2023 Icinga GmbH | GPLv2 */ -namespace Icinga\Module\Notifications\Forms; +namespace Icinga\Module\Notifications\Forms\EventRuleConfig; use Icinga\Web\Session; use ipl\Html\Form; @@ -18,7 +18,7 @@ class AddEscalationForm extends Form use Translation; protected $defaultAttributes = [ - 'class' => ['add-escalation-form', 'icinga-form', 'icinga-controls'], + 'class' => ['add-escalation-form', 'icinga-controls'], 'name' => 'add-escalation-form' ]; @@ -33,7 +33,7 @@ protected function assemble() 'submitButton', 'add', [ - 'class' => ['add-button', 'control-button', 'spinner'], + 'class' => ['add-button', 'spinner'], 'label' => new Icon('plus'), 'title' => $this->translate('Add a new escalation') ] diff --git a/application/forms/AddFilterForm.php b/application/forms/EventRuleConfig/AddFilterForm.php similarity index 81% rename from application/forms/AddFilterForm.php rename to application/forms/EventRuleConfig/AddFilterForm.php index aee6ded69..b362ff5f9 100644 --- a/application/forms/AddFilterForm.php +++ b/application/forms/EventRuleConfig/AddFilterForm.php @@ -2,7 +2,7 @@ /* Icinga Notifications Web | (c) 2023 Icinga GmbH | GPLv2 */ -namespace Icinga\Module\Notifications\Forms; +namespace Icinga\Module\Notifications\Forms\EventRuleConfig; use Icinga\Web\Session; use ipl\Html\Form; @@ -18,7 +18,7 @@ class AddFilterForm extends Form use Translation; protected $defaultAttributes = [ - 'class' => ['add-filter-form', 'icinga-form', 'icinga-controls'], + 'class' => ['add-filter-form', 'icinga-controls'], 'name' => 'add-filter-form' ]; @@ -33,7 +33,7 @@ protected function assemble() 'submitButton', 'add', [ - 'class' => ['add-button', 'control-button', 'spinner'], + 'class' => ['add-button', 'spinner'], 'label' => new Icon('plus'), 'title' => $this->translate('Add filter') ] diff --git a/application/forms/BaseEscalationForm.php b/application/forms/EventRuleConfig/BaseEscalationForm.php similarity index 73% rename from application/forms/BaseEscalationForm.php rename to application/forms/EventRuleConfig/BaseEscalationForm.php index d4dab933b..982415b87 100644 --- a/application/forms/BaseEscalationForm.php +++ b/application/forms/EventRuleConfig/BaseEscalationForm.php @@ -2,11 +2,14 @@ /* Icinga Notifications Web | (c) 2023 Icinga GmbH | GPLv2 */ -namespace Icinga\Module\Notifications\Forms; +namespace Icinga\Module\Notifications\Forms\EventRuleConfig; +use Icinga\Module\Notifications\Widget\EventRuleConfig\FlowLine; use Icinga\Web\Session; +use ipl\Html\Attributes; use ipl\Html\Contract\FormElement; use ipl\Html\Form; +use ipl\Html\HtmlElement; use ipl\Html\ValidHtml; use ipl\I18n\Translation; use ipl\Web\Common\CsrfCounterMeasure; @@ -19,7 +22,7 @@ abstract class BaseEscalationForm extends Form use FormUid; use Translation; - protected $defaultAttributes = ['class' => ['escalation-form', 'icinga-form', 'icinga-controls']]; + protected $defaultAttributes = ['class' => ['escalation-form', 'icinga-controls']]; /** @var int The count of existing conditions/recipients */ protected $count; @@ -51,7 +54,7 @@ protected function createAddButton(): FormElement 'submitButton', 'add', [ - 'class' => ['add-button', 'control-button', 'spinner'], + 'class' => ['add-button', 'spinner'], 'label' => new Icon('plus'), 'title' => $this->translate('Add more'), 'formnovalidate' => true @@ -79,7 +82,15 @@ protected function assemble() $this->assembleElements(); } - $this->add($addButton); + if ($this->options) { + $wrapper = new HtmlElement('div', Attributes::create(['class' => 'option-wrapper'])); + $wrapper->addHtml(new HtmlElement('ul', Attributes::create(['class' => 'options']), ...$this->options)); + $wrapper->addHtml($addButton); + $this->addHtml($wrapper); + } else { + $this->addHtml((new FlowLine())->getRightArrow()); + $this->addHtml($addButton); + } } public function isAddButtonPressed(): ?bool diff --git a/application/forms/EscalationConditionForm.php b/application/forms/EventRuleConfig/EscalationConditionForm.php similarity index 97% rename from application/forms/EscalationConditionForm.php rename to application/forms/EventRuleConfig/EscalationConditionForm.php index 8458a1155..563ad9b7a 100644 --- a/application/forms/EscalationConditionForm.php +++ b/application/forms/EventRuleConfig/EscalationConditionForm.php @@ -2,7 +2,7 @@ /* Icinga Notifications Web | (c) 2023 Icinga GmbH | GPLv2 */ -namespace Icinga\Module\Notifications\Forms; +namespace Icinga\Module\Notifications\Forms\EventRuleConfig; use Icinga\Module\Notifications\Web\FilterRenderer; use Icinga\Module\Notifications\Web\Form\EventRuleDecorator; @@ -11,8 +11,6 @@ use ipl\Stdlib\Filter; use ipl\Validator\CallbackValidator; use ipl\Web\Filter\QueryString; -use ipl\Web\Filter\Renderer; -use ipl\Web\Url; use ipl\Web\Widget\Icon; class EscalationConditionForm extends BaseEscalationForm @@ -154,8 +152,6 @@ protected function assembleElements(): void } $this->handleRemove(); - - $this->add(Html::tag('ul', ['class' => 'options'], $this->options)); } public function getValues() @@ -223,7 +219,7 @@ protected function createRemoveButton(int $count): ?FormElement 'submitButton', 'remove_' . $count, [ - 'class' => ['remove-button', 'control-button', 'spinner'], + 'class' => ['remove-button', 'spinner'], 'label' => new Icon('minus'), 'title' => $this->translate('Remove'), 'formnovalidate' => true @@ -262,6 +258,10 @@ protected function handleRemove(): void } } + if (! $this->deleteRemoveButton || $this->count > 1) { + $this->addAttributes(['class' => 'removal-allowed']); + } + if (empty($this->options)) { $this->addAttributes(['class' => 'count-zero-escalation-condition-form']); } else { diff --git a/application/forms/EscalationRecipientForm.php b/application/forms/EventRuleConfig/EscalationRecipientForm.php similarity index 97% rename from application/forms/EscalationRecipientForm.php rename to application/forms/EventRuleConfig/EscalationRecipientForm.php index 61e093b2d..576391346 100644 --- a/application/forms/EscalationRecipientForm.php +++ b/application/forms/EventRuleConfig/EscalationRecipientForm.php @@ -2,7 +2,7 @@ /* Icinga Notifications Web | (c) 2023 Icinga GmbH | GPLv2 */ -namespace Icinga\Module\Notifications\Forms; +namespace Icinga\Module\Notifications\Forms\EventRuleConfig; use Icinga\Module\Notifications\Common\Database; use Icinga\Module\Notifications\Model\Channel; @@ -114,8 +114,6 @@ protected function assembleElements(): void } $this->handleRemove(); - - $this->add(Html::tag('ul', ['class' => 'options'], $this->options)); } public function getValues() @@ -189,7 +187,7 @@ protected function createRemoveButton(int $count): ?FormElement 'submitButton', 'remove_' . $count, [ - 'class' => ['remove-button', 'control-button', 'spinner'], + 'class' => ['remove-button', 'spinner'], 'label' => new Icon('minus'), 'title' => $this->translate('Remove'), 'formnovalidate' => true diff --git a/application/forms/EventRuleForm.php b/application/forms/EventRuleConfig/EventRuleForm.php similarity index 95% rename from application/forms/EventRuleForm.php rename to application/forms/EventRuleConfig/EventRuleForm.php index 54379ecf8..40cc4bb04 100644 --- a/application/forms/EventRuleForm.php +++ b/application/forms/EventRuleConfig/EventRuleForm.php @@ -2,7 +2,7 @@ /* Icinga Notifications Web | (c) 2023 Icinga GmbH | GPLv2 */ -namespace Icinga\Module\Notifications\Forms; +namespace Icinga\Module\Notifications\Forms\EventRuleConfig; use Icinga\Web\Session; use ipl\Html\Form; diff --git a/application/forms/RemoveEscalationForm.php b/application/forms/EventRuleConfig/RemoveEscalationForm.php similarity index 56% rename from application/forms/RemoveEscalationForm.php rename to application/forms/EventRuleConfig/RemoveEscalationForm.php index 1154d7506..ba59b96f2 100644 --- a/application/forms/RemoveEscalationForm.php +++ b/application/forms/EventRuleConfig/RemoveEscalationForm.php @@ -2,7 +2,7 @@ /* Icinga Notifications Web | (c) 2023 Icinga GmbH | GPLv2 */ -namespace Icinga\Module\Notifications\Forms; +namespace Icinga\Module\Notifications\Forms\EventRuleConfig; use Icinga\Web\Session; use ipl\Html\Form; @@ -18,11 +18,11 @@ class RemoveEscalationForm extends Form use Translation; protected $defaultAttributes = [ - 'class' => ['remove-escalation-form', 'icinga-form', 'icinga-controls'], + 'class' => ['remove-escalation-form', 'icinga-controls'], ]; - /** @var bool */ - private $disableRemoveButtton; + /** @var string */ + private $disableReason; protected function assemble() { @@ -33,7 +33,7 @@ protected function assemble() 'submitButton', 'remove', [ - 'class' => ['remove-button', 'control-button', 'spinner'], + 'class' => ['remove-button', 'spinner'], 'label' => new Icon('minus') ] ); @@ -41,29 +41,23 @@ protected function assemble() $this->getElement('remove') ->getAttributes() ->registerAttributeCallback('disabled', function () { - return $this->disableRemoveButtton; + return $this->disableReason !== null; }) ->registerAttributeCallback('title', function () { - if ($this->disableRemoveButtton) { - return $this->translate( - 'There exist active incidents for this escalation and hence cannot be removed' - ); - } - - return $this->translate('Remove escalation'); + return $this->disableReason ?? $this->translate('Remove escalation'); }); } /** - * Method to set disabled state of remove button + * Disable the button and show the given reason in the title * - * @param bool $disable + * @param string $reason * * @return $this */ - public function setRemoveButtonDisabled(bool $state = false) + public function setRemoveButtonDisabled(string $reason) { - $this->disableRemoveButtton = $state; + $this->disableReason = $reason; return $this; } diff --git a/application/forms/SaveEventRuleForm.php b/application/forms/EventRuleConfig/SaveEventRuleForm.php similarity index 99% rename from application/forms/SaveEventRuleForm.php rename to application/forms/EventRuleConfig/SaveEventRuleForm.php index f7bd7aa0f..4fc4a2af1 100644 --- a/application/forms/SaveEventRuleForm.php +++ b/application/forms/EventRuleConfig/SaveEventRuleForm.php @@ -2,7 +2,7 @@ /* Icinga Notifications Web | (c) 2023 Icinga GmbH | GPLv2 */ -namespace Icinga\Module\Notifications\Forms; +namespace Icinga\Module\Notifications\Forms\EventRuleConfig; use Exception; use Icinga\Module\Notifications\Common\Database; diff --git a/library/Notifications/Widget/Escalations.php b/library/Notifications/Widget/Escalations.php deleted file mode 100644 index de216093d..000000000 --- a/library/Notifications/Widget/Escalations.php +++ /dev/null @@ -1,64 +0,0 @@ - 'escalations']; - - protected $tag = 'div'; - - protected $config; - - private $escalations = []; - - protected function assemble() - { - $this->add($this->escalations); - } - - public function addEscalation(int $position, array $escalation, ?RemoveEscalationForm $removeEscalationForm = null) - { - $flowLine = (new FlowLine())->getRightArrow(); - - if ( - in_array( - 'count-zero-escalation-condition-form', - $escalation[0]->getAttributes()->get('class')->getValue() - ) - ) { - $flowLine->addAttributes(['class' => 'right-arrow-long']); - } - - if ($removeEscalationForm) { - $this->escalations[$position] = Html::tag( - 'div', - ['class' => 'escalation'], - [ - $removeEscalationForm, - $flowLine, - $escalation[0], - $flowLine, - $escalation[1], - ] - ); - } else { - $this->escalations[$position] = Html::tag( - 'div', - ['class' => 'escalation'], - [ - $flowLine->addAttributes(['class' => 'right-arrow-one-escalation']), - $escalation[0], - $flowLine, - $escalation[1] - ] - ); - } - } -} diff --git a/library/Notifications/Widget/EventRuleConfig.php b/library/Notifications/Widget/EventRuleConfig.php index 7bca0867f..51291b715 100644 --- a/library/Notifications/Widget/EventRuleConfig.php +++ b/library/Notifications/Widget/EventRuleConfig.php @@ -6,13 +6,15 @@ use Icinga\Exception\ProgrammingError; use Icinga\Module\Notifications\Common\Database; -use Icinga\Module\Notifications\Forms\AddEscalationForm; -use Icinga\Module\Notifications\Forms\AddFilterForm; -use Icinga\Module\Notifications\Forms\EscalationConditionForm; -use Icinga\Module\Notifications\Forms\EscalationRecipientForm; +use Icinga\Module\Notifications\Forms\EventRuleConfig\AddEscalationForm; +use Icinga\Module\Notifications\Forms\EventRuleConfig\AddFilterForm; +use Icinga\Module\Notifications\Forms\EventRuleConfig\EscalationConditionForm; +use Icinga\Module\Notifications\Forms\EventRuleConfig\EscalationRecipientForm; use Icinga\Module\Notifications\Model\Incident; +use Icinga\Module\Notifications\Widget\EventRuleConfig\Escalations; +use Icinga\Module\Notifications\Widget\EventRuleConfig\FlowLine; use ipl\Html\Attributes; -use Icinga\Module\Notifications\Forms\RemoveEscalationForm; +use Icinga\Module\Notifications\Forms\EventRuleConfig\RemoveEscalationForm; use ipl\Html\BaseHtmlElement; use ipl\Html\Form; use ipl\Html\FormElement\TextElement; @@ -199,7 +201,7 @@ protected function assemble() $searchBar = new TextElement( 'searchbar', [ - 'class' => 'filter-input control-button', + 'class' => 'filter-input', 'readonly' => true, 'value' => isset($this->config['object_filter']) ? rawurldecode($this->config['object_filter']) @@ -226,7 +228,12 @@ protected function assemble() if (isset($this->removeEscalationForms[$position])) { $escalations->addEscalation($position, $escalation, $this->removeEscalationForms[$position]); } else { - $escalations->addEscalation($position, $escalation); + $escalations->addEscalation( + $position, + $escalation, + $this->createRemoveEscalationForm($position) + ->setRemoveButtonDisabled(t('Removal not possible. There must be at least one escalation.')) + ); } } @@ -349,10 +356,8 @@ private function createRemoveEscalationForm(int $position): RemoveEscalationForm } } - $form = (new RemoveEscalationForm()) ->addAttributes(['name' => 'remove-escalation-form-' . $escalationId]) - ->setRemoveButtonDisabled($disableRemoveButton) ->on(Form::ON_SENT, function ($form) use ($position) { unset($this->config['rule_escalation'][$position]); unset($this->escalationForms[$position]); @@ -401,6 +406,11 @@ private function createRemoveEscalationForm(int $position): RemoveEscalationForm $this->emit(self::ON_CHANGE, [$this]); }); + if ($disableRemoveButton) { + $form->setRemoveButtonDisabled( + t('Removal not possible. There are active incidents for this escalation.') + ); + } return $form; } diff --git a/library/Notifications/Widget/CheckboxIcon.php b/library/Notifications/Widget/EventRuleConfig/CheckboxIcon.php similarity index 80% rename from library/Notifications/Widget/CheckboxIcon.php rename to library/Notifications/Widget/EventRuleConfig/CheckboxIcon.php index 16c5845c6..618bc6c76 100644 --- a/library/Notifications/Widget/CheckboxIcon.php +++ b/library/Notifications/Widget/EventRuleConfig/CheckboxIcon.php @@ -2,13 +2,10 @@ /* Icinga Notifications Web | (c) 2023 Icinga GmbH | GPLv2 */ -namespace Icinga\Module\Notifications\Widget; +namespace Icinga\Module\Notifications\Widget\EventRuleConfig; -use Icinga\Module\Notifications\Model\Contact; -use Icinga\Module\Notifications\Model\RuleEscalationRecipient; use ipl\Html\BaseHtmlElement; use ipl\Html\Html; -use ipl\Web\Widget\Icon; class CheckboxIcon extends BaseHtmlElement { diff --git a/library/Notifications/Widget/EventRuleConfig/Escalations.php b/library/Notifications/Widget/EventRuleConfig/Escalations.php new file mode 100644 index 000000000..8dc292fab --- /dev/null +++ b/library/Notifications/Widget/EventRuleConfig/Escalations.php @@ -0,0 +1,51 @@ + 'escalations']; + + protected $tag = 'div'; + + protected $config; + + private $escalations = []; + + protected function assemble() + { + $this->add($this->escalations); + } + + public function addEscalation(int $position, array $escalation, RemoveEscalationForm $removeEscalationForm) + { + $flowLine = (new FlowLine())->getRightArrow(); + + if ( + in_array( + 'count-zero-escalation-condition-form', + $escalation[0]->getAttributes()->get('class')->getValue() + ) + ) { + $flowLine->addAttributes(['class' => 'right-arrow-long']); + } + + $this->escalations[$position] = Html::tag( + 'div', + ['class' => 'escalation'], + [ + $removeEscalationForm, + $flowLine, + $escalation[0], + $flowLine, + $escalation[1], + ] + ); + } +} diff --git a/library/Notifications/Widget/FlowLine.php b/library/Notifications/Widget/EventRuleConfig/FlowLine.php similarity index 88% rename from library/Notifications/Widget/FlowLine.php rename to library/Notifications/Widget/EventRuleConfig/FlowLine.php index 20c43926d..33565caef 100644 --- a/library/Notifications/Widget/FlowLine.php +++ b/library/Notifications/Widget/EventRuleConfig/FlowLine.php @@ -2,10 +2,9 @@ /* Icinga Notifications Web | (c) 2023 Icinga GmbH | GPLv2 */ -namespace Icinga\Module\Notifications\Widget; +namespace Icinga\Module\Notifications\Widget\EventRuleConfig; use ipl\Html\BaseHtmlElement; -use ipl\Web\Widget\StateBall; class FlowLine extends BaseHtmlElement { diff --git a/library/Notifications/Widget/RightArrow.php b/library/Notifications/Widget/EventRuleConfig/RightArrow.php similarity index 75% rename from library/Notifications/Widget/RightArrow.php rename to library/Notifications/Widget/EventRuleConfig/RightArrow.php index 0eb2931a5..4f2f23858 100644 --- a/library/Notifications/Widget/RightArrow.php +++ b/library/Notifications/Widget/EventRuleConfig/RightArrow.php @@ -2,10 +2,9 @@ /* Icinga Notifications Web | (c) 2023 Icinga GmbH | GPLv2 */ -namespace Icinga\Module\Notifications\Widget; +namespace Icinga\Module\Notifications\Widget\EventRuleConfig; use ipl\Html\BaseHtmlElement; -use ipl\Web\Widget\StateBall; class RightArrow extends BaseHtmlElement { diff --git a/library/Notifications/Widget/RuleEscalationRecipientBadge.php b/library/Notifications/Widget/EventRuleConfig/RuleEscalationRecipientBadge.php similarity index 96% rename from library/Notifications/Widget/RuleEscalationRecipientBadge.php rename to library/Notifications/Widget/EventRuleConfig/RuleEscalationRecipientBadge.php index 698b10b1d..611d9d52c 100644 --- a/library/Notifications/Widget/RuleEscalationRecipientBadge.php +++ b/library/Notifications/Widget/EventRuleConfig/RuleEscalationRecipientBadge.php @@ -2,7 +2,7 @@ /* Icinga Notifications Web | (c) 2023 Icinga GmbH | GPLv2 */ -namespace Icinga\Module\Notifications\Widget; +namespace Icinga\Module\Notifications\Widget\EventRuleConfig; use Icinga\Module\Notifications\Model\Contact; use Icinga\Module\Notifications\Model\RuleEscalationRecipient; diff --git a/library/Notifications/Widget/ItemList/EventRuleListItem.php b/library/Notifications/Widget/ItemList/EventRuleListItem.php index 59eefa31a..4a7361338 100644 --- a/library/Notifications/Widget/ItemList/EventRuleListItem.php +++ b/library/Notifications/Widget/ItemList/EventRuleListItem.php @@ -7,8 +7,8 @@ use Icinga\Module\Notifications\Common\BaseListItem; use Icinga\Module\Notifications\Common\Links; use Icinga\Module\Notifications\Model\Rule; -use Icinga\Module\Notifications\Widget\CheckboxIcon; -use Icinga\Module\Notifications\Widget\RuleEscalationRecipientBadge; +use Icinga\Module\Notifications\Widget\EventRuleConfig\CheckboxIcon; +use Icinga\Module\Notifications\Widget\EventRuleConfig\RuleEscalationRecipientBadge; use ipl\Html\BaseHtmlElement; use ipl\Html\Html; use ipl\Web\Widget\Icon; diff --git a/public/css/detail/event-rule-detail.less b/public/css/detail/event-rule-detail.less index 6f85b48dd..8918a5bbf 100644 --- a/public/css/detail/event-rule-detail.less +++ b/public/css/detail/event-rule-detail.less @@ -1,365 +1,242 @@ .event-rule-detail { + @connectorHeight: .5em; + @connectorColor: @gray-lighter; + + // Layout + display: flex; - align-items: baseline; - > .right-arrow:first-child { - margin-top: 3.125em; + > .right-arrow, + > .horizontal-line { + flex: 1 1 auto; + height: @connectorHeight; + margin-top: 2.75em; + min-width: 1em; } - &.invalid { - .escalations .escalation form.escalation-form { - select, - input { - &:invalid { - background-color: red; - } - } + > .search-controls { + flex: 3 1 auto; + min-width: 16em; + height: fit-content; + margin-top: 1.25em; + + .filter-input { + width: 100%; + margin-right: .5em; } } - .search-controls { - display: inline-flex; - width: 20em; - min-width: unset; - padding: 0.5em; - border: 1px solid @gray-lighter; - border-radius: 0.5em; - - input.filter-input { - width: 20em; - background-color: @search-term-bg; - color: @search-term-color; - } + > .escalations-with-add-form { + flex: 15 1 auto; } .escalations { - display: inline-flex; - flex-direction: column; - width: 70em; + display: grid; + grid-template-columns: min-content minmax(1em, 4em) 1fr minmax(1em, 4em) 1fr; - .vertical-line { - position: absolute; - z-index: -1; - top: 15%; - bottom: 0; - margin-left: 1.25em; + .escalation { + display: contents; } - > .escalation { - display: flex; - align-items: center; - padding-bottom: 2em; - position: relative; - - &:before { - content: ""; - display: block; - position: absolute; - top: 0; - bottom: 0; - width: .5em; - margin-left: 1.25em; - background: @gray-lighter; - z-index: -1; - } - - &:first-child:before { - content: ""; - display: block; - top: calc(~"50% - 1em"); - } - - .right-arrow:first-child { - width: 2em; - } - - .right-arrow-long { - width: 38em; - } + .remove-escalation-form { + .vertical-line(); - .right-arrow.right-arrow-long:first-child { - width: 47em; - } - - .right-arrow-one-escalation:first-child { - width: 15em; + .remove-button { + margin-top: 2em; } + } - .escalation-condition-form, - .escalation-recipient-form { - width: 100%; - - padding: 0.5em; - border: 1px solid @gray-lighter; - border-radius: 0.5em; - - .options { - list-style-type: none; - padding: 0; - margin: 0; - - > li { - display: flex; - margin-bottom: .4em; - - &.option { - .errors { - display: inline-flex; - width: fit-content; - margin: 0; - } - - .errors + .remove-button { - margin: 0; - } - } - } + // The first escalation isn't connected to anything on top of it + .escalation:first-child .remove-escalation-form::before { + top: 2em; + } - .default-channel { - color: @disabled-gray; - } + .right-arrow { + height: @connectorHeight; + margin-top: 2.75em; + } - select, input { - min-width: 10em; - text-align: center; - height: 2.25em; - line-height: normal; - background: @search-term-bg; - color: @search-term-color; - } + .escalation-form { + position: relative; + margin-bottom: 1em; - select { - background-image: url('@{iplWebAssets}/img/select-icon.svg'); - background-position: center right; - background-repeat: no-repeat; - } + .options { + list-style-type: none; + margin: 0; + padding: 0; - .left-operand { - border-radius: 0.4em 0 0 0.4em; - margin-right: 1px; - } + .option { + display: flex; + margin-bottom: .5em; + .left-operand, .right-operand { - border-radius: 0 0.4em 0.4em 0; + flex: 1 1 4em; + min-width: 8em; width: 0; - flex: 1 1 auto; - margin-left: 1px; } .operator-input { - min-width: unset; - padding-right: 0.5em; - width: 3em; - border-radius: unset; - margin: 0 1px; - background: @search-term-bg; - color: @search-term-color; - - option { text-align: center; } + width: 4em; } } - .remove-button { - height: 2.25em; - margin-left: 0.5em; - } - } + & + .add-button { + width: 100%; - .escalation-condition-form.count-zero-escalation-condition-form { - width: fit-content; - border: none; - margin: 0; - padding: 0; - - button[type="submit"] { - font-size: 2em; - width: 3em; - margin: 0; - background: @low-sat-blue; - border: none; - - &:hover { - background: @low-sat-blue-dark; + > .icon { + margin: 0 auto; } } } - .escalation-condition-form.count-zero-escalation-condition-form:after { - content: 'Condition'; - align-self: center; - margin-bottom: -1.5em; - color: @text-color-light; + &.removal-allowed .add-button { + width: ~"calc(100% - 3.1em)"; // remove-button width + margin-left = 3.1em } - } - } -} -.escalations-with-add-form { - .add-escalation-form { - position: relative; - margin-left: -0.1em; - } -} + :not(.options) + .add-button { + position: absolute; + left: 50%; + top: 50%; + transform: translate(-50%, -50%); + } + } -.cache-notice { - margin: 1em; - padding: 1em; - background-color: @gray-lighter; - text-align: center; - .rounded-corners(); -} + .escalation:first-child .escalation-form .option:first-child .remove-button { + height: auto; // Don't ask me (jom) why this is necessary. The selector is that specific for this very reason + } -// Collecting button styles -.event-rule-button() { - color: @icinga-blue; - background: @low-sat-blue; + & + .add-escalation-form { + display: inline-block; - border: none; - text-align: center; - line-height: 1.5; - display: block; + .vertical-line(); - &:hover, - &:focus { - color: @icinga-blue; + .add-button { + margin-top: 2em; + } + } } - &:hover { - background: @low-sat-blue-dark; - } + // Style - &:focus { - outline: 3px solid fade(@icinga-blue, 50%); - outline-offset: 1px; + .right-arrow, + .horizontal-line { + background-color: @connectorColor; } -} -.escalation-form { - display: flex; - flex-direction: column; + .search-controls, + .option-wrapper { + padding: .5em; + border: 1px solid @connectorColor; + .rounded-corners(); + } - .options +.add-button, + .add-button, .remove-button { .event-rule-button(); } - .options + .add-button { - margin-right: 3.5em; - } + .add-filter-form .add-button, + .escalation-form :not(.options) + .add-button { + // (2em * 2) + 1.5 (icon height) = total height in em of a recipient escalation form with a single recipient + padding: ~"calc(2em + 1px) 4.125em"; // 1px is the border width of an escalation form - .options li { - input, select { - &:last-child:not(.remove-button) { - margin-right: 3.5em; - } + .icon::before { + font-size: 2em; } } -} -.add-filter-form, -.escalation-form.count-zero-escalation-condition-form { - button[type="submit"] { - font-size: 2em; - height: 2.25em; - margin: 0; + .remove-escalation-form .remove-button[disabled] { + background: @connectorColor; + color: @disabled-gray; + cursor: not-allowed; + } - > .icon { - flex-wrap: wrap; - align-content: flex-start; + .escalation-form .options .option { + > :first-child { + .rounded-corners(.25em); + border-top-right-radius: 0; + border-bottom-right-radius: 0; } - .event-rule-button(); - } -} - -.remove-escalation-form button[type="submit"], -.add-escalation-form button[type="submit"] { - .event-rule-button(); -} + > :last-child { + .rounded-corners(.25em); + border-top-left-radius: 0; + border-bottom-left-radius: 0; + } -.right-arrow, -.horizontal-line { - display: inline-block; - background-color: @base-gray-lighter; - height: 0.5em; - text-align: end; -} + > :not(:last-child) { + margin-right: 1px; + } -.right-arrow { - width: 10em; - min-width: 2em; - margin-right: 0.4em; - position: relative; -} + > :not(:first-child):not(:last-child) { + .rounded-corners(0); + } + } -.horizontal-line { - width: 3em; - min-width: 1em; -} + &.invalid { + select, + input { + &:invalid { + background-color: @state-critical; + } + } + } -.right-arrow:after { - content: ''; - position: absolute; - border: 0.3em solid transparent; - border-left: 0.4em solid @base-gray-lighter; -} + .vertical-line() { + position: relative; -.vertical-line { - width: 0.7em; - background-color: @base-gray-lighter; -} + &::before { + position: absolute; + z-index: -1; + top: 0; + bottom: 0; -.remove-escalation-form { - width: fit-content; -} + @halfedConnectorHeight: @connectorHeight / 2; + left: ~"calc(50% - @{halfedConnectorHeight})"; + right: ~"calc(50% - @{halfedConnectorHeight})"; -#layout.minimal-layout form.icinga-form:not(.inline).remove-escalation-form:not(.inline), -#layout.twocols:not(.wide-layout) form.icinga-form.remove-escalation-form:not(.inline) { - width: fit-content; -} + content: ""; + width: @connectorHeight; -.add-escalation-form { - display: flex; - min-height: 6em; - align-items: center; - - &:before { - content: ""; - display: block; - position: absolute; - width: .5em; - background: @gray-lighter; - top: 0; - bottom: 50%; - left: calc(~"1.25em + 1px"); - z-index: -1; + background-color: @connectorColor; + } } } -#layout.minimal-layout form.icinga-form:not(.inline).count-zero-escalation-condition-form:not(.inline), -#layout.twocols:not(.wide-layout) form.icinga-form.escalation-condition-form.count-zero-escalation-condition-form:not(.inline) { - width: fit-content; -} +#layout.twocols:not(.wide-layout) { + .event-rule-detail { + .search-controls { + min-width: fit-content; -.add-filter-form { - text-align: center; - width: auto; - position: relative; - bottom: calc(~"-.5em - 1px"); -} + .filter-input { + display: none; + } + } -.add-filter-form:after { - content: 'Filter'; - display: block; - color: @text-color-light; -} + .add-filter-form .add-button, + .escalation-form :not(.options) + .add-button { + padding: .25em 1em; -.horizontal-line-long { - width: 14.5em; + .icon::before { + font-size: inherit; + } + } + + .add-filter-form .add-button { + margin-top: 2em; + } + } } -.new-event-rule { - margin-bottom: 1em; +// Other stuff + +.cache-notice { + margin: 1em; + padding: 1em; + background-color: @gray-lighter; + text-align: center; + .rounded-corners(); } .event-rule-and-save-forms { @@ -424,13 +301,3 @@ } } } - -.remove-escalation-form { - button[disabled] { - &:disabled { - background: @gray-light; - color: @disabled-gray; - cursor: not-allowed; - } - } -} diff --git a/public/css/mixins.less b/public/css/mixins.less index 8e5ad9345..4d8a27cd6 100644 --- a/public/css/mixins.less +++ b/public/css/mixins.less @@ -23,6 +23,7 @@ text-align: center; line-height: 1.5; display: block; + padding: .25em 1em; &:hover, &:focus { @@ -34,4 +35,8 @@ outline: 3px solid fade(@icinga-blue, 50%); outline-offset: 1px; } -} \ No newline at end of file + + .icon::before { + margin-right: 0; + } +}