Utilize widgets moved to ipl-web

This commit is contained in:
Yonas Habteab 2023-08-09 14:25:44 +02:00 committed by Johannes Meyer
parent cacc770ce5
commit 705a470a1f
77 changed files with 275 additions and 1929 deletions

View file

@ -11,8 +11,8 @@ use Icinga\Module\Icingadb\Model\Comment;
use Icinga\Module\Icingadb\Web\Control\SearchBar\ObjectSuggestions;
use Icinga\Module\Icingadb\Web\Controller;
use Icinga\Module\Icingadb\Widget\ItemList\CommentList;
use Icinga\Module\Icingadb\Widget\ShowMore;
use Icinga\Module\Icingadb\Web\Control\ViewModeSwitcher;
use Icinga\Module\Icingadb\Widget\ShowMore;
use ipl\Web\Control\LimitControl;
use ipl\Web\Control\SortControl;
use ipl\Web\Filter\QueryString;

View file

@ -11,8 +11,8 @@ use Icinga\Module\Icingadb\Model\Downtime;
use Icinga\Module\Icingadb\Web\Control\SearchBar\ObjectSuggestions;
use Icinga\Module\Icingadb\Web\Controller;
use Icinga\Module\Icingadb\Widget\ItemList\DowntimeList;
use Icinga\Module\Icingadb\Widget\ShowMore;
use Icinga\Module\Icingadb\Web\Control\ViewModeSwitcher;
use Icinga\Module\Icingadb\Widget\ShowMore;
use ipl\Web\Control\LimitControl;
use ipl\Web\Control\SortControl;
use ipl\Web\Filter\QueryString;

View file

@ -10,9 +10,8 @@ use Icinga\Module\Icingadb\Model\Hostgroupsummary;
use Icinga\Module\Icingadb\Web\Control\SearchBar\ObjectSuggestions;
use Icinga\Module\Icingadb\Web\Controller;
use Icinga\Module\Icingadb\Widget\ItemTable\HostgroupTable;
use Icinga\Module\Icingadb\Widget\ShowMore;
use Icinga\Module\Icingadb\Web\Control\ViewModeSwitcher;
use ipl\Orm\Query;
use Icinga\Module\Icingadb\Widget\ShowMore;
use ipl\Web\Control\LimitControl;
use ipl\Web\Control\SortControl;
use ipl\Web\Url;

View file

