Skip to content

Commit

Permalink
!feat(events-incident-history-improvements): event-bound load more tr…
Browse files Browse the repository at this point in the history
…ait, dynamic result set with soft limit

caution when using: this code is currently under heavy development and might change over the next commits
  • Loading branch information
ncosta-ic committed Apr 16, 2024
1 parent 18a82ba commit d252c3e
Show file tree
Hide file tree
Showing 5 changed files with 398 additions and 27 deletions.
64 changes: 47 additions & 17 deletions application/controllers/IncidentController.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,13 @@
use Icinga\Module\Notifications\Model\Contact;
use Icinga\Module\Notifications\Model\Incident;
use Icinga\Module\Notifications\Model\IncidentHistory;
use Icinga\Module\Notifications\Model\ResultSets\DynamicResultSet;
use Icinga\Module\Notifications\Web\Control\SearchBar\ObjectSuggestions;
use Icinga\Module\Notifications\Widget\Detail\IncidentDetail;
use Icinga\Module\Notifications\Widget\Detail\IncidentQuickActions;
use Icinga\Module\Notifications\Widget\ItemList\ExtendedIncidentHistoryListInfinite;
use Icinga\Module\Notifications\Widget\ItemList\IncidentList;
use ipl\Orm\Query;
use ipl\Stdlib\Filter;
use ipl\Web\Compat\CompatController;
use ipl\Web\Compat\SearchControls;
Expand Down Expand Up @@ -101,15 +103,13 @@ public function historyAction(): void
'schedule',
'channel'
]
);
$compact = $this->view->compact;
)
->setResultSetClass(DynamicResultSet::class);

$compact = $this->view->compact;
$linkedIndex = $this->params->shift('lnkIdx');
$paginationControl = $this->createPaginationControl($history);

// time splitter
/** @var string $time */
$time = $this->params->shift('time', strval(time()));

// create and add controls
$limitControl = $this->createLimitControl();
$sortControl = $this->createSortControl(
Expand All @@ -136,18 +136,22 @@ public function historyAction(): void
$filter = $searchBar->getFilter();
}

// page mangement
// page management
$page = $paginationControl->getCurrentPageNumber();
if ($page > 1 && ! $compact) {
$history->resetOffset();
$history->limit($page * $limitControl->getLimit());
}
$history->limit($page * ($limitControl->getLimit() + 10));
$history->resetOffset();

// restrict query and apply filters
$this->applyRestrictions($history);
$history->filter(Filter::equal('incident.id', $this->id));
$history->filter($filter);
$history->filter(Filter::lessThanOrEqual('time', $time));
if ($linkedIndex && $compact) {
if ($this->calculateListOrder($history) === 'desc') {
$history->filter(Filter::lessThan('id', $linkedIndex));
} else {
$history->filter(Filter::greaterThan('id', $linkedIndex));
}
}
$history->peekAhead();

// add controls
Expand All @@ -166,13 +170,11 @@ public function historyAction(): void
// create and render history list
$list = (new ExtendedIncidentHistoryListInfinite($history))
->setPageSize($limitControl->getLimit())
->setLoadMoreUrl($url->setParam('time', $time));

if ($compact) {
$list->setPageNumber($page);
}
->setLoadMoreUrl($url)
->setMaxPage($page);

if ($compact && $page > 1) {
$list->setPageOffset($page - 1);
$this->document->addFrom($list);
} else {
$this->addContent($list);
Expand All @@ -186,6 +188,34 @@ public function historyAction(): void
$this->getTabs()->activate('history');
}

/**
* Calculates what order the list should be displayed
*
* @param Query $query
*
* @return string
*/
protected function calculateListOrder(Query $query): string
{
$orderBy = $query->getOrderBy();
if ($orderBy === null) {
$sort = $query->getModel()->getDefaultSort();
$rules = [];

if (gettype($sort) === 'array') {
for ($i = 0; $i < sizeof($sort); ++$i) {
$rule = $sort[$i];
$rules[] = array_values(explode(' ', trim($rule)));
}
$orderBy = $rules;
} else {
$orderBy = array_values(explode(' ', trim($sort)));
}
}

return $orderBy[0][1];
}

public function completeAction(): void
{
$suggestions = new ObjectSuggestions();
Expand Down
104 changes: 104 additions & 0 deletions library/Notifications/Common/BoundLoadMore.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
<?php

/* Icinga Notifications Web | (c) 2024 Icinga GmbH | GPLv2 */

namespace Icinga\Module\Notifications\Common;

use BadMethodCallException;
use Icinga\Module\Notifications\Widget\ItemList\PageSeparatorItem;
use Icinga\Module\Notifications\Widget\ShowMore;
use ipl\Html\HtmlDocument;
use ipl\Orm\Model;
use ipl\Web\Common\BaseListItem;
use ipl\Web\Url;

trait BoundLoadMore
{
/** @var ?int */
private $lastPageNumber;

/** @var ?Model */
private $lastData;

/** @var int */
protected $pageSize;

/** @var int */
protected $pageNumber;

/** @var Url */
protected $loadMoreUrl;

/**
* Set the page size
*
* @param int $size
*
* @return $this
*/
public function setPageSize(int $size): self
{
$this->pageSize = $size;

return $this;
}

/**
* Set the url to fetch more items
*
* @param Url $url
*
* @return $this
*/
public function setLoadMoreUrl(Url $url): self
{
$this->loadMoreUrl = $url;

return $this;
}

protected function bind($entryAddEvent, $listAssembledEvent)
{
if (! ($this instanceof HtmlDocument && method_exists($this, 'on'))) {
throw new BadMethodCallException(
"The 'LoadMore' trait can only be bound to classes extending the 'ipl\Html\HtmlDocument' class,"
. "which in turn needs to implement the event emitter methods (e.g the 'Events' trait)."
);
}

$this->on($entryAddEvent, function (BaseListItem $entry, Model $data) {
$this->handleEventEntryAdd($entry, $data);
});
$this->on($listAssembledEvent, function (HtmlDocument $htmlDocument) {
$this->handleEventAssembled($htmlDocument);
});
}

protected function handleEventEntryAdd(BaseListItem $entry, Model $data): void
{
$pageNumber = $this->data->getCurrentPage();
if ($this->lastPageNumber && $this->lastPageNumber !== $pageNumber) {
$this->add(new PageSeparatorItem($pageNumber));
} elseif ($this->lastPageNumber === null && $pageNumber > 1) {
$this->add(new PageSeparatorItem($pageNumber));
}

$this->lastData = $data;
$this->lastPageNumber = $pageNumber;
}

protected function handleEventAssembled(HtmlDocument $htmlDocument): void {
if ($this->lastPageNumber !== null && $this->loadMoreUrl !== null) {
$showMore = (new ShowMore(
$this->data,
$this->loadMoreUrl->setParam('lnkIdx', $this->lastData[$this->data->getLinkedIndex()])
->setParam('page', ($this->lastPageNumber + 1))
->setAnchor('page-' . ($this->lastPageNumber + 1))
))
->setLabel(t('Load More'))
->setAttribute('data-no-icinga-ajax', true);

$this->add($showMore->setTag('li')->addAttributes(['class' => 'list-item']));
}
}
}
Loading

0 comments on commit d252c3e

Please sign in to comment.