mirror of
https://github.com/Icinga/icingaweb2-module-businessprocess.git
synced 2025-12-25 00:59:34 -05:00
Support custom ordering of nodes (#384)
resolves #252 closes #297 requires https://github.com/Icinga/ipl-web/pull/173
This commit is contained in:
commit
be1f56ba08
23 changed files with 586 additions and 487 deletions
|
|
@ -26,10 +26,13 @@ use Icinga\Web\Notification;
|
|||
use Icinga\Web\Url;
|
||||
use Icinga\Web\Widget\Tabextension\DashboardAction;
|
||||
use Icinga\Web\Widget\Tabextension\OutputFormat;
|
||||
use ipl\Html\Form;
|
||||
use ipl\Html\Html;
|
||||
use ipl\Html\HtmlElement;
|
||||
use ipl\Html\HtmlString;
|
||||
use ipl\Html\TemplateString;
|
||||
use ipl\Html\Text;
|
||||
use ipl\Web\Control\SortControl;
|
||||
use ipl\Web\Widget\Link;
|
||||
|
||||
class ProcessController extends Controller
|
||||
|
|
@ -117,7 +120,7 @@ class ProcessController extends Controller
|
|||
|
||||
$this->tabs()->extend(new OutputFormat());
|
||||
|
||||
$this->content()->add($this->showHints($bp));
|
||||
$this->content()->add($this->showHints($bp, $renderer));
|
||||
$this->content()->add($this->showWarnings($bp));
|
||||
$this->content()->add($this->showErrors($bp));
|
||||
$this->content()->add($renderer);
|
||||
|
|
@ -125,6 +128,50 @@ class ProcessController extends Controller
|
|||
$this->setDynamicAutorefresh();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a sort control and apply its sort specification to the given renderer
|
||||
*
|
||||
* @param Renderer $renderer
|
||||
* @param BpConfig $config
|
||||
*
|
||||
* @return SortControl
|
||||
*/
|
||||
protected function createBpSortControl(Renderer $renderer, BpConfig $config): SortControl
|
||||
{
|
||||
$defaultSort = $this->session()->get('sort.default', $renderer->getDefaultSort());
|
||||
$options = [
|
||||
'display_name asc' => $this->translate('Name'),
|
||||
'state desc' => $this->translate('State')
|
||||
];
|
||||
if ($config->getMetadata()->isManuallyOrdered()) {
|
||||
$options['manual asc'] = $this->translate('Manual');
|
||||
} elseif ($defaultSort === 'manual desc') {
|
||||
$defaultSort = $renderer->getDefaultSort();
|
||||
}
|
||||
|
||||
$sortControl = SortControl::create($options)
|
||||
->setDefault($defaultSort)
|
||||
->setMethod('POST')
|
||||
->setAttribute('name', 'bp-sort-control')
|
||||
->on(Form::ON_SUCCESS, function (SortControl $sortControl) use ($renderer) {
|
||||
$sort = $sortControl->getSort();
|
||||
if ($sort === $renderer->getDefaultSort()) {
|
||||
$this->session()->delete('sort.default');
|
||||
$url = Url::fromRequest()->without($sortControl->getSortParam());
|
||||
} else {
|
||||
$this->session()->set('sort.default', $sort);
|
||||
$url = Url::fromRequest()->with($sortControl->getSortParam(), $sort);
|
||||
}
|
||||
|
||||
$this->redirectNow($url);
|
||||
})->handleRequest($this->getServerRequest());
|
||||
|
||||
$renderer->setSort($sortControl->getSort());
|
||||
$this->params->shift($sortControl->getSortParam());
|
||||
|
||||
return $sortControl;
|
||||
}
|
||||
|
||||
protected function prepareControls($bp, $renderer)
|
||||
{
|
||||
$controls = $this->controls();
|
||||
|
|
@ -153,6 +200,8 @@ class ProcessController extends Controller
|
|||
new RenderedProcessActionBar($bp, $renderer, $this->Auth(), $this->url())
|
||||
);
|
||||
}
|
||||
|
||||
$controls->addHtml($this->createBpSortControl($renderer, $bp));
|
||||
}
|
||||
|
||||
protected function getNode(BpConfig $bp)
|
||||
|
|
@ -263,7 +312,21 @@ class ProcessController extends Controller
|
|||
->setSimulation(Simulation::fromSession($this->session()))
|
||||
->handleRequest();
|
||||
} elseif ($action === 'move') {
|
||||
$successUrl = $this->url()->without(['action', 'movenode']);
|
||||
if ($this->params->get('mode') === 'tree') {
|
||||
// If the user moves a node from a subtree, the `node` param exists
|
||||
$successUrl->getParams()->remove('node');
|
||||
}
|
||||
|
||||
if ($this->session()->get('sort.default')) {
|
||||
// If there's a default sort specification in the session, it can only be `display_name desc`,
|
||||
// as otherwise the user wouldn't be able to trigger this action. So it's safe to just define
|
||||
// descending manual order now.
|
||||
$successUrl->getParams()->add(SortControl::DEFAULT_SORT_PARAM, 'manual desc');
|
||||
}
|
||||
|
||||
$form = $this->loadForm('MoveNode')
|
||||
->setSuccessUrl($successUrl)
|
||||
->setProcess($bp)
|
||||
->setParentNode($node)
|
||||
->setSession($this->session())
|
||||
|
|
@ -321,7 +384,7 @@ class ProcessController extends Controller
|
|||
}
|
||||
}
|
||||
|
||||
protected function showHints(BpConfig $bp)
|
||||
protected function showHints(BpConfig $bp, Renderer $renderer)
|
||||
{
|
||||
$ul = Html::tag('ul', ['class' => 'error']);
|
||||
$this->prepareMissingNodeLinks($ul);
|
||||
|
|
@ -362,6 +425,20 @@ class ProcessController extends Controller
|
|||
$ul->add($li);
|
||||
}
|
||||
|
||||
if (! $renderer->isLocked() && $renderer->appliesCustomSorting()) {
|
||||
$ul->addHtml(Html::tag('li', null, [
|
||||
Text::create($this->translate('Drag&Drop disabled. Custom sort order applied.')),
|
||||
(new Form())
|
||||
->setAttribute('class', 'inline')
|
||||
->addElement('submitButton', SortControl::DEFAULT_SORT_PARAM, [
|
||||
'label' => $this->translate('Reset to default'),
|
||||
'value' => $renderer->getDefaultSort(),
|
||||
'class' => 'link-button'
|
||||
])
|
||||
->addElement('hidden', 'uid', ['value' => 'bp-sort-control'])
|
||||
])->setSeparator(' '));
|
||||
}
|
||||
|
||||
if (! $ul->isEmpty()) {
|
||||
return $ul;
|
||||
} else {
|
||||
|
|
@ -510,7 +587,7 @@ class ProcessController extends Controller
|
|||
->setParams($this->getRequest()->getUrl()->getParams());
|
||||
$this->content()->add(
|
||||
$this->loadForm('bpConfig')
|
||||
->setProcessConfig($bp)
|
||||
->setProcess($bp)
|
||||
->setStorage($this->storage())
|
||||
->setSuccessUrl($url)
|
||||
->handleRequest()
|
||||
|
|
@ -647,7 +724,7 @@ class ProcessController extends Controller
|
|||
if (isset($node['since'])) {
|
||||
$data[] = DateFormatter::formatDateTime($node['since']);
|
||||
}
|
||||
|
||||
|
||||
if (isset($node['in_downtime'])) {
|
||||
$data[] = $node['in_downtime'];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,30 +4,18 @@ namespace Icinga\Module\Businessprocess\Forms;
|
|||
|
||||
use Exception;
|
||||
use Icinga\Module\Businessprocess\BpNode;
|
||||
use Icinga\Module\Businessprocess\BpConfig;
|
||||
use Icinga\Module\Businessprocess\Common\EnumList;
|
||||
use Icinga\Module\Businessprocess\Common\Sort;
|
||||
use Icinga\Module\Businessprocess\ImportedNode;
|
||||
use Icinga\Module\Businessprocess\Modification\ProcessChanges;
|
||||
use Icinga\Module\Businessprocess\Node;
|
||||
use Icinga\Module\Businessprocess\Storage\Storage;
|
||||
use Icinga\Module\Businessprocess\Web\Form\QuickForm;
|
||||
use Icinga\Module\Businessprocess\Web\Form\BpConfigBaseForm;
|
||||
use Icinga\Module\Businessprocess\Web\Form\Validator\NoDuplicateChildrenValidator;
|
||||
use Icinga\Module\Monitoring\Backend\MonitoringBackend;
|
||||
use Icinga\Web\Session\SessionNamespace;
|
||||
use ipl\Sql\Connection as IcingaDbConnection;
|
||||
|
||||
class AddNodeForm extends QuickForm
|
||||
class AddNodeForm extends BpConfigBaseForm
|
||||
{
|
||||
use EnumList;
|
||||
|
||||
/** @var MonitoringBackend|IcingaDbConnection*/
|
||||
protected $backend;
|
||||
|
||||
/** @var Storage */
|
||||
protected $storage;
|
||||
|
||||
/** @var BpConfig */
|
||||
protected $bp;
|
||||
use Sort;
|
||||
|
||||
/** @var BpNode */
|
||||
protected $parent;
|
||||
|
|
@ -36,9 +24,6 @@ class AddNodeForm extends QuickForm
|
|||
|
||||
protected $processList = array();
|
||||
|
||||
/** @var SessionNamespace */
|
||||
protected $session;
|
||||
|
||||
public function setup()
|
||||
{
|
||||
$view = $this->getView();
|
||||
|
|
@ -119,8 +104,8 @@ class AddNodeForm extends QuickForm
|
|||
));
|
||||
|
||||
$display = 1;
|
||||
if ($this->bp->getMetadata()->isManuallyOrdered() && !$this->bp->isEmpty()) {
|
||||
$rootNodes = $this->bp->getRootNodes();
|
||||
if ($this->bp->getMetadata()->isManuallyOrdered() && ! $this->bp->isEmpty()) {
|
||||
$rootNodes = self::applyManualSorting($this->bp->getRootNodes());
|
||||
$display = end($rootNodes)->getDisplay() + 1;
|
||||
}
|
||||
$this->addElement('select', 'display', array(
|
||||
|
|
@ -389,37 +374,6 @@ class AddNodeForm extends QuickForm
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param MonitoringBackend|IcingaDbConnection $backend
|
||||
* @return $this
|
||||
*/
|
||||
public function setBackend($backend)
|
||||
{
|
||||
$this->backend = $backend;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Storage $storage
|
||||
* @return $this
|
||||
*/
|
||||
public function setStorage(Storage $storage)
|
||||
{
|
||||
$this->storage = $storage;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param BpConfig $process
|
||||
* @return $this
|
||||
*/
|
||||
public function setProcess(BpConfig $process)
|
||||
{
|
||||
$this->bp = $process;
|
||||
$this->setBackend($process->getBackend());
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param BpNode|null $node
|
||||
* @return $this
|
||||
|
|
@ -438,16 +392,6 @@ class AddNodeForm extends QuickForm
|
|||
return $this->parent !== null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param SessionNamespace $session
|
||||
* @return $this
|
||||
*/
|
||||
public function setSession(SessionNamespace $session)
|
||||
{
|
||||
$this->session = $session;
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function hasProcesses()
|
||||
{
|
||||
return count($this->enumProcesses()) > 0;
|
||||
|
|
@ -492,9 +436,6 @@ class AddNodeForm extends QuickForm
|
|||
}
|
||||
}
|
||||
|
||||
if (! $this->bp->getMetadata()->isManuallyOrdered()) {
|
||||
natcasesort($list);
|
||||
}
|
||||
return $list;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -116,12 +116,12 @@ class BpConfigForm extends BpConfigBaseForm
|
|||
),
|
||||
));
|
||||
|
||||
if ($this->config === null) {
|
||||
if ($this->bp === null) {
|
||||
$this->setSubmitLabel(
|
||||
$this->translate('Add')
|
||||
);
|
||||
} else {
|
||||
$config = $this->config;
|
||||
$config = $this->bp;
|
||||
|
||||
$meta = $config->getMetadata();
|
||||
foreach ($meta->getProperties() as $k => $v) {
|
||||
|
|
@ -156,13 +156,13 @@ class BpConfigForm extends BpConfigBaseForm
|
|||
$name = $this->getValue('name');
|
||||
|
||||
if ($this->shouldBeDeleted()) {
|
||||
if ($this->config->isReferenced()) {
|
||||
if ($this->bp->isReferenced()) {
|
||||
$this->addError(sprintf(
|
||||
$this->translate('Process "%s" cannot be deleted as it has been referenced in other processes'),
|
||||
$name
|
||||
));
|
||||
} else {
|
||||
$this->config->clearAppliedChanges();
|
||||
$this->bp->clearAppliedChanges();
|
||||
$this->storage->deleteProcess($name);
|
||||
$this->setSuccessUrl('businessprocess');
|
||||
$this->redirectOnSuccess(sprintf('Process %s has been deleted', $name));
|
||||
|
|
@ -174,7 +174,7 @@ class BpConfigForm extends BpConfigBaseForm
|
|||
{
|
||||
$name = $this->getValue('name');
|
||||
|
||||
if ($this->config === null) {
|
||||
if ($this->bp === null) {
|
||||
if ($this->storage->hasProcess($name)) {
|
||||
$this->addError(sprintf(
|
||||
$this->translate('A process named "%s" already exists'),
|
||||
|
|
@ -199,7 +199,7 @@ class BpConfigForm extends BpConfigBaseForm
|
|||
);
|
||||
$this->setSuccessMessage(sprintf('Process %s has been created', $name));
|
||||
} else {
|
||||
$config = $this->config;
|
||||
$config = $this->bp;
|
||||
$this->setSuccessMessage(sprintf('Process %s has been stored', $name));
|
||||
}
|
||||
$meta = $config->getMetadata();
|
||||
|
|
|
|||
|
|
@ -10,8 +10,6 @@ use Icinga\Web\Notification;
|
|||
|
||||
class BpUploadForm extends BpConfigBaseForm
|
||||
{
|
||||
protected $backend;
|
||||
|
||||
protected $node;
|
||||
|
||||
protected $objectList = array();
|
||||
|
|
|
|||
|
|
@ -3,31 +3,18 @@
|
|||
namespace Icinga\Module\Businessprocess\Forms;
|
||||
|
||||
use Icinga\Module\Businessprocess\BpNode;
|
||||
use Icinga\Module\Businessprocess\BpConfig;
|
||||
use Icinga\Module\Businessprocess\Modification\ProcessChanges;
|
||||
use Icinga\Module\Businessprocess\Node;
|
||||
use Icinga\Module\Businessprocess\Web\Form\QuickForm;
|
||||
use Icinga\Module\Monitoring\Backend\MonitoringBackend;
|
||||
use Icinga\Web\Session\SessionNamespace;
|
||||
use ipl\Sql\Connection as IcingaDbConnection;
|
||||
use Icinga\Module\Businessprocess\Web\Form\BpConfigBaseForm;
|
||||
|
||||
class DeleteNodeForm extends QuickForm
|
||||
class DeleteNodeForm extends BpConfigBaseForm
|
||||
{
|
||||
/** @var MonitoringBackend|IcingaDbConnection */
|
||||
protected $backend;
|
||||
|
||||
/** @var BpConfig */
|
||||
protected $bp;
|
||||
|
||||
/** @var Node */
|
||||
protected $node;
|
||||
|
||||
/** @var BpNode */
|
||||
protected $parentNode;
|
||||
|
||||
/** @var SessionNamespace */
|
||||
protected $session;
|
||||
|
||||
public function setup()
|
||||
{
|
||||
$node = $this->node;
|
||||
|
|
@ -80,27 +67,6 @@ class DeleteNodeForm extends QuickForm
|
|||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param MonitoringBackend|IcingaDbConnection $backend
|
||||
* @return $this
|
||||
*/
|
||||
public function setBackend($backend)
|
||||
{
|
||||
$this->backend = $backend;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param BpConfig $process
|
||||
* @return $this
|
||||
*/
|
||||
public function setProcess(BpConfig $process)
|
||||
{
|
||||
$this->bp = $process;
|
||||
$this->setBackend($process->getBackend());
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Node $node
|
||||
* @return $this
|
||||
|
|
@ -121,16 +87,6 @@ class DeleteNodeForm extends QuickForm
|
|||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param SessionNamespace $session
|
||||
* @return $this
|
||||
*/
|
||||
public function setSession(SessionNamespace $session)
|
||||
{
|
||||
$this->session = $session;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function onSuccess()
|
||||
{
|
||||
$changes = ProcessChanges::construct($this->bp, $this->session);
|
||||
|
|
|
|||
|
|
@ -3,26 +3,16 @@
|
|||
namespace Icinga\Module\Businessprocess\Forms;
|
||||
|
||||
use Icinga\Module\Businessprocess\BpNode;
|
||||
use Icinga\Module\Businessprocess\BpConfig;
|
||||
use Icinga\Module\Businessprocess\Common\EnumList;
|
||||
use Icinga\Module\Businessprocess\Modification\ProcessChanges;
|
||||
use Icinga\Module\Businessprocess\Node;
|
||||
use Icinga\Module\Businessprocess\Web\Form\QuickForm;
|
||||
use Icinga\Module\Businessprocess\Web\Form\BpConfigBaseForm;
|
||||
use Icinga\Module\Businessprocess\Web\Form\Validator\NoDuplicateChildrenValidator;
|
||||
use Icinga\Module\Monitoring\Backend\MonitoringBackend;
|
||||
use Icinga\Web\Session\SessionNamespace;
|
||||
use ipl\Sql\Connection as IcingaDbConnection;
|
||||
|
||||
class EditNodeForm extends QuickForm
|
||||
class EditNodeForm extends BpConfigBaseForm
|
||||
{
|
||||
use EnumList;
|
||||
|
||||
/** @var MonitoringBackend|IcingaDbConnection */
|
||||
protected $backend;
|
||||
|
||||
/** @var BpConfig */
|
||||
protected $bp;
|
||||
|
||||
/** @var Node */
|
||||
protected $node;
|
||||
|
||||
|
|
@ -37,9 +27,6 @@ class EditNodeForm extends QuickForm
|
|||
|
||||
protected $host;
|
||||
|
||||
/** @var SessionNamespace */
|
||||
protected $session;
|
||||
|
||||
public function setup()
|
||||
{
|
||||
$this->host = substr($this->getNode()->getName(), 0, strpos($this->getNode()->getName(), ';'));
|
||||
|
|
@ -283,27 +270,6 @@ class EditNodeForm extends QuickForm
|
|||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param MonitoringBackend|IcingaDbConnection $backend
|
||||
* @return $this
|
||||
*/
|
||||
public function setBackend($backend)
|
||||
{
|
||||
$this->backend = $backend;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param BpConfig $process
|
||||
* @return $this
|
||||
*/
|
||||
public function setProcess(BpConfig $process)
|
||||
{
|
||||
$this->bp = $process;
|
||||
$this->setBackend($process->getBackend());
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param BpNode|null $node
|
||||
* @return $this
|
||||
|
|
@ -322,16 +288,6 @@ class EditNodeForm extends QuickForm
|
|||
return $this->parent !== null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param SessionNamespace $session
|
||||
* @return $this
|
||||
*/
|
||||
public function setSession(SessionNamespace $session)
|
||||
{
|
||||
$this->session = $session;
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function hasProcesses()
|
||||
{
|
||||
return count($this->enumProcesses()) > 0;
|
||||
|
|
@ -354,9 +310,6 @@ class EditNodeForm extends QuickForm
|
|||
}
|
||||
}
|
||||
|
||||
if (! $this->bp->getMetadata()->isManuallyOrdered()) {
|
||||
natcasesort($list);
|
||||
}
|
||||
return $list;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -171,7 +171,11 @@ class MoveNodeForm extends QuickForm
|
|||
$this->notifySuccess($this->getSuccessMessage($this->translate('Node order updated')));
|
||||
|
||||
$response = $this->getRequest()->getResponse()
|
||||
->setHeader('X-Icinga-Container', 'ignore');
|
||||
->setHeader('X-Icinga-Container', 'ignore')
|
||||
->setHeader('X-Icinga-Extra-Updates', implode(';', [
|
||||
$this->getRequest()->getHeader('X-Icinga-Container'),
|
||||
$this->getSuccessUrl()->getAbsoluteUrl()
|
||||
]));
|
||||
|
||||
Session::getSession()->write();
|
||||
$response->sendResponse();
|
||||
|
|
|
|||
|
|
@ -3,29 +3,16 @@
|
|||
namespace Icinga\Module\Businessprocess\Forms;
|
||||
|
||||
use Icinga\Module\Businessprocess\BpNode;
|
||||
use Icinga\Module\Businessprocess\BpConfig;
|
||||
use Icinga\Module\Businessprocess\Modification\ProcessChanges;
|
||||
use Icinga\Module\Businessprocess\Node;
|
||||
use Icinga\Module\Businessprocess\Web\Form\QuickForm;
|
||||
use Icinga\Module\Monitoring\Backend\MonitoringBackend;
|
||||
use Icinga\Module\Businessprocess\Web\Form\BpConfigBaseForm;
|
||||
use Icinga\Web\Notification;
|
||||
use Icinga\Web\Session\SessionNamespace;
|
||||
use ipl\Sql\Connection as IcingaDbConnection;
|
||||
|
||||
class ProcessForm extends QuickForm
|
||||
class ProcessForm extends BpConfigBaseForm
|
||||
{
|
||||
/** @var MonitoringBackend|IcingaDbConnection */
|
||||
protected $backend;
|
||||
|
||||
/** @var BpConfig */
|
||||
protected $bp;
|
||||
|
||||
/** @var BpNode */
|
||||
protected $node;
|
||||
|
||||
/** @var SessionNamespace */
|
||||
protected $session;
|
||||
|
||||
public function setup()
|
||||
{
|
||||
if ($this->node !== null) {
|
||||
|
|
@ -94,27 +81,6 @@ class ProcessForm extends QuickForm
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param MonitoringBackend|IcingaDbConnection $backend
|
||||
* @return $this
|
||||
*/
|
||||
public function setBackend($backend)
|
||||
{
|
||||
$this->backend = $backend;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param BpConfig $process
|
||||
* @return $this
|
||||
*/
|
||||
public function setProcess(BpConfig $process)
|
||||
{
|
||||
$this->bp = $process;
|
||||
$this->setBackend($process->getBackend());
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param BpNode $node
|
||||
* @return $this
|
||||
|
|
@ -125,16 +91,6 @@ class ProcessForm extends QuickForm
|
|||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param SessionNamespace $session
|
||||
* @return $this
|
||||
*/
|
||||
public function setSession(SessionNamespace $session)
|
||||
{
|
||||
$this->session = $session;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function onSuccess()
|
||||
{
|
||||
$changes = ProcessChanges::construct($this->bp, $this->session);
|
||||
|
|
|
|||
|
|
@ -4,9 +4,9 @@ namespace Icinga\Module\Businessprocess\Forms;
|
|||
|
||||
use Icinga\Module\Businessprocess\MonitoredNode;
|
||||
use Icinga\Module\Businessprocess\Simulation;
|
||||
use Icinga\Module\Businessprocess\Web\Form\QuickForm;
|
||||
use Icinga\Module\Businessprocess\Web\Form\BpConfigBaseForm;
|
||||
|
||||
class SimulationForm extends QuickForm
|
||||
class SimulationForm extends BpConfigBaseForm
|
||||
{
|
||||
/** @var MonitoredNode */
|
||||
protected $node;
|
||||
|
|
|
|||
|
|
@ -432,33 +432,12 @@ class BpConfig
|
|||
*/
|
||||
public function getRootNodes()
|
||||
{
|
||||
if ($this->getMetadata()->isManuallyOrdered()) {
|
||||
uasort($this->root_nodes, function (BpNode $a, BpNode $b) {
|
||||
$a = $a->getDisplay();
|
||||
$b = $b->getDisplay();
|
||||
return $a > $b ? 1 : ($a < $b ? -1 : 0);
|
||||
});
|
||||
} else {
|
||||
ksort($this->root_nodes, SORT_NATURAL | SORT_FLAG_CASE);
|
||||
}
|
||||
|
||||
return $this->root_nodes;
|
||||
}
|
||||
|
||||
public function listRootNodes()
|
||||
{
|
||||
$names = array_keys($this->root_nodes);
|
||||
if ($this->getMetadata()->isManuallyOrdered()) {
|
||||
uasort($names, function ($a, $b) {
|
||||
$a = $this->root_nodes[$a]->getDisplay();
|
||||
$b = $this->root_nodes[$b]->getDisplay();
|
||||
return $a > $b ? 1 : ($a < $b ? -1 : 0);
|
||||
});
|
||||
} else {
|
||||
natcasesort($names);
|
||||
}
|
||||
|
||||
return $names;
|
||||
return array_keys($this->root_nodes);
|
||||
}
|
||||
|
||||
public function getNodes()
|
||||
|
|
@ -826,16 +805,6 @@ class BpConfig
|
|||
$nodes[$name] = $name === $alias ? $name : sprintf('%s (%s)', $alias, $node);
|
||||
}
|
||||
|
||||
if ($this->getMetadata()->isManuallyOrdered()) {
|
||||
uasort($nodes, function ($a, $b) {
|
||||
$a = $this->nodes[$a]->getDisplay();
|
||||
$b = $this->nodes[$b]->getDisplay();
|
||||
return $a > $b ? 1 : ($a < $b ? -1 : 0);
|
||||
});
|
||||
} else {
|
||||
natcasesort($nodes);
|
||||
}
|
||||
|
||||
return $nodes;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -135,7 +135,6 @@ class BpNode extends Node
|
|||
|
||||
$this->children[$name] = $node;
|
||||
$this->childNames[] = $name;
|
||||
$this->reorderChildren();
|
||||
$node->addParent($this);
|
||||
return $this;
|
||||
}
|
||||
|
|
@ -549,7 +548,6 @@ class BpNode extends Node
|
|||
{
|
||||
$this->childNames = $names;
|
||||
$this->children = null;
|
||||
$this->reorderChildren();
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
|
@ -568,7 +566,6 @@ class BpNode extends Node
|
|||
{
|
||||
if ($this->children === null) {
|
||||
$this->children = [];
|
||||
$this->reorderChildren();
|
||||
foreach ($this->getChildNames() as $name) {
|
||||
$this->children[$name] = $this->getBpConfig()->getNode($name);
|
||||
$this->children[$name]->addParent($this);
|
||||
|
|
@ -578,29 +575,6 @@ class BpNode extends Node
|
|||
return $this->children;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reorder this node's children, in case manual order is not applied
|
||||
*/
|
||||
protected function reorderChildren()
|
||||
{
|
||||
if ($this->getBpConfig()->getMetadata()->isManuallyOrdered()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$childNames = $this->getChildNames();
|
||||
natcasesort($childNames);
|
||||
$this->childNames = array_values($childNames);
|
||||
|
||||
if (! empty($this->children)) {
|
||||
$children = [];
|
||||
foreach ($this->childNames as $name) {
|
||||
$children[$name] = $this->children[$name];
|
||||
}
|
||||
|
||||
$this->children = $children;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* return BpNode[]
|
||||
*/
|
||||
|
|
|
|||
154
library/Businessprocess/Common/Sort.php
Normal file
154
library/Businessprocess/Common/Sort.php
Normal file
|
|
@ -0,0 +1,154 @@
|
|||
<?php
|
||||
// Icinga Business Process Modelling | (c) 2023 Icinga GmbH | GPLv2
|
||||
|
||||
namespace Icinga\Module\Businessprocess\Common;
|
||||
|
||||
use Icinga\Module\Businessprocess\BpNode;
|
||||
use Icinga\Module\Businessprocess\Node;
|
||||
use InvalidArgumentException;
|
||||
use ipl\Stdlib\Str;
|
||||
|
||||
trait Sort
|
||||
{
|
||||
/** @var string Current sort specification */
|
||||
protected $sort;
|
||||
|
||||
/** @var callable Actual sorting function */
|
||||
protected $sortFn;
|
||||
|
||||
/**
|
||||
* Get the sort specification
|
||||
*
|
||||
* @return ?string
|
||||
*/
|
||||
public function getSort(): ?string
|
||||
{
|
||||
return $this->sort;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the sort specification
|
||||
*
|
||||
* @param string $sort
|
||||
*
|
||||
* @return $this
|
||||
*
|
||||
* @throws InvalidArgumentException When sorting according to the specified specification is not possible
|
||||
*/
|
||||
public function setSort(string $sort): self
|
||||
{
|
||||
list($sortBy, $direction) = Str::symmetricSplit($sort, ' ', 2, 'asc');
|
||||
|
||||
switch ($sortBy) {
|
||||
case 'manual':
|
||||
if ($direction === 'asc') {
|
||||
$this->sortFn = function (array &$nodes) {
|
||||
$firstNode = reset($nodes);
|
||||
if ($firstNode instanceof BpNode && $firstNode->getDisplay() > 0) {
|
||||
$nodes = self::applyManualSorting($nodes);
|
||||
}
|
||||
|
||||
// Child nodes don't need to be ordered in this case, their implicit order is significant
|
||||
};
|
||||
} else {
|
||||
$this->sortFn = function (array &$nodes) {
|
||||
$firstNode = reset($nodes);
|
||||
if ($firstNode instanceof BpNode && $firstNode->getDisplay() > 0) {
|
||||
uasort($nodes, function (BpNode $a, BpNode $b) {
|
||||
return $b->getDisplay() <=> $a->getDisplay();
|
||||
});
|
||||
} else {
|
||||
$nodes = array_reverse($nodes);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
break;
|
||||
case 'display_name':
|
||||
if ($direction === 'asc') {
|
||||
$this->sortFn = function (array &$nodes) {
|
||||
uasort($nodes, function (Node $a, Node $b) {
|
||||
return strnatcasecmp(
|
||||
$a->getAlias() ?? $a->getName(),
|
||||
$b->getAlias() ?? $b->getName()
|
||||
);
|
||||
});
|
||||
};
|
||||
} else {
|
||||
$this->sortFn = function (array &$nodes) {
|
||||
uasort($nodes, function (Node $a, Node $b) {
|
||||
return strnatcasecmp(
|
||||
$b->getAlias() ?? $b->getName(),
|
||||
$a->getAlias() ?? $a->getName()
|
||||
);
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
break;
|
||||
case 'state':
|
||||
if ($direction === 'asc') {
|
||||
$this->sortFn = function (array &$nodes) {
|
||||
uasort($nodes, function (Node $a, Node $b) {
|
||||
return $a->getSortingState() <=> $b->getSortingState();
|
||||
});
|
||||
};
|
||||
} else {
|
||||
$this->sortFn = function (array &$nodes) {
|
||||
uasort($nodes, function (Node $a, Node $b) {
|
||||
return $b->getSortingState() <=> $a->getSortingState();
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
throw new InvalidArgumentException(sprintf(
|
||||
"Can't sort by %s. It's only possible to sort by manual order, display_name or state",
|
||||
$sortBy
|
||||
));
|
||||
}
|
||||
|
||||
$this->sort = $sort;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort the given nodes as specified by {@see setSort()}
|
||||
*
|
||||
* If {@see setSort()} has not been called yet, the default sort specification is used
|
||||
*
|
||||
* @param array $nodes
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function sort(array $nodes): array
|
||||
{
|
||||
if (empty($nodes)) {
|
||||
return $nodes;
|
||||
}
|
||||
|
||||
if ($this->sortFn !== null) {
|
||||
call_user_func_array($this->sortFn, [&$nodes]);
|
||||
}
|
||||
|
||||
return $nodes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply manual sort order on the given process nodes
|
||||
*
|
||||
* @param array $bpNodes
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function applyManualSorting(array $bpNodes): array
|
||||
{
|
||||
uasort($bpNodes, function (BpNode $a, BpNode $b) {
|
||||
return $a->getDisplay() <=> $b->getDisplay();
|
||||
});
|
||||
|
||||
return $bpNodes;
|
||||
}
|
||||
}
|
||||
|
|
@ -3,9 +3,12 @@
|
|||
namespace Icinga\Module\Businessprocess\Modification;
|
||||
|
||||
use Icinga\Module\Businessprocess\BpConfig;
|
||||
use Icinga\Module\Businessprocess\Common\Sort;
|
||||
|
||||
class NodeApplyManualOrderAction extends NodeAction
|
||||
{
|
||||
use Sort;
|
||||
|
||||
public function appliesTo(BpConfig $config)
|
||||
{
|
||||
return $config->getMetadata()->get('ManualOrder') !== 'yes';
|
||||
|
|
@ -20,7 +23,10 @@ class NodeApplyManualOrderAction extends NodeAction
|
|||
}
|
||||
|
||||
if ($node->hasChildren()) {
|
||||
$node->setChildNames($node->getChildNames());
|
||||
$node->setChildNames(array_keys(
|
||||
$this->setSort('display_name asc')
|
||||
->sort($node->getChildren())
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,9 +3,12 @@
|
|||
namespace Icinga\Module\Businessprocess\Modification;
|
||||
|
||||
use Icinga\Module\Businessprocess\BpConfig;
|
||||
use Icinga\Module\Businessprocess\Common\Sort;
|
||||
|
||||
class NodeCopyAction extends NodeAction
|
||||
{
|
||||
use Sort;
|
||||
|
||||
/**
|
||||
* @param BpConfig $config
|
||||
* @return bool
|
||||
|
|
@ -31,9 +34,15 @@ class NodeCopyAction extends NodeAction
|
|||
public function applyTo(BpConfig $config)
|
||||
{
|
||||
$name = $this->getNodeName();
|
||||
$rootNodes = $config->getRootNodes();
|
||||
|
||||
$display = 1;
|
||||
if ($config->getMetadata()->isManuallyOrdered()) {
|
||||
$rootNodes = self::applyManualSorting($config->getRootNodes());
|
||||
$display = end($rootNodes)->getDisplay() + 1;
|
||||
}
|
||||
|
||||
$config->addRootNode($name)
|
||||
->getBpNode($name)
|
||||
->setDisplay(end($rootNodes)->getDisplay() + 1);
|
||||
->setDisplay($display);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,9 +4,12 @@ namespace Icinga\Module\Businessprocess\Modification;
|
|||
|
||||
use Icinga\Module\Businessprocess\BpConfig;
|
||||
use Icinga\Module\Businessprocess\BpNode;
|
||||
use Icinga\Module\Businessprocess\Common\Sort;
|
||||
|
||||
class NodeMoveAction extends NodeAction
|
||||
{
|
||||
use Sort;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
|
|
@ -87,16 +90,28 @@ class NodeMoveAction extends NodeAction
|
|||
|
||||
$nodes = $parent->getChildNames();
|
||||
if (! isset($nodes[$this->from]) || $nodes[$this->from] !== $name) {
|
||||
$this->error('Node "%s" not found at position %d', $name, $this->from);
|
||||
$reversedNodes = array_reverse($nodes); // The user may have reversed the sort direction
|
||||
if (! isset($reversedNodes[$this->from]) || $reversedNodes[$this->from] !== $name) {
|
||||
$this->error('Node "%s" not found at position %d', $name, $this->from);
|
||||
} else {
|
||||
$this->from = array_search($reversedNodes[$this->from], $nodes, true);
|
||||
$this->to = array_search($reversedNodes[$this->to], $nodes, true);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (! $config->hasRootNode($name)) {
|
||||
$this->error('Toplevel process "%s" not found', $name);
|
||||
}
|
||||
|
||||
$nodes = $config->listRootNodes();
|
||||
$nodes = array_keys(self::applyManualSorting($config->getRootNodes()));
|
||||
if (! isset($nodes[$this->from]) || $nodes[$this->from] !== $name) {
|
||||
$this->error('Toplevel process "%s" not found at position %d', $name, $this->from);
|
||||
$reversedNodes = array_reverse($nodes); // The user may have reversed the sort direction
|
||||
if (! isset($reversedNodes[$this->from]) || $reversedNodes[$this->from] !== $name) {
|
||||
$this->error('Toplevel process "%s" not found at position %d', $name, $this->from);
|
||||
} else {
|
||||
$this->from = array_search($reversedNodes[$this->from], $nodes, true);
|
||||
$this->to = array_search($reversedNodes[$this->to], $nodes, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -144,7 +159,7 @@ class NodeMoveAction extends NodeAction
|
|||
if ($this->parent !== null) {
|
||||
$nodes = $config->getBpNode($this->parent)->getChildren();
|
||||
} else {
|
||||
$nodes = $config->getRootNodes();
|
||||
$nodes = self::applyManualSorting($config->getRootNodes());
|
||||
}
|
||||
|
||||
$node = $nodes[$name];
|
||||
|
|
@ -162,7 +177,7 @@ class NodeMoveAction extends NodeAction
|
|||
if ($this->newParent !== null) {
|
||||
$newNodes = $config->getBpNode($this->newParent)->getChildren();
|
||||
} else {
|
||||
$newNodes = $config->getRootNodes();
|
||||
$newNodes = self::applyManualSorting($config->getRootNodes());
|
||||
}
|
||||
|
||||
$newNodes = array_merge(
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ namespace Icinga\Module\Businessprocess\Renderer;
|
|||
use Icinga\Exception\ProgrammingError;
|
||||
use Icinga\Module\Businessprocess\BpNode;
|
||||
use Icinga\Module\Businessprocess\BpConfig;
|
||||
use Icinga\Module\Businessprocess\Common\Sort;
|
||||
use Icinga\Module\Businessprocess\ImportedNode;
|
||||
use Icinga\Module\Businessprocess\MonitoredNode;
|
||||
use Icinga\Module\Businessprocess\Node;
|
||||
|
|
@ -12,10 +13,13 @@ use Icinga\Module\Businessprocess\Web\Url;
|
|||
use ipl\Html\BaseHtmlElement;
|
||||
use ipl\Html\Html;
|
||||
use ipl\Html\HtmlDocument;
|
||||
use ipl\Stdlib\Str;
|
||||
use ipl\Web\Widget\StateBadge;
|
||||
|
||||
abstract class Renderer extends HtmlDocument
|
||||
{
|
||||
use Sort;
|
||||
|
||||
/** @var BpConfig */
|
||||
protected $config;
|
||||
|
||||
|
|
@ -120,6 +124,33 @@ abstract class Renderer extends HtmlDocument
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the default sort specification
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getDefaultSort(): string
|
||||
{
|
||||
if ($this->config->getMetadata()->isManuallyOrdered()) {
|
||||
return 'manual asc';
|
||||
}
|
||||
|
||||
return 'display_name asc';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get whether a custom sort order is applied
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function appliesCustomSorting(): bool
|
||||
{
|
||||
list($sortBy, $_) = Str::symmetricSplit($this->getSort(), ' ', 2);
|
||||
list($defaultSortBy, $_) = Str::symmetricSplit($this->getDefaultSort(), ' ', 2);
|
||||
|
||||
return $sortBy !== $defaultSortBy;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -17,7 +17,9 @@ class TileRenderer extends Renderer
|
|||
[
|
||||
'class' => ['sortable', 'tiles', $this->howMany()],
|
||||
'data-base-target' => '_self',
|
||||
'data-sortable-disabled' => $this->isLocked() ? 'true' : 'false',
|
||||
'data-sortable-disabled' => $this->isLocked() || $this->appliesCustomSorting()
|
||||
? 'true'
|
||||
: 'false',
|
||||
'data-sortable-data-id-attr' => 'id',
|
||||
'data-sortable-direction' => 'horizontal', // Otherwise movement is buggy on small lists
|
||||
'data-csrf-token' => CsrfToken::generate()
|
||||
|
|
@ -43,10 +45,8 @@ class TileRenderer extends Renderer
|
|||
->getAbsoluteUrl());
|
||||
}
|
||||
|
||||
$nodes = $this->getChildNodes();
|
||||
|
||||
$path = $this->getCurrentPath();
|
||||
foreach ($nodes as $name => $node) {
|
||||
foreach ($this->sort($this->getChildNodes()) as $name => $node) {
|
||||
$this->add(new NodeTile($this, $node, $path));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -29,7 +29,9 @@ class TreeRenderer extends Renderer
|
|||
[
|
||||
'id' => $htmlId,
|
||||
'class' => ['bp', 'sortable', $this->wantsRootNodes() ? '' : 'process'],
|
||||
'data-sortable-disabled' => $this->isLocked() ? 'true' : 'false',
|
||||
'data-sortable-disabled' => $this->isLocked() || $this->appliesCustomSorting()
|
||||
? 'true'
|
||||
: 'false',
|
||||
'data-sortable-data-id-attr' => 'id',
|
||||
'data-sortable-direction' => 'vertical',
|
||||
'data-sortable-group' => json_encode([
|
||||
|
|
@ -69,18 +71,18 @@ class TreeRenderer extends Renderer
|
|||
|
||||
/**
|
||||
* @param BpConfig $bp
|
||||
* @return string
|
||||
* @return array
|
||||
*/
|
||||
public function renderBp(BpConfig $bp)
|
||||
{
|
||||
$html = array();
|
||||
$html = [];
|
||||
if ($this->wantsRootNodes()) {
|
||||
$nodes = $bp->getChildren();
|
||||
$nodes = $bp->getRootNodes();
|
||||
} else {
|
||||
$nodes = $this->parent->getChildren();
|
||||
}
|
||||
|
||||
foreach ($nodes as $name => $node) {
|
||||
foreach ($this->sort($nodes) as $name => $node) {
|
||||
if ($node instanceof BpNode) {
|
||||
$html[] = $this->renderNode($bp, $node);
|
||||
} else {
|
||||
|
|
@ -238,7 +240,9 @@ class TreeRenderer extends Renderer
|
|||
|
||||
$ul = Html::tag('ul', [
|
||||
'class' => ['bp', 'sortable'],
|
||||
'data-sortable-disabled' => ($this->isLocked() || $differentConfig) ? 'true' : 'false',
|
||||
'data-sortable-disabled' => ($this->isLocked() || $differentConfig || $this->appliesCustomSorting())
|
||||
? 'true'
|
||||
: 'false',
|
||||
'data-sortable-invert-swap' => 'true',
|
||||
'data-sortable-data-id-attr' => 'id',
|
||||
'data-sortable-draggable' => '.movable',
|
||||
|
|
@ -259,7 +263,7 @@ class TreeRenderer extends Renderer
|
|||
]);
|
||||
|
||||
$path[] = $differentConfig ? $node->getIdentifier() : $node->getName();
|
||||
foreach ($node->getChildren() as $name => $child) {
|
||||
foreach ($this->sort($node->getChildren()) as $name => $child) {
|
||||
if ($child instanceof BpNode) {
|
||||
$ul->add($this->renderNode($bp, $child, $path));
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -73,7 +73,6 @@ class LegacyStorage extends Storage
|
|||
$files[$name] = $meta->getExtendedTitle();
|
||||
}
|
||||
|
||||
natcasesort($files);
|
||||
return $files;
|
||||
}
|
||||
|
||||
|
|
@ -93,7 +92,6 @@ class LegacyStorage extends Storage
|
|||
$files[$name] = $name;
|
||||
}
|
||||
|
||||
natcasesort($files);
|
||||
return $files;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,12 +12,12 @@ use Icinga\Module\Businessprocess\Web\Component\Controls;
|
|||
use Icinga\Module\Businessprocess\Web\Component\Content;
|
||||
use Icinga\Module\Businessprocess\Web\Component\Tabs;
|
||||
use Icinga\Module\Businessprocess\Web\Form\FormLoader;
|
||||
use Icinga\Web\Controller as ModuleController;
|
||||
use Icinga\Web\Notification;
|
||||
use Icinga\Web\View;
|
||||
use ipl\Html\Html;
|
||||
use ipl\Web\Compat\CompatController;
|
||||
|
||||
class Controller extends ModuleController
|
||||
class Controller extends CompatController
|
||||
{
|
||||
/** @var View */
|
||||
public $view;
|
||||
|
|
@ -173,14 +173,6 @@ class Controller extends ModuleController
|
|||
return $this;
|
||||
}
|
||||
|
||||
protected function setTitle($title)
|
||||
{
|
||||
$args = func_get_args();
|
||||
array_shift($args);
|
||||
$this->view->title = vsprintf($title, $args);
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function addTitle($title)
|
||||
{
|
||||
$args = func_get_args();
|
||||
|
|
|
|||
|
|
@ -5,16 +5,25 @@ namespace Icinga\Module\Businessprocess\Web\Form;
|
|||
use Icinga\Application\Config;
|
||||
use Icinga\Application\Icinga;
|
||||
use Icinga\Authentication\Auth;
|
||||
use Icinga\Module\Businessprocess\Storage\LegacyStorage;
|
||||
use Icinga\Module\Businessprocess\BpConfig;
|
||||
use Icinga\Module\Businessprocess\Storage\Storage;
|
||||
use Icinga\Module\Monitoring\Backend\MonitoringBackend;
|
||||
use Icinga\Web\Session\SessionNamespace;
|
||||
use ipl\Sql\Connection as IcingaDbConnection;
|
||||
|
||||
abstract class BpConfigBaseForm extends QuickForm
|
||||
{
|
||||
/** @var LegacyStorage */
|
||||
/** @var Storage */
|
||||
protected $storage;
|
||||
|
||||
/** @var BpConfig */
|
||||
protected $config;
|
||||
protected $bp;
|
||||
|
||||
/** @var MonitoringBackend|IcingaDbConnection*/
|
||||
protected $backend;
|
||||
|
||||
/** @var SessionNamespace */
|
||||
protected $session;
|
||||
|
||||
protected function listAvailableBackends()
|
||||
{
|
||||
|
|
@ -28,15 +37,60 @@ abstract class BpConfigBaseForm extends QuickForm
|
|||
return $keys;
|
||||
}
|
||||
|
||||
public function setStorage(LegacyStorage $storage)
|
||||
/**
|
||||
* Set the storage to use
|
||||
*
|
||||
* @param Storage $storage
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setStorage(Storage $storage): self
|
||||
{
|
||||
$this->storage = $storage;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setProcessConfig(BpConfig $config)
|
||||
/**
|
||||
* Set the config to use
|
||||
*
|
||||
* @param BpConfig $config
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setProcess(BpConfig $config): self
|
||||
{
|
||||
$this->config = $config;
|
||||
$this->bp = $config;
|
||||
$this->setBackend($config->getBackend());
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the backend to use
|
||||
*
|
||||
* @param MonitoringBackend|IcingaDbConnection $backend
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setBackend($backend): self
|
||||
{
|
||||
$this->backend = $backend;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the session namespace to use
|
||||
*
|
||||
* @param SessionNamespace $session
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setSession(SessionNamespace $session): self
|
||||
{
|
||||
$this->session = $session;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
|
@ -69,4 +123,13 @@ abstract class BpConfigBaseForm extends QuickForm
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function setPreferredDecorators()
|
||||
{
|
||||
parent::setPreferredDecorators();
|
||||
|
||||
$this->setAttrib('class', $this->getAttrib('class') . ' bp-form');
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ a:focus {
|
|||
}
|
||||
|
||||
.action-bar {
|
||||
float: left;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 1.3em;
|
||||
|
|
@ -76,6 +77,10 @@ a:focus {
|
|||
}
|
||||
}
|
||||
|
||||
.controls .sort-control {
|
||||
float: right;
|
||||
}
|
||||
|
||||
form a {
|
||||
color: @icinga-blue;
|
||||
}
|
||||
|
|
@ -742,7 +747,8 @@ ul.error, ul.warning {
|
|||
padding: 0.3em 0.8em;
|
||||
}
|
||||
|
||||
li a {
|
||||
li a,
|
||||
li .link-button {
|
||||
color: inherit;
|
||||
text-decoration: underline;
|
||||
|
||||
|
|
@ -790,177 +796,178 @@ table.sourcecode {
|
|||
left: -100%;
|
||||
}
|
||||
|
||||
form input[type=file] {
|
||||
padding-right: 1em;
|
||||
}
|
||||
|
||||
form input[type=submit]:first-of-type {
|
||||
border-width: 2px;
|
||||
}
|
||||
|
||||
form p.description {
|
||||
padding: 1em 1em;
|
||||
margin: 0;
|
||||
font-style: italic;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
form ul.form-errors {
|
||||
margin-bottom: 0.5em;
|
||||
|
||||
ul.errors li {
|
||||
background: @color-critical;
|
||||
font-weight: bold;
|
||||
padding: 0.5em 1em;
|
||||
color: @text-color-on-icinga-blue;
|
||||
}
|
||||
}
|
||||
|
||||
input[type=text], input[type=password], input[type=file], textarea, select {
|
||||
max-width: 36em;
|
||||
min-width: 20em;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
label {
|
||||
line-height: 2em;
|
||||
}
|
||||
|
||||
form dl {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
select option {
|
||||
padding-left: 0.5em;
|
||||
}
|
||||
|
||||
form dt label {
|
||||
width: auto;
|
||||
font-weight: normal;
|
||||
font-size: inherit;
|
||||
|
||||
&.required {
|
||||
&::after {
|
||||
content: '*'
|
||||
}
|
||||
form.bp-form {
|
||||
input[type=file] {
|
||||
padding-right: 1em;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
cursor: pointer;
|
||||
input[type=submit]:first-of-type {
|
||||
border-width: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
#stateOverrides-element {
|
||||
display: inline-table;
|
||||
table-layout: fixed;
|
||||
border-spacing: .5em;
|
||||
padding: 0;
|
||||
|
||||
label {
|
||||
display: table-row;
|
||||
|
||||
span, select {
|
||||
display: table-cell;
|
||||
}
|
||||
|
||||
span {
|
||||
width: 10em;
|
||||
}
|
||||
|
||||
select {
|
||||
width: 26em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
form fieldset {
|
||||
min-width: 36em;
|
||||
}
|
||||
|
||||
form dd input.related-action[type='submit'] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
form dd.active li.active input.related-action[type='submit'] {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
form dd.active {
|
||||
p.description {
|
||||
color: inherit;
|
||||
font-style: normal;
|
||||
}
|
||||
}
|
||||
|
||||
form dd {
|
||||
padding: 0.3em 0.5em;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
form dt {
|
||||
padding: 0.5em 0.5em;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
form dt.active, form dd.active {
|
||||
background-color: @tr-active-color;
|
||||
}
|
||||
|
||||
form dt {
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
min-width: 12em;
|
||||
min-height: 2.5em;
|
||||
width: 30%;
|
||||
&.errors label {
|
||||
color: @color-critical;
|
||||
}
|
||||
}
|
||||
|
||||
form .errors label {
|
||||
color: @color-critical;
|
||||
}
|
||||
|
||||
form dd {
|
||||
display: inline-block;
|
||||
width: 63%;
|
||||
min-height: 2.5em;
|
||||
vertical-align: top;
|
||||
margin: 0;
|
||||
&.errors {
|
||||
input[type=text], select {
|
||||
border-color: @color-critical;
|
||||
}
|
||||
}
|
||||
|
||||
&.full-width {
|
||||
padding: 0.5em;
|
||||
padding: 1em 1em;
|
||||
margin: 0;
|
||||
font-style: italic;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
form dd:after {
|
||||
display: block;
|
||||
content: '';
|
||||
}
|
||||
ul.form-errors {
|
||||
margin-bottom: 0.5em;
|
||||
|
||||
form textarea {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
form dd ul.errors {
|
||||
list-style-type: none;
|
||||
padding-left: 0.3em;
|
||||
|
||||
li {
|
||||
color: @color-critical;
|
||||
padding: 0.3em;
|
||||
ul.errors li {
|
||||
background: @color-critical;
|
||||
font-weight: bold;
|
||||
padding: 0.5em 1em;
|
||||
color: @text-color-on-icinga-blue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
form {
|
||||
input[type=text], input[type=password], input[type=file], textarea, select {
|
||||
max-width: 36em;
|
||||
min-width: 20em;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
label {
|
||||
line-height: 2em;
|
||||
}
|
||||
|
||||
dl {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
select option {
|
||||
padding-left: 0.5em;
|
||||
}
|
||||
|
||||
dt label {
|
||||
width: auto;
|
||||
font-weight: normal;
|
||||
font-size: inherit;
|
||||
|
||||
&.required {
|
||||
&::after {
|
||||
content: '*'
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
#stateOverrides-element {
|
||||
display: inline-table;
|
||||
table-layout: fixed;
|
||||
border-spacing: .5em;
|
||||
padding: 0;
|
||||
|
||||
label {
|
||||
display: table-row;
|
||||
|
||||
span, select {
|
||||
display: table-cell;
|
||||
}
|
||||
|
||||
span {
|
||||
width: 10em;
|
||||
}
|
||||
|
||||
select {
|
||||
width: 26em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fieldset {
|
||||
min-width: 36em;
|
||||
}
|
||||
|
||||
dd input.related-action[type='submit'] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
dd.active li.active input.related-action[type='submit'] {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
dd.active {
|
||||
p.description {
|
||||
color: inherit;
|
||||
font-style: normal;
|
||||
}
|
||||
}
|
||||
|
||||
dd {
|
||||
padding: 0.3em 0.5em;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
dt {
|
||||
padding: 0.5em 0.5em;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
dt.active, dd.active {
|
||||
background-color: @tr-active-color;
|
||||
}
|
||||
|
||||
dt {
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
min-width: 12em;
|
||||
min-height: 2.5em;
|
||||
width: 30%;
|
||||
&.errors label {
|
||||
color: @color-critical;
|
||||
}
|
||||
}
|
||||
|
||||
.errors label {
|
||||
color: @color-critical;
|
||||
}
|
||||
|
||||
dd {
|
||||
display: inline-block;
|
||||
width: 63%;
|
||||
min-height: 2.5em;
|
||||
vertical-align: top;
|
||||
margin: 0;
|
||||
&.errors {
|
||||
input[type=text], select {
|
||||
border-color: @color-critical;
|
||||
}
|
||||
}
|
||||
|
||||
&.full-width {
|
||||
padding: 0.5em;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
dd:after {
|
||||
display: block;
|
||||
content: '';
|
||||
}
|
||||
|
||||
textarea {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
dd ul.errors {
|
||||
list-style-type: none;
|
||||
padding-left: 0.3em;
|
||||
|
||||
li {
|
||||
color: @color-critical;
|
||||
padding: 0.3em;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#_FAKE_SUBMIT {
|
||||
position: absolute;
|
||||
left: -100%;
|
||||
|
|
|
|||
|
|
@ -122,11 +122,7 @@
|
|||
].join('&');
|
||||
|
||||
var $container = $source.closest('.container');
|
||||
var req = icinga.loader.loadUrl(actionUrl, $container, data, 'POST');
|
||||
req.always(function() {
|
||||
icinga.loader.loadUrl(
|
||||
$container.data('icingaUrl'), $container, undefined, undefined, undefined, true);
|
||||
});
|
||||
icinga.loader.loadUrl(actionUrl, $container, data, 'POST');
|
||||
}
|
||||
},
|
||||
|
||||
|
|
@ -159,11 +155,7 @@
|
|||
].join('&');
|
||||
|
||||
var $container = $target.closest('.container');
|
||||
var req = icinga.loader.loadUrl(actionUrl, $container, data, 'POST');
|
||||
req.always(function() {
|
||||
icinga.loader.loadUrl(
|
||||
$container.data('icingaUrl'), $container, undefined, undefined, undefined, true);
|
||||
});
|
||||
icinga.loader.loadUrl(actionUrl, $container, data, 'POST');
|
||||
event.stopPropagation();
|
||||
}
|
||||
},
|
||||
|
|
|
|||
Loading…
Reference in a new issue