mirror of
https://github.com/Icinga/icingaweb2-module-businessprocess.git
synced 2025-12-18 23:16:16 -05:00
431 lines
9.6 KiB
PHP
431 lines
9.6 KiB
PHP
<?php
|
|
|
|
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;
|
|
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;
|
|
|
|
/** @var BpNode */
|
|
protected $parent;
|
|
|
|
/** @var bool Administrative actions are hidden unless unlocked */
|
|
protected $locked = true;
|
|
|
|
/** @var Url */
|
|
protected $url;
|
|
|
|
/** @var Url */
|
|
protected $baseUrl;
|
|
|
|
/** @var array */
|
|
protected $path = array();
|
|
|
|
/** @var bool */
|
|
protected $isBreadcrumb = false;
|
|
|
|
/**
|
|
* Renderer constructor.
|
|
*
|
|
* @param BpConfig $config
|
|
* @param BpNode|null $parent
|
|
*/
|
|
public function __construct(BpConfig $config, BpNode $parent = null)
|
|
{
|
|
$this->config = $config;
|
|
$this->parent = $parent;
|
|
}
|
|
|
|
/**
|
|
* @return BpConfig
|
|
*/
|
|
public function getBusinessProcess()
|
|
{
|
|
return $this->config;
|
|
}
|
|
|
|
/**
|
|
* Whether this will render all root nodes
|
|
*
|
|
* @return bool
|
|
*/
|
|
public function wantsRootNodes()
|
|
{
|
|
return $this->parent === null;
|
|
}
|
|
|
|
/**
|
|
* Whether this will only render parts of given config
|
|
*
|
|
* @return bool
|
|
*/
|
|
public function rendersSubNode()
|
|
{
|
|
return $this->parent !== null;
|
|
}
|
|
|
|
public function rendersImportedNode()
|
|
{
|
|
return $this->parent !== null && $this->parent->getBpConfig()->getName() !== $this->config->getName();
|
|
}
|
|
|
|
public function setParentNode(BpNode $node)
|
|
{
|
|
$this->parent = $node;
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* @return BpNode
|
|
*/
|
|
public function getParentNode()
|
|
{
|
|
return $this->parent;
|
|
}
|
|
|
|
/**
|
|
* @return BpNode[]
|
|
*/
|
|
public function getParentNodes()
|
|
{
|
|
if ($this->wantsRootNodes()) {
|
|
return array();
|
|
}
|
|
|
|
return $this->parent->getParents();
|
|
}
|
|
|
|
/**
|
|
* @return BpNode[]
|
|
*/
|
|
public function getChildNodes()
|
|
{
|
|
if ($this->wantsRootNodes()) {
|
|
return $this->config->getRootNodes();
|
|
} else {
|
|
return $this->parent->getChildren();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 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
|
|
{
|
|
if (empty($this->getSort())) {
|
|
return false;
|
|
}
|
|
|
|
list($sortBy, $_) = Str::symmetricSplit($this->getSort(), ' ', 2);
|
|
list($defaultSortBy, $_) = Str::symmetricSplit($this->getDefaultSort(), ' ', 2);
|
|
|
|
return $sortBy !== $defaultSortBy;
|
|
}
|
|
|
|
/**
|
|
* @return int
|
|
*/
|
|
public function countChildNodes()
|
|
{
|
|
if ($this->wantsRootNodes()) {
|
|
return $this->config->countChildren();
|
|
} else {
|
|
return $this->parent->countChildren();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param $summary
|
|
* @return ?BaseHtmlElement
|
|
*/
|
|
public function renderStateBadges($summary, $totalChildren)
|
|
{
|
|
$itemCount = Html::tag(
|
|
'span',
|
|
[
|
|
'class' => [
|
|
'item-count',
|
|
]
|
|
],
|
|
sprintf(mtp('businessprocess', '%u Child', '%u Children', $totalChildren), $totalChildren)
|
|
);
|
|
|
|
$elements = array_filter([
|
|
$this->createBadgeGroup($summary, 'CRITICAL'),
|
|
$this->createBadgeGroup($summary, 'UNKNOWN'),
|
|
$this->createBadgeGroup($summary, 'WARNING'),
|
|
$this->createBadge($summary, 'MISSING'),
|
|
$this->createBadge($summary, 'PENDING')
|
|
]);
|
|
|
|
if (! empty($elements)) {
|
|
$container = Html::tag('ul', ['class' => 'state-badges']);
|
|
$container->add($itemCount);
|
|
foreach ($elements as $element) {
|
|
$container->add($element);
|
|
}
|
|
|
|
return $container;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
protected function createBadge($summary, $state)
|
|
{
|
|
if ($summary[$state] !== 0) {
|
|
return Html::tag('li', new StateBadge($summary[$state], strtolower($state)));
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
protected function createBadgeGroup($summary, $state)
|
|
{
|
|
$content = [];
|
|
if ($summary[$state] !== 0) {
|
|
$content[] = Html::tag('li', new StateBadge($summary[$state], strtolower($state)));
|
|
}
|
|
|
|
if ($summary[$state . '-HANDLED'] !== 0) {
|
|
$content[] = Html::tag('li', new StateBadge($summary[$state . '-HANDLED'], strtolower($state), true));
|
|
}
|
|
|
|
if (empty($content)) {
|
|
return null;
|
|
}
|
|
|
|
return Html::tag('li', Html::tag('ul', $content));
|
|
}
|
|
|
|
public function getNodeClasses(Node $node)
|
|
{
|
|
if ($node->isMissing()) {
|
|
$classes = array('missing');
|
|
} else {
|
|
if ($node->isEmpty() && ! $node instanceof MonitoredNode) {
|
|
$classes = array('empty');
|
|
} else {
|
|
$classes = [strtolower($node->getStateName(
|
|
$this->parent !== null ? $this->parent->getChildState($node) : null
|
|
))];
|
|
}
|
|
if ($node->hasMissingChildren()) {
|
|
$classes[] = 'missing-children';
|
|
}
|
|
}
|
|
|
|
if ($node->isHandled()) {
|
|
$classes[] = 'handled';
|
|
}
|
|
|
|
if ($node instanceof BpNode) {
|
|
$classes[] = 'process-node';
|
|
} else {
|
|
$classes[] = 'monitored-node';
|
|
}
|
|
// TODO: problem?
|
|
return $classes;
|
|
}
|
|
|
|
/**
|
|
* Return the url to the given node's source configuration
|
|
*
|
|
* @param BpNode $node
|
|
*
|
|
* @return Url
|
|
*/
|
|
public function getSourceUrl(BpNode $node)
|
|
{
|
|
if ($node instanceof ImportedNode) {
|
|
$name = $node->getNodeName();
|
|
$paths = $node->getBpConfig()->getBpNode($name)->getPaths();
|
|
} else {
|
|
$name = $node->getName();
|
|
$paths = $node->getPaths();
|
|
}
|
|
|
|
$url = clone $this->getUrl();
|
|
$url->setParams([
|
|
'config' => $node->getBpConfig()->getName(),
|
|
'node' => $name
|
|
]);
|
|
// This depends on the fact that the node's root path is the last element in $paths
|
|
$url->getParams()->addValues('path', array_slice(array_pop($paths), 0, -1));
|
|
if (! $this->isLocked()) {
|
|
$url->getParams()->add('unlocked', true);
|
|
}
|
|
|
|
return $url;
|
|
}
|
|
|
|
/**
|
|
* @param Node $node
|
|
* @param $path
|
|
* @return string
|
|
*/
|
|
public function getId(Node $node, $path)
|
|
{
|
|
return 'businessprocess-' . md5((empty($path) ? '' : implode(';', $path)) . $node->getName());
|
|
}
|
|
|
|
public function setPath(array $path)
|
|
{
|
|
$this->path = $path;
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* @return array
|
|
*/
|
|
public function getPath()
|
|
{
|
|
return $this->path;
|
|
}
|
|
|
|
public function getCurrentPath()
|
|
{
|
|
$path = $this->getPath();
|
|
if ($this->rendersSubNode()) {
|
|
$path[] = $this->rendersImportedNode()
|
|
? $this->parent->getIdentifier()
|
|
: $this->parent->getName();
|
|
}
|
|
|
|
return $path;
|
|
}
|
|
|
|
/**
|
|
* @param Url $url
|
|
* @return $this
|
|
*/
|
|
public function setUrl(Url $url)
|
|
{
|
|
$this->url = $url->without(array(
|
|
'action',
|
|
'deletenode',
|
|
'deleteparent',
|
|
'editnode',
|
|
'simulationnode',
|
|
'view'
|
|
));
|
|
$this->setBaseUrl($this->url);
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* @param Url $url
|
|
* @return $this
|
|
*/
|
|
protected function setBaseUrl(Url $url)
|
|
{
|
|
$this->baseUrl = $url->without(array('node', 'path'));
|
|
return $this;
|
|
}
|
|
|
|
public function getUrl()
|
|
{
|
|
return $this->url;
|
|
}
|
|
|
|
/**
|
|
* @return Url
|
|
* @throws ProgrammingError
|
|
*/
|
|
public function getBaseUrl()
|
|
{
|
|
if ($this->baseUrl === null) {
|
|
throw new ProgrammingError('Renderer has no baseUrl');
|
|
}
|
|
|
|
return clone($this->baseUrl);
|
|
}
|
|
|
|
/**
|
|
* @return bool
|
|
*/
|
|
public function isLocked()
|
|
{
|
|
return $this->locked;
|
|
}
|
|
|
|
/**
|
|
* @return $this
|
|
*/
|
|
public function lock()
|
|
{
|
|
$this->locked = true;
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* @return $this
|
|
*/
|
|
public function unlock()
|
|
{
|
|
$this->locked = false;
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* TODO: Get rid of this
|
|
*
|
|
* @return $this
|
|
*/
|
|
public function setIsBreadcrumb()
|
|
{
|
|
$this->isBreadcrumb = true;
|
|
return $this;
|
|
}
|
|
|
|
public function isBreadcrumb()
|
|
{
|
|
return $this->isBreadcrumb;
|
|
}
|
|
|
|
protected function createUnboundParent(BpConfig $bp)
|
|
{
|
|
return $bp->getNode('__unbound__');
|
|
}
|
|
|
|
/**
|
|
* Just to be on the safe side
|
|
*/
|
|
public function __destruct()
|
|
{
|
|
unset($this->parent);
|
|
unset($this->config);
|
|
}
|
|
}
|