@ -18,8 +18,8 @@ use Icinga\Module\Icingadb\Widget\Detail\ObjectsDetail;
use Icinga\Module\Icingadb\Widget\ItemList\HostList;
use Icinga\Module\Icingadb\Widget\HostStatusBar;
use Icinga\Module\Icingadb\Widget\ItemTable\HostItemTable;
use Icinga\Module\Icingadb\Widget\ShowMore;
use Icinga\Module\Icingadb\Web\Control\ViewModeSwitcher;
use Icinga\Module\Icingadb\Widget\ShowMore;
use ipl\Orm\Query;
use ipl\Stdlib\Filter;
use ipl\Web\Control\LimitControl;
@ -121,7 +121,9 @@ class HostsController extends Controller
))
);
} else {
$this->addFooter((new HostStatusBar($summary->first()))->setBaseFilter($filter));
/** @var HoststateSummary $hostsSummary */
$hostsSummary = $summary->first();
$this->addFooter((new HostStatusBar($hostsSummary))->setBaseFilter($filter));
}
if (! $searchBar->hasBeenSubmitted() && $searchBar->hasBeenSent()) {

View file

@ -10,8 +10,8 @@ use Icinga\Module\Icingadb\Model\ServicegroupSummary;
use Icinga\Module\Icingadb\Web\Control\SearchBar\ObjectSuggestions;
use Icinga\Module\Icingadb\Web\Controller;
use Icinga\Module\Icingadb\Widget\ItemTable\ServicegroupTable;
use Icinga\Module\Icingadb\Widget\ShowMore;
use Icinga\Module\Icingadb\Web\Control\ViewModeSwitcher;
use Icinga\Module\Icingadb\Widget\ShowMore;
use ipl\Web\Control\LimitControl;
use ipl\Web\Control\SortControl;
use ipl\Web\Url;

View file

@ -20,8 +20,8 @@ use Icinga\Module\Icingadb\Widget\Detail\ObjectsDetail;
use Icinga\Module\Icingadb\Widget\ItemList\ServiceList;
use Icinga\Module\Icingadb\Widget\ItemTable\ServiceItemTable;
use Icinga\Module\Icingadb\Widget\ServiceStatusBar;
use Icinga\Module\Icingadb\Widget\ShowMore;
use Icinga\Module\Icingadb\Web\Control\ViewModeSwitcher;
use Icinga\Module\Icingadb\Widget\ShowMore;
use Icinga\Util\Environment;
use ipl\Html\HtmlString;
use ipl\Orm\Query;
@ -132,7 +132,9 @@ class ServicesController extends Controller
))
);
} else {
$this->addFooter((new ServiceStatusBar($summary->first()))->setBaseFilter($filter));
/** @var ServicestateSummary $servicesSummary */
$servicesSummary = $summary->first();
$this->addFooter((new ServiceStatusBar($servicesSummary))->setBaseFilter($filter));
}
if (! $searchBar->hasBeenSubmitted() && $searchBar->hasBeenSent()) {

View file

@ -1,100 +0,0 @@
<?php
/* Icinga DB Web | (c) 2020 Icinga GmbH | GPLv2 */
namespace Icinga\Module\Icingadb\Common;
use Icinga\Module\Icingadb\Widget\EmptyState;
use InvalidArgumentException;
use ipl\Html\BaseHtmlElement;
use ipl\Stdlib\BaseFilter;
/**
* Base class for item lists
*/
abstract class BaseItemList extends BaseHtmlElement
{
use BaseFilter;
use DetailActions;
protected $baseAttributes = [
'class' => 'item-list',
'data-base-target' => '_next',
'data-pdfexport-page-breaks-at' => '.list-item'
];
/** @var iterable */
protected $data;
/** @var bool Whether the list contains at least one item with an icon_image */
protected $hasIconImages = false;
protected $tag = 'ul';
/**
* Create a new item list
*
* @param iterable $data Data source of the list
*/
public function __construct($data)
{
if (! is_iterable($data)) {
throw new InvalidArgumentException('Data must be an array or an instance of Traversable');
}
$this->data = $data;
$this->addAttributes($this->baseAttributes);
$this->initializeDetailActions();
$this->init();
}
abstract protected function getItemClass(): string;
/**
* Get whether the list contains at least one item with an icon_image
*
* @return bool
*/
public function hasIconImages(): bool
{
return $this->hasIconImages;
}
/**
* Set whether the list contains at least one item with an icon_image
*
* @param bool $hasIconImages
*/
public function setHasIconImages(bool $hasIconImages)
{
$this->hasIconImages = $hasIconImages;
}
/**
* Initialize the item list
*
* If you want to adjust the item list after construction, override this method.
*/
protected function init()
{
}
protected function assemble()
{
$itemClass = $this->getItemClass();
foreach ($this->data as $data) {
/** @var BaseListItem|BaseTableRowItem $item */
$item = new $itemClass($data, $this);
$this->add($item);
}
if ($this->isEmpty()) {
$this->setTag('div');
$this->add(new EmptyState(t('No items found.')));
}
}
}

View file

@ -1,88 +0,0 @@
<?php
/* Icinga DB Web | (c) 2023 Icinga GmbH | GPLv2 */
namespace Icinga\Module\Icingadb\Common;
use Icinga\Module\Icingadb\Widget\EmptyState;
use InvalidArgumentException;
use ipl\Html\BaseHtmlElement;
use ipl\Stdlib\BaseFilter;
/**
* Base class for item tables
*/
abstract class BaseItemTable extends BaseHtmlElement
{
use BaseFilter;
use DetailActions;
protected $baseAttributes = [
'class' => 'item-table',
'data-base-target' => '_next'
];
/** @var iterable */
protected $data;
protected $tag = 'ul';
/**
* Create a new item table
*
* @param iterable $data Data source of the table
*/
public function __construct($data)
{
if (! is_iterable($data)) {
throw new InvalidArgumentException('Data must be an array or an instance of Traversable');
}
$this->data = $data;
$this->addAttributes($this->baseAttributes);
$this->initializeDetailActions();
$this->init();
}
/**
* Initialize the item table
*
* If you want to adjust the item table after construction, override this method.
*/
protected function init()
{
}
/**
* Get the table layout to use
*
* @return string
*/
protected function getLayout(): string
{
return 'table-layout';
}
abstract protected function getItemClass(): string;
protected function assemble()
{
$this->addAttributes(['class' => $this->getLayout()]);
$itemClass = $this->getItemClass();
foreach ($this->data as $data) {
/** @var BaseTableRowItem $item */
$item = new $itemClass($data, $this);
$this->addHtml($item);
}
if ($this->isEmpty()) {
$this->setTag('div');
$this->addHtml(new EmptyState(t('No items found.')));
}
}
}

View file

@ -1,165 +0,0 @@
<?php
/* Icinga DB Web | (c) 2020 Icinga GmbH | GPLv2 */
namespace Icinga\Module\Icingadb\Common;
use Icinga\Module\Icingadb\Common\BaseItemList;
use ipl\Html\BaseHtmlElement;
use ipl\Html\Html;
use ipl\Html\HtmlElement;
use ipl\Stdlib\Filter\Rule;
use ipl\Web\Filter\QueryString;
/**
* Base class for list items
*/
abstract class BaseListItem extends BaseHtmlElement
{
protected $baseAttributes = ['class' => 'list-item'];
/** @var object The associated list item */
protected $item;
/** @var BaseItemList The list where the item is part of */
protected $list;
protected $tag = 'li';
/**
* Create a new list item
*
* @param object $item
* @param BaseItemList $list
*/
public function __construct($item, BaseItemList $list)
{
$this->item = $item;
$this->list = $list;
$this->addAttributes($this->baseAttributes);
$this->init();
}
abstract protected function assembleHeader(BaseHtmlElement $header);
abstract protected function assembleMain(BaseHtmlElement $main);
protected function assembleFooter(BaseHtmlElement $footer)
{
}
protected function assembleCaption(BaseHtmlElement $caption)
{
}
protected function assembleIconImage(BaseHtmlElement $iconImage)
{
}
protected function assembleTitle(BaseHtmlElement $title)
{
}
protected function assembleVisual(BaseHtmlElement $visual)
{
}
protected function createCaption(): BaseHtmlElement
{
$caption = Html::tag('section', ['class' => 'caption']);
$this->assembleCaption($caption);
return $caption;
}
protected function createHeader(): BaseHtmlElement
{
$header = Html::tag('header');
$this->assembleHeader($header);
return $header;
}
protected function createMain(): BaseHtmlElement
{
$main = Html::tag('div', ['class' => 'main']);
$this->assembleMain($main);
return $main;
}
protected function createFooter(): BaseHtmlElement
{
$footer = new HtmlElement('footer');
$this->assembleFooter($footer);
return $footer;
}
/**
* @return ?BaseHtmlElement
*/
protected function createIconImage()
{
if (! $this->list->hasIconImages()) {
return null;
}
$iconImage = HtmlElement::create('div', [
'class' => 'icon-image',
]);
$this->assembleIconImage($iconImage);
return $iconImage;
}
protected function createTimestamp()
{
}
protected function createTitle(): BaseHtmlElement
{
$title = HTML::tag('div', ['class' => 'title']);
$this->assembleTitle($title);
return $title;
}
/**
* @return ?BaseHtmlElement
*/
protected function createVisual()
{
$visual = Html::tag('div', ['class' => 'visual']);
$this->assembleVisual($visual);
return $visual;
}
/**
* Initialize the list item
*
* If you want to adjust the list item after construction, override this method.
*/
protected function init()
{
}
protected function assemble()
{
$this->add([
$this->createVisual(),
$this->createIconImage(),
$this->createMain()
]);
}
}

View file

@ -1,34 +0,0 @@
<?php
/* Icinga DB Web | (c) 2020 Icinga GmbH | GPLv2 */
namespace Icinga\Module\Icingadb\Common;
use Icinga\Module\Icingadb\Common\BaseItemList;
use Icinga\Module\Icingadb\Widget\EmptyState;
/**
* @method BaseOrderedListItem getItemClass()
*/
abstract class BaseOrderedItemList extends BaseItemList
{
protected $tag = 'ol';
protected function assemble()
{
$itemClass = $this->getItemClass();
$i = 0;
foreach ($this->data as $data) {
$item = new $itemClass($data, $this);
$item->setOrder($i++);
$this->add($item);
}
if ($this->isEmpty()) {
$this->setTag('div');
$this->add(new EmptyState(t('No items found.')));
}
}
}

View file

@ -1,41 +0,0 @@
<?php
/* Icinga DB Web | (c) 2020 Icinga GmbH | GPLv2 */
namespace Icinga\Module\Icingadb\Common;
abstract class BaseOrderedListItem extends BaseListItem
{
/** @var int This element's position */
protected $order;
/**
* Set this element's position
*
* @param int $order
*
* @return $this
*/
public function setOrder(int $order): self
{
$this->order = $order;
return $this;
}
/**
* Get this element's position
*
* @return int
*/
public function getOrder()
{
if ($this->order === null) {
throw new \LogicException(
'You are accessing an unset property. Please make sure to set it beforehand.'
);
}
return $this->order;
}
}

View file

@ -1,116 +0,0 @@
<?php
/* Icinga DB Web | (c) 2020 Icinga GmbH | GPLv2 */
namespace Icinga\Module\Icingadb\Common;
use ipl\Html\Attributes;
use ipl\Html\BaseHtmlElement;
use ipl\Html\Html;
use ipl\Html\HtmlDocument;
use ipl\Html\HtmlElement;
abstract class BaseTableRowItem extends BaseHtmlElement
{
protected $baseAttributes = ['class' => 'table-row'];
/** @var object The associated list item */
protected $item;
/** @var ?BaseItemTable The list where the item is part of */
protected $table;
protected $tag = 'li';
/**
* Create a new table row item
*
* @param object $item
* @param BaseItemTable $table
*/
public function __construct($item, BaseItemTable $table = null)
{
$this->item = $item;
$this->table = $table;
if ($table === null) {
$this->setTag('div');
}
$this->addAttributes($this->baseAttributes);
$this->init();
}
abstract protected function assembleTitle(BaseHtmlElement $title);
protected function assembleColumns(HtmlDocument $columns)
{
}
protected function assembleVisual(BaseHtmlElement $visual)
{
}
protected function createColumn($content = null): BaseHtmlElement
{
return new HtmlElement(
'div',
Attributes::create(['class' => 'col']),
new HtmlElement(
'div',
Attributes::create(['class' => 'content']),
...Html::wantHtmlList($content)
)
);
}
protected function createColumns(): HtmlDocument
{
$columns = new HtmlDocument();
$this->assembleColumns($columns);
return $columns;
}
protected function createTitle(): BaseHtmlElement
{
$title = $this->createColumn()->addAttributes(['class' => 'title']);
$this->assembleTitle($title->getFirst('div'));
$title->prepend($this->createVisual());
return $title;
}
/**
* @return ?BaseHtmlElement
*/
protected function createVisual()
{
$visual = new HtmlElement('div', Attributes::create(['class' => 'visual']));
$this->assembleVisual($visual);
return $visual->isEmpty() ? null : $visual;
}
/**
* Initialize the list item
*
* If you want to adjust the list item after construction, override this method.
*/
protected function init()
{
}
protected function assemble()
{
$this->add([
$this->createTitle(),
$this->createColumns()
]);
}
}

View file

@ -70,7 +70,6 @@ trait DetailActions
*/
protected function setMultiselectUrl(Url $url): self
{
/** @var BaseHtmlElement $this */
$this->getAttributes()
->registerAttributeCallback('data-icinga-multiselect-url', function () use ($url) {
return $this->getDetailActionsDisabled() ? null : (string) $url;
@ -88,7 +87,6 @@ trait DetailActions
*/
protected function setDetailUrl(Url $url): self
{
/** @var BaseHtmlElement $this */
$this->getAttributes()
->registerAttributeCallback('data-icinga-detail-url', function () use ($url) {
return $this->getDetailActionsDisabled() ? null : (string) $url;

View file

@ -10,17 +10,17 @@ trait ListItemCommonLayout
{
use CaptionDisabled;
protected function assembleHeader(BaseHtmlElement $header)
protected function assembleHeader(BaseHtmlElement $header): void
{
$header->add($this->createTitle());
$header->addHtml($this->createTitle());
$header->add($this->createTimestamp());
}
protected function assembleMain(BaseHtmlElement $main)
protected function assembleMain(BaseHtmlElement $main): void
{
$main->add($this->createHeader());
if (! $this->isCaptionDisabled()) {
$main->add($this->createCaption());
$main->addHtml($this->createHeader());
if (!$this->isCaptionDisabled()) {
$main->addHtml($this->createCaption());
}
}
}

View file

@ -8,13 +8,13 @@ use ipl\Html\BaseHtmlElement;
trait ListItemDetailedLayout
{
protected function assembleHeader(BaseHtmlElement $header)
protected function assembleHeader(BaseHtmlElement $header): void
{
$header->add($this->createTitle());
$header->add($this->createTimestamp());
}
protected function assembleMain(BaseHtmlElement $main)
protected function assembleMain(BaseHtmlElement $main): void
{
$main->add($this->createHeader());
$main->add($this->createCaption());

View file

@ -10,7 +10,7 @@ trait ListItemMinimalLayout
{
use CaptionDisabled;
protected function assembleHeader(BaseHtmlElement $header)
protected function assembleHeader(BaseHtmlElement $header): void
{
$header->add($this->createTitle());
if (! $this->isCaptionDisabled()) {
@ -19,7 +19,7 @@ trait ListItemMinimalLayout
$header->add($this->createTimestamp());
}
protected function assembleMain(BaseHtmlElement $main)
protected function assembleMain(BaseHtmlElement $main): void
{
$main->add($this->createHeader());
}

View file

@ -12,7 +12,6 @@ use Icinga\Exception\Json\JsonDecodeException;
use Icinga\Module\Icingadb\Model\Host;
use Icinga\Module\Icingadb\Model\Service;
use Icinga\Module\Icingadb\Widget\Detail\CustomVarTable;
use Icinga\Module\Icingadb\Widget\EmptyState;
use Icinga\Util\Format;
use Icinga\Util\Json;
use ipl\Html\BaseHtmlElement;
@ -22,6 +21,7 @@ use ipl\Html\Table;
use ipl\Html\Text;
use ipl\Orm\Model;
use ipl\Web\Widget\CopyToClipboard;
use ipl\Web\Widget\EmptyState;
abstract class ObjectInspectionDetail extends BaseHtmlElement
{

View file

@ -5,9 +5,9 @@
namespace Icinga\Module\Icingadb\Hook\Common;
use Icinga\Module\Icingadb\ProvidedHook\Reporting\HostSlaReport;
use Icinga\Module\Icingadb\Widget\EmptyState;
use Icinga\Module\Reporting\Timerange;
use ipl\Html\Html;
use ipl\Web\Widget\EmptyState;
use function ipl\I18n\t;

View file

@ -8,16 +8,15 @@ use DateInterval;
use DatePeriod;
use Icinga\Module\Icingadb\Common\Auth;
use Icinga\Module\Icingadb\Common\Database;
use Icinga\Module\Icingadb\Widget\EmptyState;
use Icinga\Module\Reporting\Hook\ReportHook;
use Icinga\Module\Reporting\ReportData;
use Icinga\Module\Reporting\ReportRow;
use Icinga\Module\Reporting\Timerange;
use ipl\Html\Form;
use ipl\Html\Html;
use ipl\Html\HtmlElement;
use ipl\Stdlib\Filter\Rule;
use ipl\Web\Filter\QueryString;
use ipl\Web\Widget\EmptyState;
use function ipl\I18n\t;

View file

@ -18,9 +18,7 @@ use Icinga\Exception\ConfigurationError;
use Icinga\Exception\Http\HttpBadRequestException;
use Icinga\Exception\Json\JsonDecodeException;
use Icinga\Module\Icingadb\Common\Auth;
use Icinga\Module\Icingadb\Common\BaseItemTable;
use Icinga\Module\Icingadb\Common\Database;
use Icinga\Module\Icingadb\Common\BaseItemList;
use Icinga\Module\Icingadb\Common\SearchControls;
use Icinga\Module\Icingadb\Data\CsvResultSet;
use Icinga\Module\Icingadb\Data\JsonResultSet;
@ -39,6 +37,8 @@ use ipl\Html\ValidHtml;
use ipl\Orm\Query;
use ipl\Orm\UnionQuery;
use ipl\Stdlib\Filter;
use ipl\Web\Common\BaseItemList;
use ipl\Web\Common\BaseItemTable;
use ipl\Web\Compat\CompatController;
use ipl\Web\Control\LimitControl;
use ipl\Web\Control\PaginationControl;

View file

@ -6,7 +6,6 @@ namespace Icinga\Module\Icingadb\Widget\Detail;
use Icinga\Date\DateFormatter;
use Icinga\Module\Icingadb\Widget\CheckAttempt;
use Icinga\Module\Icingadb\Widget\EmptyState;
use Icinga\Util\Format;
use ipl\Html\Attributes;
use ipl\Html\BaseHtmlElement;
@ -15,6 +14,7 @@ use ipl\Html\HtmlElement;
use ipl\Html\HtmlString;
use ipl\Html\Text;
use ipl\Web\Common\Card;
use ipl\Web\Widget\EmptyState;
use ipl\Web\Widget\StateBall;
use ipl\Web\Widget\TimeAgo;
use ipl\Web\Widget\TimeSince;

View file

@ -5,7 +5,6 @@
namespace Icinga\Module\Icingadb\Widget\Detail;
use Icinga\Module\Icingadb\Hook\CustomVarRendererHook;
use Icinga\Module\Icingadb\Widget\EmptyState;
use ipl\Html\Attributes;
use ipl\Html\BaseHtmlElement;
use ipl\Html\Html;
@ -13,6 +12,7 @@ use ipl\Html\HtmlDocument;
use ipl\Html\HtmlElement;
use ipl\Html\Text;
use ipl\Orm\Model;
use ipl\Web\Widget\EmptyState;
use ipl\Web\Widget\Icon;
use Closure;

View file

@ -10,14 +10,14 @@ use Icinga\Module\Icingadb\Common\Auth;
use Icinga\Module\Icingadb\Common\Database;
use Icinga\Module\Icingadb\Common\HostLink;
use Icinga\Module\Icingadb\Common\Links;
use Icinga\Module\Icingadb\Widget\EmptyState;
use Icinga\Module\Icingadb\Widget\MarkdownText;
use Icinga\Module\Icingadb\Common\ServiceLink;
use Icinga\Module\Icingadb\Forms\Command\Object\DeleteDowntimeForm;
use Icinga\Module\Icingadb\Model\Downtime;
use Icinga\Module\Icingadb\Widget\ItemList\DowntimeList;
use ipl\Web\Widget\HorizontalKeyValue;
use Icinga\Module\Icingadb\Widget\ShowMore;
use ipl\Web\Widget\EmptyState;
use ipl\Web\Widget\HorizontalKeyValue;
use ipl\Html\BaseHtmlElement;
use ipl\Html\Html;
use ipl\Html\HtmlElement;

View file

@ -25,12 +25,12 @@ use Icinga\Module\Icingadb\Model\History;
use Icinga\Module\Icingadb\Model\NotificationHistory;
use Icinga\Module\Icingadb\Model\StateHistory;
use Icinga\Module\Icingadb\Util\PluginOutput;
use Icinga\Module\Icingadb\Widget\EmptyState;
use Icinga\Module\Icingadb\Widget\ShowMore;
use ipl\Web\Widget\CopyToClipboard;
use ipl\Web\Widget\EmptyState;
use ipl\Web\Widget\HorizontalKeyValue;
use Icinga\Module\Icingadb\Widget\ItemTable\UserTable;
use Icinga\Module\Icingadb\Widget\PluginOutputContainer;
use Icinga\Module\Icingadb\Widget\ShowMore;
use ipl\Html\BaseHtmlElement;
use ipl\Html\FormattedString;
use ipl\Html\HtmlElement;

View file

@ -7,9 +7,9 @@ namespace Icinga\Module\Icingadb\Widget\Detail;
use Icinga\Module\Icingadb\Hook\ExtensionHook\ObjectDetailExtensionHook;
use Icinga\Module\Icingadb\Model\Host;
use Icinga\Module\Icingadb\Model\ServicestateSummary;
use Icinga\Module\Icingadb\Widget\EmptyState;
use ipl\Html\Html;
use ipl\Stdlib\Filter;
use ipl\Web\Widget\EmptyState;
class HostDetail extends ObjectDetail
{

View file

@ -6,7 +6,7 @@ namespace Icinga\Module\Icingadb\Widget\Detail;
use Icinga\Date\DateFormatter;
use Icinga\Module\Icingadb\Model\Host;
use Icinga\Module\Icingadb\Widget\EmptyState;
use ipl\Web\Widget\EmptyState;
use ipl\Web\Widget\HorizontalKeyValue;
use ipl\Web\Widget\VerticalKeyValue;
use ipl\Html\Attributes;

View file

@ -32,13 +32,12 @@ use Icinga\Module\Icingadb\Model\User;
use Icinga\Module\Icingadb\Model\Usergroup;
use Icinga\Module\Icingadb\Util\PluginOutput;
use Icinga\Module\Icingadb\Widget\ItemList\DowntimeList;
use Icinga\Module\Icingadb\Widget\EmptyState;
use Icinga\Module\Icingadb\Widget\StateChange;
use Icinga\Module\Icingadb\Widget\ShowMore;
use ipl\Web\Widget\CopyToClipboard;
use ipl\Web\Widget\EmptyState;
use ipl\Web\Widget\HorizontalKeyValue;
use Icinga\Module\Icingadb\Widget\ItemList\CommentList;
use Icinga\Module\Icingadb\Widget\PluginOutputContainer;
use Icinga\Module\Icingadb\Widget\ShowMore;
use Icinga\Module\Icingadb\Widget\TagList;
use Icinga\Module\Monitoring\Hook\DetailviewExtensionHook;
use Icinga\Web\Navigation\Navigation;

View file

@ -11,12 +11,11 @@ use Icinga\Module\Icingadb\Hook\ExtensionHook\ObjectsDetailExtensionHook;
use Icinga\Module\Icingadb\Model\HoststateSummary;
use Icinga\Module\Icingadb\Model\ServicestateSummary;
use Icinga\Module\Icingadb\Util\FeatureStatus;
use Icinga\Module\Icingadb\Widget\EmptyState;
use Icinga\Module\Icingadb\Widget\HostStateBadges;
use Icinga\Module\Icingadb\Widget\ServiceStateBadges;
use ipl\Html\HtmlElement;
use ipl\Orm\Query;
use ipl\Stdlib\BaseFilter;
use ipl\Web\Widget\EmptyState;
use ipl\Web\Widget\VerticalKeyValue;
use ipl\Html\BaseHtmlElement;
use ipl\Html\Html;

View file

@ -6,13 +6,13 @@ namespace Icinga\Module\Icingadb\Widget\Detail;
use Icinga\Module\Icingadb\Util\PerfData;
use Icinga\Module\Icingadb\Util\PerfDataSet;
use Icinga\Module\Icingadb\Widget\EmptyState;
use ipl\Html\Attributes;
use ipl\Html\HtmlElement;
use ipl\Html\HtmlString;
use ipl\Html\Table;
use ipl\Html\Text;
use ipl\I18n\Translation;
use ipl\Web\Widget\EmptyState;
use ipl\Web\Widget\Icon;
class PerfDataTable extends Table

View file

@ -9,11 +9,11 @@ use Icinga\Module\Icingadb\Common\Database;
use Icinga\Module\Icingadb\Common\Links;
use Icinga\Module\Icingadb\Hook\ExtensionHook\ObjectDetailExtensionHook;
use Icinga\Module\Icingadb\Model\User;
use Icinga\Module\Icingadb\Widget\EmptyState;
use Icinga\Module\Icingadb\Widget\ShowMore;
use ipl\Html\Attributes;
use ipl\Web\Widget\EmptyState;
use ipl\Web\Widget\HorizontalKeyValue;
use Icinga\Module\Icingadb\Widget\ItemTable\UsergroupTable;
use Icinga\Module\Icingadb\Widget\ShowMore;
use ipl\Html\BaseHtmlElement;
use ipl\Html\HtmlElement;
use ipl\Html\Text;

View file

@ -9,13 +9,13 @@ use Icinga\Module\Icingadb\Common\Database;
use Icinga\Module\Icingadb\Common\Links;
use Icinga\Module\Icingadb\Hook\ExtensionHook\ObjectDetailExtensionHook;
use Icinga\Module\Icingadb\Model\Usergroup;
use Icinga\Module\Icingadb\Widget\EmptyState;
use Icinga\Module\Icingadb\Widget\ItemTable\UserTable;
use Icinga\Module\Icingadb\Widget\ShowMore;
use ipl\Html\Attributes;
use ipl\Html\BaseHtmlElement;
use ipl\Html\HtmlElement;
use ipl\Html\Text;
use ipl\Web\Widget\EmptyState;
use ipl\Web\Widget\HorizontalKeyValue;
class UsergroupDetail extends BaseHtmlElement

View file

@ -1,27 +0,0 @@
<?php
/* Icinga DB Web | (c) 2020 Icinga GmbH | GPLv2 */
namespace Icinga\Module\Icingadb\Widget;
use ipl\Html\BaseHtmlElement;
class EmptyState extends BaseHtmlElement
{
/** @var mixed Content */
protected $content;
protected $tag = 'div';
protected $defaultAttributes = ['class' => 'empty-state'];
public function __construct($content)
{
$this->content = $content;
}
protected function assemble()
{
$this->add($this->content);
}
}

View file

@ -9,7 +9,7 @@ use ipl\Html\BaseHtmlElement;
class HostStatusBar extends BaseStatusBar
{
protected function assembleTotal(BaseHtmlElement $total)
protected function assembleTotal(BaseHtmlElement $total): void
{
$total->add(sprintf(tp('%d Host', '%d Hosts', $this->summary->hosts_total), $this->summary->hosts_total));
}

View file

@ -4,18 +4,18 @@
namespace Icinga\Module\Icingadb\Widget\ItemList;
use Icinga\Module\Icingadb\Common\NoSubjectLink;
use Icinga\Module\Icingadb\Common\ObjectLinkDisabled;
use Icinga\Module\Icingadb\Common\TicketLinks;
use ipl\Html\Html;
use Icinga\Module\Icingadb\Common\HostLink;
use Icinga\Module\Icingadb\Common\Icons;
use Icinga\Module\Icingadb\Common\Links;
use Icinga\Module\Icingadb\Widget\MarkdownLine;
use Icinga\Module\Icingadb\Common\NoSubjectLink;
use Icinga\Module\Icingadb\Common\ObjectLinkDisabled;
use Icinga\Module\Icingadb\Common\ServiceLink;
use Icinga\Module\Icingadb\Model\Comment;
use Icinga\Module\Icingadb\Common\BaseListItem;
use ipl\Html\FormattedString;
use ipl\Web\Common\BaseListItem;
use ipl\Web\Widget\TimeAgo;
use ipl\Html\Attributes;
use ipl\Html\BaseHtmlElement;
@ -40,7 +40,7 @@ abstract class BaseCommentListItem extends BaseListItem
use ObjectLinkDisabled;
use TicketLinks;
protected function assembleCaption(BaseHtmlElement $caption)
protected function assembleCaption(BaseHtmlElement $caption): void
{
$markdownLine = new MarkdownLine($this->createTicketLinks($this->item->text));
@ -48,7 +48,7 @@ abstract class BaseCommentListItem extends BaseListItem
$caption->addFrom($markdownLine);
}
protected function assembleTitle(BaseHtmlElement $title)
protected function assembleTitle(BaseHtmlElement $title): void
{
$isAck = $this->item->entry_type === 'ack';
$expires = $this->item->expire_time;
@ -96,7 +96,7 @@ abstract class BaseCommentListItem extends BaseListItem
$title->addHtml(...$headerParts);
}
protected function assembleVisual(BaseHtmlElement $visual)
protected function assembleVisual(BaseHtmlElement $visual): void
{
$visual->addHtml(new HtmlElement(
'div',
@ -105,7 +105,7 @@ abstract class BaseCommentListItem extends BaseListItem
));
}
protected function createTimestamp()
protected function createTimestamp(): ?BaseHtmlElement
{
if ($this->item->expire_time) {
return Html::tag(
@ -120,7 +120,7 @@ abstract class BaseCommentListItem extends BaseListItem
);
}
protected function init()
protected function init(): void
{
$this->setTicketLinkEnabled($this->list->getTicketLinkEnabled());
$this->list->addDetailFilterAttribute($this, Filter::equal('name', $this->item->name));

View file

@ -5,7 +5,6 @@
namespace Icinga\Module\Icingadb\Widget\ItemList;
use Icinga\Date\DateFormatter;
use Icinga\Module\Icingadb\Common\BaseListItem;
use Icinga\Module\Icingadb\Common\HostLink;
use Icinga\Module\Icingadb\Common\Icons;
use Icinga\Module\Icingadb\Common\Links;
@ -22,6 +21,7 @@ use ipl\Html\HtmlElement;
use ipl\Html\TemplateString;
use ipl\Html\Text;
use ipl\Stdlib\Filter;
use ipl\Web\Common\BaseListItem;
use ipl\Web\Widget\Icon;
use ipl\Web\Widget\Link;
@ -54,7 +54,7 @@ abstract class BaseDowntimeListItem extends BaseListItem
/** @var int Downtime start time */
protected $startTime;
protected function init()
protected function init(): void
{
if ($this->item->is_flexible && $this->item->is_in_effect) {
$this->startTime = $this->item->start_time->getTimestamp();
@ -102,7 +102,7 @@ abstract class BaseDowntimeListItem extends BaseListItem
);
}
protected function assembleCaption(BaseHtmlElement $caption)
protected function assembleCaption(BaseHtmlElement $caption): void
{
$markdownLine = new MarkdownLine($this->createTicketLinks($this->item->comment));
$caption->getAttributes()->add($markdownLine->getAttributes());
@ -117,7 +117,7 @@ abstract class BaseDowntimeListItem extends BaseListItem
)->addFrom($markdownLine);
}
protected function assembleTitle(BaseHtmlElement $title)
protected function assembleTitle(BaseHtmlElement $title): void
{
if ($this->getObjectLinkDisabled()) {
$link = null;
@ -164,7 +164,7 @@ abstract class BaseDowntimeListItem extends BaseListItem
}
}
protected function assembleVisual(BaseHtmlElement $visual)
protected function assembleVisual(BaseHtmlElement $visual): void
{
$dateTime = DateFormatter::formatDateTime($this->endTime);
@ -191,7 +191,7 @@ abstract class BaseDowntimeListItem extends BaseListItem
}
}
protected function createTimestamp()
protected function createTimestamp(): ?BaseHtmlElement
{
$dateTime = DateFormatter::formatDateTime($this->isActive ? $this->endTime : $this->startTime);

View file

@ -9,19 +9,19 @@ use Icinga\Module\Icingadb\Common\HostLink;
use Icinga\Module\Icingadb\Common\HostStates;
use Icinga\Module\Icingadb\Common\Icons;
use Icinga\Module\Icingadb\Common\Links;
use Icinga\Module\Icingadb\Common\TicketLinks;
use Icinga\Module\Icingadb\Widget\EmptyState;
use Icinga\Module\Icingadb\Widget\MarkdownLine;
use Icinga\Module\Icingadb\Common\NoSubjectLink;
use Icinga\Module\Icingadb\Common\TicketLinks;
use Icinga\Module\Icingadb\Widget\MarkdownLine;
use Icinga\Module\Icingadb\Common\ServiceLink;
use Icinga\Module\Icingadb\Common\ServiceStates;
use Icinga\Module\Icingadb\Model\History;
use Icinga\Module\Icingadb\Util\PluginOutput;
use Icinga\Module\Icingadb\Common\BaseListItem;
use Icinga\Module\Icingadb\Widget\CheckAttempt;
use Icinga\Module\Icingadb\Widget\PluginOutputContainer;
use Icinga\Module\Icingadb\Widget\StateChange;
use ipl\Stdlib\Filter;
use ipl\Web\Common\BaseListItem;
use ipl\Web\Widget\EmptyState;
use ipl\Web\Widget\StateBall;
use ipl\Web\Widget\TimeAgo;
use ipl\Html\BaseHtmlElement;
@ -43,7 +43,7 @@ abstract class BaseHistoryListItem extends BaseListItem
/** @var HistoryList */
protected $list;
protected function init()
protected function init(): void
{
$this->setNoSubjectLink($this->list->getNoSubjectLink());
$this->setTicketLinkEnabled($this->list->getTicketLinkEnabled());
@ -52,7 +52,7 @@ abstract class BaseHistoryListItem extends BaseListItem
abstract protected function getStateBallSize(): string;
protected function assembleCaption(BaseHtmlElement $caption)
protected function assembleCaption(BaseHtmlElement $caption): void
{
switch ($this->item->event_type) {
case 'comment_add':
@ -168,7 +168,7 @@ abstract class BaseHistoryListItem extends BaseListItem
}
}
protected function assembleVisual(BaseHtmlElement $visual)
protected function assembleVisual(BaseHtmlElement $visual): void
{
switch ($this->item->event_type) {
case 'comment_add':
@ -270,7 +270,7 @@ abstract class BaseHistoryListItem extends BaseListItem
}
}
protected function assembleTitle(BaseHtmlElement $title)
protected function assembleTitle(BaseHtmlElement $title): void
{
switch ($this->item->event_type) {
case 'comment_add':
@ -398,7 +398,7 @@ abstract class BaseHistoryListItem extends BaseListItem
}
}
protected function createTimestamp()
protected function createTimestamp(): ?BaseHtmlElement
{
return new TimeAgo($this->item->event_time->getTimestamp());
}

View file

@ -42,7 +42,7 @@ abstract class BaseHostListItem extends StateListItem
}
}
protected function init()
protected function init(): void
{
parent::init();

View file

@ -12,11 +12,11 @@ use Icinga\Module\Icingadb\Common\NoSubjectLink;
use Icinga\Module\Icingadb\Common\ServiceLink;
use Icinga\Module\Icingadb\Common\ServiceStates;
use Icinga\Module\Icingadb\Util\PluginOutput;
use Icinga\Module\Icingadb\Common\BaseListItem;
use Icinga\Module\Icingadb\Widget\EmptyState;
use Icinga\Module\Icingadb\Widget\PluginOutputContainer;
use Icinga\Module\Icingadb\Widget\StateChange;
use ipl\Stdlib\Filter;
use ipl\Web\Common\BaseListItem;
use ipl\Web\Widget\EmptyState;
use ipl\Web\Widget\TimeAgo;
use InvalidArgumentException;
use ipl\Html\BaseHtmlElement;
@ -34,7 +34,7 @@ abstract class BaseNotificationListItem extends BaseListItem
/** @var NotificationList */
protected $list;
protected function init()
protected function init(): void
{
$this->setNoSubjectLink($this->list->getNoSubjectLink());
$this->list->addDetailFilterAttribute($this, Filter::equal('id', bin2hex($this->item->history->id)));
@ -75,7 +75,7 @@ abstract class BaseNotificationListItem extends BaseListItem
abstract protected function getStateBallSize();
protected function assembleCaption(BaseHtmlElement $caption)
protected function assembleCaption(BaseHtmlElement $caption): void
{
if (in_array($this->item->type, ['flapping_end', 'flapping_start', 'problem', 'recovery'])) {
$commandName = $this->item->object_type === 'host'
@ -103,7 +103,7 @@ abstract class BaseNotificationListItem extends BaseListItem
}
}
protected function assembleVisual(BaseHtmlElement $visual)
protected function assembleVisual(BaseHtmlElement $visual): void
{
switch ($this->item->type) {
case 'acknowledgement':
@ -157,7 +157,7 @@ abstract class BaseNotificationListItem extends BaseListItem
}
}
protected function assembleTitle(BaseHtmlElement $title)
protected function assembleTitle(BaseHtmlElement $title): void
{
if ($this->getNoSubjectLink()) {
$title->addHtml(HtmlElement::create(
@ -182,7 +182,7 @@ abstract class BaseNotificationListItem extends BaseListItem
$title->addHtml(Text::create(' '), $link);
}
protected function createTimestamp()
protected function createTimestamp(): ?BaseHtmlElement
{
return new TimeAgo($this->item->send_time->getTimestamp());
}

View file

@ -44,7 +44,7 @@ abstract class BaseServiceListItem extends StateListItem
return [Html::sprintf(t('%s on %s', '<service> on <host>'), $service, $host)];
}
protected function init()
protected function init(): void
{
parent::init();

View file

@ -4,14 +4,18 @@
namespace Icinga\Module\Icingadb\Widget\ItemList;
use Icinga\Module\Icingadb\Common\BaseOrderedItemList;
use Icinga\Module\Icingadb\Common\DetailActions;
use ipl\Web\Common\BaseOrderedItemList;
use ipl\Web\Url;
class CommandTransportList extends BaseOrderedItemList
{
protected function init()
use DetailActions;
protected function init(): void
{
$this->getAttributes()->add('class', 'command-transport-list');
$this->initializeDetailActions();
$this->setDetailUrl(Url::fromPath('icingadb/command-transport/show'));
}

View file

@ -4,27 +4,27 @@
namespace Icinga\Module\Icingadb\Widget\ItemList;
use Icinga\Module\Icingadb\Common\BaseOrderedListItem;
use ipl\Html\BaseHtmlElement;
use ipl\Html\HtmlElement;
use ipl\Html\Text;
use ipl\Stdlib\Filter;
use ipl\Web\Common\BaseOrderedListItem;
use ipl\Web\Url;
use ipl\Web\Widget\Icon;
use ipl\Web\Widget\Link;
class CommandTransportListItem extends BaseOrderedListItem
{
protected function init()
protected function init(): void
{
$this->list->addDetailFilterAttribute($this, Filter::equal('name', $this->item->name));
}
protected function assembleHeader(BaseHtmlElement $header)
protected function assembleHeader(BaseHtmlElement $header): void
{
}
protected function assembleMain(BaseHtmlElement $main)
protected function assembleMain(BaseHtmlElement $main): void
{
$main->addHtml(new Link(
new HtmlElement('strong', null, Text::create($this->item->name)),
@ -64,7 +64,8 @@ class CommandTransportListItem extends BaseOrderedListItem
}
}
protected function createVisual()
protected function createVisual(): ?BaseHtmlElement
{
return null;
}
}

View file

@ -5,12 +5,13 @@
namespace Icinga\Module\Icingadb\Widget\ItemList;
use Icinga\Module\Icingadb\Common\CaptionDisabled;
use Icinga\Module\Icingadb\Common\DetailActions;
use Icinga\Module\Icingadb\Common\Links;
use Icinga\Module\Icingadb\Common\NoSubjectLink;
use Icinga\Module\Icingadb\Common\ObjectLinkDisabled;
use Icinga\Module\Icingadb\Common\TicketLinks;
use Icinga\Module\Icingadb\Common\ViewMode;
use Icinga\Module\Icingadb\Common\BaseItemList;
use ipl\Web\Common\BaseItemList;
use ipl\Web\Url;
class CommentList extends BaseItemList
@ -20,6 +21,7 @@ class CommentList extends BaseItemList
use ObjectLinkDisabled;
use ViewMode;
use TicketLinks;
use DetailActions;
protected $defaultAttributes = ['class' => 'comment-list'];
@ -31,13 +33,16 @@ class CommentList extends BaseItemList
if ($viewMode === 'minimal') {
return CommentListItemMinimal::class;
} elseif ($viewMode === 'detailed') {
$this->removeAttribute('class', 'default-layout');
}
return CommentListItem::class;
}
protected function init()
protected function init(): void
{
$this->initializeDetailActions();
$this->setMultiselectUrl(Links::commentsDetails());
$this->setDetailUrl(Url::fromPath('icingadb/comment'));
}

View file

@ -10,7 +10,7 @@ class CommentListItemMinimal extends BaseCommentListItem
{
use ListItemMinimalLayout;
protected function init()
protected function init(): void
{
parent::init();

View file

@ -4,13 +4,14 @@
namespace Icinga\Module\Icingadb\Widget\ItemList;
use Icinga\Module\Icingadb\Common\BaseItemList;
use Icinga\Module\Icingadb\Common\CaptionDisabled;
use Icinga\Module\Icingadb\Common\DetailActions;
use Icinga\Module\Icingadb\Common\Links;
use Icinga\Module\Icingadb\Common\NoSubjectLink;
use Icinga\Module\Icingadb\Common\ObjectLinkDisabled;
use Icinga\Module\Icingadb\Common\TicketLinks;
use Icinga\Module\Icingadb\Common\ViewMode;
use ipl\Web\Common\BaseItemList;
use ipl\Web\Url;
class DowntimeList extends BaseItemList
@ -20,6 +21,7 @@ class DowntimeList extends BaseItemList
use ObjectLinkDisabled;
use ViewMode;
use TicketLinks;
use DetailActions;
protected $defaultAttributes = ['class' => 'downtime-list'];
@ -31,13 +33,16 @@ class DowntimeList extends BaseItemList
if ($viewMode === 'minimal') {
return DowntimeListItemMinimal::class;
} elseif ($viewMode === 'detailed') {
$this->removeAttribute('class', 'default-layout');
}
return DowntimeListItem::class;
}
protected function init()
protected function init(): void
{
$this->initializeDetailActions();
$this->setMultiselectUrl(Links::downtimesDetails());
$this->setDetailUrl(Url::fromPath('icingadb/downtime'));
}

View file

@ -11,7 +11,7 @@ class DowntimeListItem extends BaseDowntimeListItem
{
use ListItemCommonLayout;
protected function assembleMain(BaseHtmlElement $main)
protected function assembleMain(BaseHtmlElement $main): void
{
if ($this->item->is_in_effect) {
$main->add($this->createProgress());

View file

@ -10,7 +10,7 @@ class DowntimeListItemMinimal extends BaseDowntimeListItem
{
use ListItemMinimalLayout;
protected function init()
protected function init(): void
{
parent::init();

View file

@ -5,12 +5,13 @@
namespace Icinga\Module\Icingadb\Widget\ItemList;
use Icinga\Module\Icingadb\Common\CaptionDisabled;
use Icinga\Module\Icingadb\Common\DetailActions;
use Icinga\Module\Icingadb\Common\LoadMore;
use Icinga\Module\Icingadb\Common\NoSubjectLink;
use Icinga\Module\Icingadb\Common\TicketLinks;
use Icinga\Module\Icingadb\Common\ViewMode;
use Icinga\Module\Icingadb\Common\BaseItemList;
use ipl\Orm\ResultSet;
use ipl\Web\Common\BaseItemList;
use ipl\Web\Url;
class HistoryList extends BaseItemList
@ -20,20 +21,16 @@ class HistoryList extends BaseItemList
use ViewMode;
use LoadMore;
use TicketLinks;
use DetailActions;
protected $defaultAttributes = ['class' => 'history-list'];
/** @var ResultSet */
protected $data;
public function __construct(ResultSet $data)
protected function init(): void
{
parent::__construct($data);
}
protected function init()
{
$this->data = $this->getIterator($this->data);
/** @var ResultSet $data */
$data = $this->data;
$this->data = $this->getIterator($data);
$this->initializeDetailActions();
$this->setDetailUrl(Url::fromPath('icingadb/event'));
}
@ -43,13 +40,15 @@ class HistoryList extends BaseItemList
case 'minimal':
return HistoryListItemMinimal::class;
case 'detailed':
$this->removeAttribute('class', 'default-layout');
return HistoryListItemDetailed::class;
default:
return HistoryListItem::class;
}
}
protected function assemble()
protected function assemble(): void
{
$this->addAttributes(['class' => $this->getViewMode()]);

View file

@ -11,7 +11,7 @@ class HistoryListItemMinimal extends BaseHistoryListItem
{
use ListItemMinimalLayout;
protected function init()
protected function init(): void
{
parent::init();

View file

@ -16,7 +16,7 @@ class HostDetailHeader extends HostListItemMinimal
return '';
}
protected function assembleVisual(BaseHtmlElement $visual)
protected function assembleVisual(BaseHtmlElement $visual): void
{
if ($this->state->state_type === 'soft') {
$stateType = 'soft_state';
@ -55,7 +55,7 @@ class HostDetailHeader extends HostListItemMinimal
$visual->addHtml($stateChange);
}
protected function assemble()
protected function assemble(): void
{
$attributes = $this->list->getAttributes();
if (! in_array('minimal', $attributes->get('class')->getValue())) {

View file

@ -20,6 +20,8 @@ class HostList extends StateList
case 'minimal':
return HostListItemMinimal::class;
case 'detailed':
$this->removeAttribute('class', 'default-layout');
return HostListItemDetailed::class;
case 'objectHeader':
return HostDetailHeader::class;
@ -28,8 +30,9 @@ class HostList extends StateList
}
}
protected function init()
protected function init(): void
{
$this->initializeDetailActions();
$this->setMultiselectUrl(Links::hostsDetails());
$this->setDetailUrl(Url::fromPath('icingadb/host'));
}

View file

@ -27,7 +27,7 @@ class HostListItemDetailed extends BaseHostListItem
return StateBall::SIZE_LARGE;
}
protected function assembleFooter(BaseHtmlElement $footer)
protected function assembleFooter(BaseHtmlElement $footer): void
{
$statusIcons = new HtmlElement('div', Attributes::create(['class' => 'status-icons']));

View file

@ -5,11 +5,12 @@
namespace Icinga\Module\Icingadb\Widget\ItemList;
use Icinga\Module\Icingadb\Common\CaptionDisabled;
use Icinga\Module\Icingadb\Common\DetailActions;
use Icinga\Module\Icingadb\Common\LoadMore;
use Icinga\Module\Icingadb\Common\NoSubjectLink;
use Icinga\Module\Icingadb\Common\ViewMode;
use Icinga\Module\Icingadb\Common\BaseItemList;
use ipl\Orm\ResultSet;
use ipl\Web\Common\BaseItemList;
use ipl\Web\Url;
class NotificationList extends BaseItemList
@ -18,20 +19,16 @@ class NotificationList extends BaseItemList
use NoSubjectLink;
use ViewMode;
use LoadMore;
use DetailActions;
protected $defaultAttributes = ['class' => 'notification-list'];
/** @var ResultSet */
protected $data;
public function __construct(ResultSet $data)
protected function init(): void
{
parent::__construct($data);
}
protected function init()
{
$this->data = $this->getIterator($this->data);
/** @var ResultSet $data */
$data = $this->data;
$this->data = $this->getIterator($data);
$this->initializeDetailActions();
$this->setDetailUrl(Url::fromPath('icingadb/event'));
}
@ -41,13 +38,15 @@ class NotificationList extends BaseItemList
case 'minimal':
return NotificationListItemMinimal::class;
case 'detailed':
$this->removeAttribute('class', 'default-layout');
return NotificationListItemDetailed::class;
default:
return NotificationListItem::class;
}
}
protected function assemble()
protected function assemble(): void
{
$this->addAttributes(['class' => $this->getViewMode()]);

View file

@ -11,7 +11,7 @@ class NotificationListItemMinimal extends BaseNotificationListItem
{
use ListItemMinimalLayout;
protected function init()
protected function init(): void
{
parent::init();

View file

@ -16,7 +16,7 @@ class ServiceDetailHeader extends ServiceListItemMinimal
return '';
}
protected function assembleVisual(BaseHtmlElement $visual)
protected function assembleVisual(BaseHtmlElement $visual): void
{
if ($this->state->state_type === 'soft') {
$stateType = 'soft_state';
@ -55,7 +55,7 @@ class ServiceDetailHeader extends ServiceListItemMinimal
$visual->addHtml($stateChange);
}
protected function assemble()
protected function assemble(): void
{
$attributes = $this->list->getAttributes();
if (! in_array('minimal', $attributes->get('class')->getValue())) {

View file

@ -17,6 +17,8 @@ class ServiceList extends StateList
case 'minimal':
return ServiceListItemMinimal::class;
case 'detailed':
$this->removeAttribute('class', 'default-layout');
return ServiceListItemDetailed::class;
case 'objectHeader':
return ServiceDetailHeader::class;
@ -25,8 +27,9 @@ class ServiceList extends StateList
}
}
protected function init()
protected function init(): void
{
$this->initializeDetailActions();
$this->setMultiselectUrl(Links::servicesDetails());
$this->setDetailUrl(Url::fromPath('icingadb/service'));
}

View file

@ -27,7 +27,7 @@ class ServiceListItemDetailed extends BaseServiceListItem
return StateBall::SIZE_LARGE;
}
protected function assembleFooter(BaseHtmlElement $footer)
protected function assembleFooter(BaseHtmlElement $footer): void
{
$statusIcons = new HtmlElement('div', Attributes::create(['class' => 'status-icons']));

View file

@ -4,19 +4,48 @@
namespace Icinga\Module\Icingadb\Widget\ItemList;
use Icinga\Module\Icingadb\Common\BaseItemList;
use Icinga\Module\Icingadb\Common\DetailActions;
use Icinga\Module\Icingadb\Common\NoSubjectLink;
use Icinga\Module\Icingadb\Common\ViewMode;
use Icinga\Module\Icingadb\Redis\VolatileStateResults;
use Icinga\Module\Icingadb\Widget\Notice;
use ipl\Html\HtmlDocument;
use ipl\Web\Common\BaseItemList;
abstract class StateList extends BaseItemList
{
use ViewMode;
use NoSubjectLink;
use DetailActions;
protected function assemble()
/** @var bool Whether the list contains at least one item with an icon_image */
protected $hasIconImages = false;
/**
* Get whether the list contains at least one item with an icon_image
*
* @return bool
*/
public function hasIconImages(): bool
{
return $this->hasIconImages;
}
/**
* Set whether the list contains at least one item with an icon_image
*
* @param bool $hasIconImages
*
* @return $this
*/
public function setHasIconImages(bool $hasIconImages): self
{
$this->hasIconImages = $hasIconImages;
return $this;
}
protected function assemble(): void
{
$this->addAttributes(['class' => $this->getViewMode()]);

View file

@ -4,14 +4,15 @@
namespace Icinga\Module\Icingadb\Widget\ItemList;
use Icinga\Module\Icingadb\Common\BaseListItem;
use Icinga\Module\Icingadb\Common\Icons;
use Icinga\Module\Icingadb\Model\State;
use Icinga\Module\Icingadb\Util\PluginOutput;
use Icinga\Module\Icingadb\Widget\CheckAttempt;
use Icinga\Module\Icingadb\Widget\EmptyState;
use Icinga\Module\Icingadb\Widget\IconImage;
use Icinga\Module\Icingadb\Widget\PluginOutputContainer;
use ipl\Html\HtmlElement;
use ipl\Web\Common\BaseListItem;
use ipl\Web\Widget\EmptyState;
use ipl\Web\Widget\TimeSince;
use ipl\Html\BaseHtmlElement;
use ipl\Html\Html;
@ -24,10 +25,13 @@ use ipl\Web\Widget\StateBall;
*/
abstract class StateListItem extends BaseListItem
{
/** @var StateList The list where the item is part of */
protected $list;
/** @var State The state of the item */
protected $state;
protected function init()
protected function init(): void
{
$this->state = $this->item->state;
@ -40,7 +44,25 @@ abstract class StateListItem extends BaseListItem
abstract protected function getStateBallSize(): string;
protected function assembleCaption(BaseHtmlElement $caption)
/**
* @return ?BaseHtmlElement
*/
protected function createIconImage(): ?BaseHtmlElement
{
if (! $this->list->hasIconImages()) {
return null;
}
$iconImage = HtmlElement::create('div', [
'class' => 'icon-image',
]);
$this->assembleIconImage($iconImage);
return $iconImage;
}
protected function assembleCaption(BaseHtmlElement $caption): void
{
if ($this->state->soft_state === null && $this->state->output === null) {
$caption->addHtml(Text::create(t('Waiting for Icinga DB to synchronize the state.')));
@ -55,7 +77,7 @@ abstract class StateListItem extends BaseListItem
}
}
protected function assembleIconImage(BaseHtmlElement $iconImage)
protected function assembleIconImage(BaseHtmlElement $iconImage): void
{
if (isset($this->item->icon_image->icon_image)) {
$iconImage->addHtml(new IconImage($this->item->icon_image->icon_image, $this->item->icon_image_alt));
@ -64,7 +86,7 @@ abstract class StateListItem extends BaseListItem
}
}
protected function assembleTitle(BaseHtmlElement $title)
protected function assembleTitle(BaseHtmlElement $title): void
{
$title->addHtml(Html::sprintf(
t('%s is %s', '<hostname> is <state-text>'),
@ -73,7 +95,7 @@ abstract class StateListItem extends BaseListItem
));
}
protected function assembleVisual(BaseHtmlElement $visual)
protected function assembleVisual(BaseHtmlElement $visual): void
{
$stateBall = new StateBall($this->state->getStateText(), $this->getStateBallSize());
$stateBall->add($this->state->getIcon());
@ -89,7 +111,7 @@ abstract class StateListItem extends BaseListItem
}
}
protected function createTimestamp()
protected function createTimestamp(): ?BaseHtmlElement
{
if ($this->state->is_overdue) {
$since = new TimeSince($this->state->next_update->getTimestamp());
@ -99,14 +121,20 @@ abstract class StateListItem extends BaseListItem
} elseif ($this->state->last_state_change !== null && $this->state->last_state_change->getTimestamp() > 0) {
return new TimeSince($this->state->last_state_change->getTimestamp());
}
return null;
}
protected function assemble()
protected function assemble(): void
{
if ($this->state->is_overdue) {
$this->addAttributes(['class' => 'overdue']);
}
parent::assemble();
$this->add([
$this->createVisual(),
$this->createIconImage(),
$this->createMain()
]);
}
}

View file

@ -4,7 +4,6 @@
namespace Icinga\Module\Icingadb\Widget\ItemTable;
use Icinga\Module\Icingadb\Common\BaseTableRowItem;
use Icinga\Module\Icingadb\Common\Links;
use Icinga\Module\Icingadb\Model\Hostgroup;
use ipl\Html\Attributes;
@ -13,6 +12,7 @@ use ipl\Html\HtmlElement;
use ipl\Html\Text;
use ipl\I18n\Translation;
use ipl\Stdlib\Filter;
use ipl\Web\Common\BaseTableRowItem;
use ipl\Web\Widget\Link;
/**
@ -25,7 +25,7 @@ abstract class BaseHostGroupItem extends BaseTableRowItem
{
use Translation;
protected function init()
protected function init(): void
{
if (isset($this->table)) {
$this->table->addDetailFilterAttribute($this, Filter::equal('name', $this->item->name));

View file

@ -4,7 +4,6 @@
namespace Icinga\Module\Icingadb\Widget\ItemTable;
use Icinga\Module\Icingadb\Common\BaseTableRowItem;
use Icinga\Module\Icingadb\Common\Links;
use Icinga\Module\Icingadb\Model\Servicegroup;
use ipl\Html\Attributes;
@ -13,6 +12,7 @@ use ipl\Html\HtmlElement;
use ipl\Html\Text;
use ipl\I18n\Translation;
use ipl\Stdlib\Filter;
use ipl\Web\Common\BaseTableRowItem;
use ipl\Web\Widget\Link;
/**
@ -25,7 +25,7 @@ abstract class BaseServiceGroupItem extends BaseTableRowItem
{
use Translation;
protected function init()
protected function init(): void
{
if (isset($this->table)) {
$this->table->addDetailFilterAttribute($this, Filter::equal('name', $this->item->name));

View file

@ -17,12 +17,12 @@ trait GridCellLayout
*/
abstract public function createGroupBadge(): Link;
protected function assembleVisual(BaseHtmlElement $visual)
protected function assembleVisual(BaseHtmlElement $visual): void
{
$visual->add($this->createGroupBadge());
}
protected function assembleTitle(BaseHtmlElement $title)
protected function assembleTitle(BaseHtmlElement $title): void
{
$title->addHtml(
$this->createSubject(),
@ -30,7 +30,7 @@ trait GridCellLayout
);
}
protected function assemble()
protected function assemble(): void
{
$this->add([
$this->createTitle()

View file

@ -4,18 +4,21 @@
namespace Icinga\Module\Icingadb\Widget\ItemTable;
use Icinga\Module\Icingadb\Common\BaseItemTable;
use Icinga\Module\Icingadb\Common\DetailActions;
use Icinga\Module\Icingadb\Common\ViewMode;
use ipl\Web\Common\BaseItemTable;
use ipl\Web\Url;
class HostgroupTable extends BaseItemTable
{
use DetailActions;
use ViewMode;
protected $defaultAttributes = ['class' => 'hostgroup-table'];
protected function init()
protected function init(): void
{
$this->initializeDetailActions();
$this->setDetailUrl(Url::fromPath('icingadb/hostgroup'));
}

View file

@ -4,18 +4,21 @@
namespace Icinga\Module\Icingadb\Widget\ItemTable;
use Icinga\Module\Icingadb\Common\BaseItemTable;
use Icinga\Module\Icingadb\Common\DetailActions;
use Icinga\Module\Icingadb\Common\ViewMode;
use ipl\Web\Common\BaseItemTable;
use ipl\Web\Url;
class ServicegroupTable extends BaseItemTable
{
use DetailActions;
use ViewMode;
protected $defaultAttributes = ['class' => 'servicegroup-table'];
protected function init()
protected function init(): void
{
$this->initializeDetailActions();
$this->setDetailUrl(Url::fromPath('icingadb/servicegroup'));
}

View file

@ -4,17 +4,10 @@
namespace Icinga\Module\Icingadb\Widget\ItemTable;
use Icinga\Module\Icingadb\Common\BaseTableRowItem;
use Icinga\Module\Icingadb\Common\Links;
use Icinga\Module\Icingadb\Model\Servicegroup;
use Icinga\Module\Icingadb\Widget\Detail\ServiceStatistics;
use ipl\Html\Attributes;
use ipl\Html\BaseHtmlElement;
use ipl\Html\HtmlDocument;
use ipl\Html\HtmlElement;
use ipl\Html\Text;
use ipl\Stdlib\Filter;
use ipl\Web\Widget\Link;
/**
* Servicegroup item of a servicegroup list. Represents one database row.

View file

@ -4,7 +4,6 @@
namespace Icinga\Module\Icingadb\Widget\ItemTable;
use Icinga\Module\Icingadb\Widget\EmptyState;
use ipl\Html\Attributes;
use ipl\Html\BaseHtmlElement;
use ipl\Html\Form;
@ -14,6 +13,7 @@ use ipl\Html\HtmlString;
use ipl\Orm\Common\SortUtil;
use ipl\Orm\Query;
use ipl\Web\Control\SortControl;
use ipl\Web\Widget\EmptyState;
use ipl\Web\Widget\Icon;
/** @todo Figure out what this might (should) have in common with the new BaseItemTable implementation */

View file

@ -5,13 +5,11 @@
namespace Icinga\Module\Icingadb\Widget\ItemTable;
use Icinga\Module\Icingadb\Common\HostStates;
use Icinga\Module\Icingadb\Common\Icons;
use Icinga\Module\Icingadb\Common\ServiceStates;
use Icinga\Module\Icingadb\Model\Host;
use Icinga\Module\Icingadb\Util\PerfDataSet;
use Icinga\Module\Icingadb\Util\PluginOutput;
use Icinga\Module\Icingadb\Widget\CheckAttempt;
use Icinga\Module\Icingadb\Widget\EmptyState;
use Icinga\Module\Icingadb\Widget\IconImage;
use Icinga\Module\Icingadb\Widget\PluginOutputContainer;
use ipl\Html\Attributes;
@ -19,6 +17,7 @@ use ipl\Html\BaseHtmlElement;
use ipl\Html\HtmlElement;
use ipl\Html\HtmlString;
use ipl\Html\Text;
use ipl\Web\Widget\EmptyState;
use ipl\Web\Widget\Icon;
use ipl\Web\Widget\StateBall;
use ipl\Web\Widget\TimeSince;

View file

@ -9,14 +9,14 @@ use ipl\Html\HtmlDocument;
trait TableRowLayout
{
protected function assembleColumns(HtmlDocument $columns)
protected function assembleColumns(HtmlDocument $columns): void
{
foreach ($this->createStatistics() as $objectStatistic) {
$columns->addHtml($objectStatistic);
}
}
protected function assembleTitle(BaseHtmlElement $title)
protected function assembleTitle(BaseHtmlElement $title): void
{
$title->addHtml(
$this->createSubject(),

View file

@ -4,15 +4,19 @@
namespace Icinga\Module\Icingadb\Widget\ItemTable;
use Icinga\Module\Icingadb\Common\BaseItemTable;
use Icinga\Module\Icingadb\Common\DetailActions;
use ipl\Web\Common\BaseItemTable;
use ipl\Web\Url;
class UserTable extends BaseItemTable
{
use DetailActions;
protected $defaultAttributes = ['class' => 'user-table'];
protected function init()
protected function init(): void
{
$this->initializeDetailActions();
$this->setDetailUrl(Url::fromPath('icingadb/user'));
}

View file

@ -4,7 +4,6 @@
namespace Icinga\Module\Icingadb\Widget\ItemTable;
use Icinga\Module\Icingadb\Common\BaseTableRowItem;
use Icinga\Module\Icingadb\Common\Links;
use Icinga\Module\Icingadb\Model\User;
use ipl\Html\Attributes;
@ -13,6 +12,7 @@ use ipl\Html\HtmlDocument;
use ipl\Html\HtmlElement;
use ipl\Html\Text;
use ipl\Stdlib\Filter;
use ipl\Web\Common\BaseTableRowItem;
use ipl\Web\Widget\Link;
/**
@ -25,14 +25,14 @@ class UserTableRow extends BaseTableRowItem
{
protected $defaultAttributes = ['class' => 'user-table-row'];
protected function init()
protected function init(): void
{
if (isset($this->table)) {
$this->table->addDetailFilterAttribute($this, Filter::equal('name', $this->item->name));
}
}
protected function assembleVisual(BaseHtmlElement $visual)
protected function assembleVisual(BaseHtmlElement $visual): void
{
$visual->addHtml(new HtmlElement(
'div',
@ -41,7 +41,7 @@ class UserTableRow extends BaseTableRowItem
));
}
protected function assembleTitle(BaseHtmlElement $title)
protected function assembleTitle(BaseHtmlElement $title): void
{
$title->addHtml(
isset($this->table)
@ -55,7 +55,7 @@ class UserTableRow extends BaseTableRowItem
);
}
protected function assembleColumns(HtmlDocument $columns)
protected function assembleColumns(HtmlDocument $columns): void
{
}
}

View file

@ -4,15 +4,19 @@
namespace Icinga\Module\Icingadb\Widget\ItemTable;
use Icinga\Module\Icingadb\Common\BaseItemTable;
use Icinga\Module\Icingadb\Common\DetailActions;
use ipl\Web\Common\BaseItemTable;
use ipl\Web\Url;
class UsergroupTable extends BaseItemTable
{
use DetailActions;
protected $defaultAttributes = ['class' => 'usergroup-table'];
protected function init()
protected function init(): void
{
$this->initializeDetailActions();
$this->setDetailUrl(Url::fromPath('icingadb/usergroup'));
}

View file

@ -4,7 +4,6 @@
namespace Icinga\Module\Icingadb\Widget\ItemTable;
use Icinga\Module\Icingadb\Common\BaseTableRowItem;
use Icinga\Module\Icingadb\Common\Links;
use Icinga\Module\Icingadb\Model\Usergroup;
use ipl\Html\Attributes;
@ -13,6 +12,7 @@ use ipl\Html\HtmlDocument;
use ipl\Html\HtmlElement;
use ipl\Html\Text;
use ipl\Stdlib\Filter;
use ipl\Web\Common\BaseTableRowItem;
use ipl\Web\Widget\Link;
/**
@ -25,14 +25,14 @@ class UsergroupTableRow extends BaseTableRowItem
{
protected $defaultAttributes = ['class' => 'usergroup-table-row'];
protected function init()
protected function init(): void
{
if (isset($this->table)) {
$this->table->addDetailFilterAttribute($this, Filter::equal('name', $this->item->name));
}
}
protected function assembleVisual(BaseHtmlElement $visual)
protected function assembleVisual(BaseHtmlElement $visual): void
{
$visual->addHtml(new HtmlElement(
'div',
@ -41,7 +41,7 @@ class UsergroupTableRow extends BaseTableRowItem
));
}
protected function assembleTitle(BaseHtmlElement $title)
protected function assembleTitle(BaseHtmlElement $title): void
{
$title->addHtml(
isset($this->table)
@ -55,7 +55,7 @@ class UsergroupTableRow extends BaseTableRowItem
);
}
protected function assembleColumns(HtmlDocument $columns)
protected function assembleColumns(HtmlDocument $columns): void
{
}
}

View file

@ -9,7 +9,7 @@ use ipl\Html\BaseHtmlElement;
class ServiceStatusBar extends BaseStatusBar
{
protected function assembleTotal(BaseHtmlElement $total)
protected function assembleTotal(BaseHtmlElement $total): void
{
$total->add(sprintf(
tp('%d Service', '%d Services', $this->summary->services_total),

File diff suppressed because it is too large Load diff

View file

@ -1,13 +1,6 @@
// Style
.item-list {
list-style-type: none;
> .empty-state {
.rounded-corners();
background-color: @gray-lighter;
}
.load-more:hover,
.page-separator:hover {
background: none;
@ -50,60 +43,11 @@
// Layout
.item-list {
margin: 0;
padding: 0;
.list-item {
display: flex;
&.load-more a {
flex: 1;
margin: 1.5em 0;
padding: .5em 0;
}
.main {
flex: 1 1 auto;
padding: .5em 0;
width: 0;
margin-left: .5em;
}
.visual {
display: flex;
align-items: center;
flex-direction: column;
}
.caption {
height: 3em;
text-overflow: ellipsis;
overflow: hidden;
.line-clamp();
img {
max-height: 1em;
}
}
header {
display: flex;
align-items: flex-start;
justify-content: space-between;
}
footer {
display: flex;
justify-content: space-between;
}
}
> .empty-state {
margin: 0 1em;
padding: 1em;
text-align: center;
.item-list .list-item {
&.load-more a {
flex: 1;
margin: 1.5em 0;
padding: .5em 0;
}
}
@ -151,31 +95,6 @@
}
}
.item-list:not(.detailed) .list-item {
.title {
display: inline-flex;
align-items: baseline;
white-space: nowrap;
min-width: 0;
> * {
margin: 0 .28125em; // 0 calculated &nbsp; width
&:first-child {
margin-left: 0;
}
&:last-child {
margin-right: 0;
}
}
.subject {
.text-ellipsis();
}
}
}
.item-list.detailed .list-item {
.title {
word-break: break-word;
@ -220,10 +139,6 @@
}
}
.controls .list-item:not(:last-child) {
margin-bottom: .5em;
}
.controls .item-list:not(.detailed):not(.minimal) .list-item {
.plugin-output {
line-height: 1.5

View file

@ -1,104 +0,0 @@
// Style
ul.item-table {
list-style-type: none;
}
div.item-table {
> .empty-state {
.rounded-corners();
background-color: @gray-lighter;
}
}
.table-row {
color: @text-color-light;
.title {
.subject {
color: @text-color;
}
a {
font-weight: bold;
&:hover {
color: @icinga-blue;
text-decoration: none;
}
}
}
}
@media print {
.item-table li.page-break-follows:not(:last-of-type) {
.col {
border-bottom: none;
}
.visual {
margin-bottom: 0;
}
}
}
// Layout
.table-row {
.title {
display: flex;
.visual {
width: 2.5em;
padding: .5em 0;
margin-top: -.5em;
margin-bottom: -.5em;
}
.content {
flex: 1 1 auto;
width: 0;
> * {
.text-ellipsis();
}
}
}
.col {
white-space: nowrap;
}
}
ul.item-table {
display: grid;
> .table-row {
.col:not(.title) {
display: grid;
align-items: center;
}
}
}
ul.item-table {
padding: 0;
margin: 0;
}
div.item-table {
> .empty-state {
margin: 0 1em;
padding: 1em;
text-align: center;
}
}
div.table-row {
display: flex;
column-gap: 1em;
.title {
flex: 1 1 auto;
}
}

View file

@ -1,8 +1,6 @@
// Style
.list-item {
color: @text-color-light;
&.overdue {
background-color: @gray-lighter;
}
@ -18,50 +16,14 @@
color: @text-color-on-icinga-blue;
}
&:not(:first-child) > .main {
border-top: 1px solid @gray-light;
}
&:not(:first-child) .visual {
margin-top: 1px;
}
.caption {
i {
opacity: 0.8;
}
a {
color: @text-color;
}
}
.title {
span.subject,
.state-text {
color: @text-color;
}
.state-text {
text-transform: uppercase;
}
a {
color: @text-color;
font-weight: bold;
&:hover {
color: @icinga-blue;
text-decoration: none;
}
}
}
footer {
&:not(:empty) {
padding-top: .5em;
}
.status-icons {
color: @text-color-light;
@ -72,14 +34,6 @@
}
}
@media print {
.list-item.page-break-follows + .list-item {
.main {
border-top: 1px solid transparent;
}
}
}
// Layout
.list-item {
@ -88,44 +42,18 @@
padding: 0 0.5em;
}
.visual {
padding: .5em 0;
width: 2.5em;
.check-attempt {
margin-top: .5em;
}
.visual .check-attempt {
margin-top: .5em;
}
.caption {
p {
display: inline-block;
}
&.plugin-output, .plugin-output {
font-size: 11/12em;
line-height: 1.5*12/11em;
}
}
.title {
margin-right: 1em;
p {
margin: 0;
}
}
time {
white-space: nowrap;
}
footer {
> * {
font-size: .857em;
line-height: 1.5*.857em;
}
.status-icons {
display: flex;
align-items: center;

View file

@ -1,22 +1,5 @@
/* Icinga DB Web | (c) 2020 Icinga GmbH | GPLv2 */
.line-clamp(@numOfLines: 2) when (@numOfLines > 1) {
display: -webkit-box;
-webkit-line-clamp: @numOfLines;
-webkit-box-orient: vertical;
}
.line-clamp(@numOfLines: 2) when (@numOfLines = "reset") {
display: block; // Would have used "revert", but browser support is still poor and it's not final yet
-webkit-line-clamp: initial;
-webkit-box-orient: initial;
}
.text-ellipsis() {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.monospace() {
font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, monospace;
}