Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Show additional daily appointments link #124

Merged
merged 3 commits into from
Oct 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion library/Notifications/Model/Timeperiod.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public function createRelations(Relations $relations)
$relations->hasOne('parent', Schedule::class)
->setCandidateKey('owned_by_schedule_id')
->setJoinType('LEFT');
$relations->hasMany('entry', TimeperiodEntry::class)
$relations->hasMany('timeperiod_entry', TimeperiodEntry::class)
->setJoinType('LEFT');
}
}
34 changes: 31 additions & 3 deletions library/Notifications/Widget/Calendar.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use DateTime;
use Icinga\Module\Notifications\Widget\Calendar\BaseGrid;
use Icinga\Module\Notifications\Widget\Calendar\Controls;
use Icinga\Module\Notifications\Widget\Calendar\DayGrid;
use Icinga\Module\Notifications\Widget\Calendar\Entry;
use Icinga\Module\Notifications\Widget\Calendar\MonthGrid;
use Icinga\Module\Notifications\Widget\Calendar\Util;
Expand All @@ -31,6 +32,9 @@ class Calendar extends BaseHtmlElement
/** @var string Mode to show a specific calendar week */
public const MODE_WEEK = 'week';

/** @var string Mode to show only the day */
public const MODE_DAY = 'day';

protected $tag = 'div';

protected $defaultAttributes = ['class' => 'calendar'];
Expand All @@ -47,6 +51,9 @@ class Calendar extends BaseHtmlElement
/** @var Url */
protected $addEntryUrl;

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

public function setControls(Controls $controls): self
{
$this->controls = $controls;
Expand Down Expand Up @@ -75,6 +82,22 @@ public function getAddEntryUrl(): ?Url
return $this->addEntryUrl;
}

public function setUrl(?Url $url): self
{
$this->url = $url;

return $this;
}

public function prepareDayViewUrl(DateTime $date): Url
{
$url = clone $this->url;
return $url->overwriteParams([
'mode' => 'day',
'day' => $date->format('Y-m-d')
]);
}

protected function getModeStart(): DateTime
{
switch ($this->getControls()->getViewMode()) {
Expand All @@ -83,10 +106,13 @@ protected function getModeStart(): DateTime

return DateTime::createFromFormat('Y-m-d\TH:i:s', $month . '-01T00:00:00');
case self::MODE_WEEK:
default:
$week = $this->getControls()->getValue('week') ?: (new DateTime())->format('Y-\WW');

return (new DateTime())->setTimestamp(strtotime($week));
default:
$day = $this->getControls()->getValue('day') ?: (new DateTime())->format('Y-m-d');

return DateTime::createFromFormat('Y-m-d H:i:s', $day . ' 00:00:00');
}
}

Expand All @@ -95,8 +121,10 @@ public function getGrid(): BaseGrid
if ($this->grid === null) {
if ($this->getControls()->getViewMode() === self::MODE_MONTH) {
$this->grid = new MonthGrid($this, $this->getModeStart());
} else { // $mode === self::MODE_WEEK
} elseif ($this->getControls()->getViewMode() === self::MODE_WEEK) {
$this->grid = new WeekGrid($this, $this->getModeStart());
} else {
$this->grid = new DayGrid($this, $this->getModeStart());
}
}

Expand Down Expand Up @@ -124,7 +152,7 @@ public function getEntries(): Traversable
$length = $start->diff($end);

$visibleHours = Util::diffHours($start, $grid->getGridEnd());
$limit = (int) floor($visibleHours / (Util::diffHours($start, $end) ?: 0.5));
$limit = (int) ceil($visibleHours / (Util::diffHours($start, $end) ?: 0.5));
raviks789 marked this conversation as resolved.
Show resolved Hide resolved
if ($limit > $visibleHours) {
$limit = $visibleHours;
}
Expand Down
47 changes: 42 additions & 5 deletions library/Notifications/Widget/Calendar/BaseGrid.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace Icinga\Module\Notifications\Widget\Calendar;

use DateInterval;
use DateTime;
use DateTimeInterface;
use Icinga\Module\Notifications\Widget\Calendar;
Expand Down Expand Up @@ -35,6 +36,9 @@ abstract class BaseGrid extends BaseHtmlElement
/** @var DateTime */
protected $end;

/** @var array Extra counts stored as [date1 => count1, date2 => count2]*/
protected $extraEntriesCount = [];

/**
* Create a new calendar
*
Expand Down Expand Up @@ -137,6 +141,18 @@ protected function createGridOverlay(): BaseHtmlElement
return $overlay;
}

/**
* Fetch the count of additional entries for the given date
*
* @param DateTime $date
*
* @return int
*/
public function getExtraEntryCount(DateTime $date): int
{
return $this->extraEntriesCount[$date->format('Y-m-d')] ?? 0;
}

protected function assembleGridOverlay(BaseHtmlElement $overlay): void
{
$style = (new Style())->setNonce(Csp::getStyleNonce());
Expand Down Expand Up @@ -218,21 +234,42 @@ protected function assembleGridOverlay(BaseHtmlElement $overlay): void
}
}

$this->extraEntriesCount = [];
foreach ($occupiedCells as $entry) {
$continuation = false;
$rows = $occupiedCells->getInfo();
foreach ($rows as $row => $hours) {
list($rowStart, $rowSpan) = $rowPlacements[spl_object_id($entry)][$row];
$colStart = min($hours);
$colEnd = max($hours);

// Calculate number of entries that are not displayed in the grid for each date
if ($rowStart > $row + $sectionsPerStep) {
// TODO: Register as +1
$startOffset = (int) (($row / $sectionsPerStep) * ($gridBorderAt / 48) + $colStart / 48);
$endOffset = (int) (($row / $sectionsPerStep) * ($gridBorderAt / 48) + $colEnd / 48);
$startDate = (clone $this->getGridStart())->add(new DateInterval("P$startOffset" . 'D'));
$duration = $endOffset - $startOffset;
for ($i = 0; $i <= $duration; $i++) {
$countIdx = $startDate->format('Y-m-d');
if (! isset($this->extraEntriesCount[$countIdx])) {
$this->extraEntriesCount[$countIdx] = 1;
} else {
$this->extraEntriesCount[$countIdx] += 1;
}

$startDate->add(new DateInterval('P1D'));
}

continue;
}
raviks789 marked this conversation as resolved.
Show resolved Hide resolved

$rowEnd = $rowStart + $rowSpan;
$colStart = min($hours) + 1;
$colEnd = max($hours) + 2;
$gridArea = $this->getGridArea(
$rowStart,
$rowStart + $rowSpan,
$colStart + 1,
$colEnd + 2
);

$gridArea = $this->getGridArea($rowStart, $rowEnd, $colStart, $colEnd);
$entryClass = 'area-' . implode('-', $gridArea);

$style->add(".$entryClass", [
Expand Down
10 changes: 9 additions & 1 deletion library/Notifications/Widget/Calendar/Controls.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,18 +37,26 @@ protected function assemble()
]);
break;
case Calendar::MODE_WEEK:
default:
$this->addElement('input', 'week', [
'class' => 'autosubmit',
'type' => 'week',
'value' => (new DateTime())->format('Y-\WW'),
'label' => $this->translate('Calendar Week')
]);
break;
default:
$this->addElement('input', 'day', [
'class' => 'autosubmit',
'type' => 'date',
'value' => (new DateTime())->format('Y-m-d'),
'label' => $this->translate('Date')
]);
break;
}

$modeParam = 'mode';
$options = [
Calendar::MODE_DAY => $this->translate('Day'),
Calendar::MODE_WEEK => $this->translate('Week'),
Calendar::MODE_MONTH => $this->translate('Month')
];
Expand Down
125 changes: 125 additions & 0 deletions library/Notifications/Widget/Calendar/DayGrid.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
<?php

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

namespace Icinga\Module\Notifications\Widget\Calendar;

use DateInterval;
use DateTime;
use InvalidArgumentException;
use ipl\Html\Attributes;
use ipl\Html\BaseHtmlElement;
use ipl\Html\HtmlElement;
use ipl\Html\Text;
use Traversable;

class DayGrid extends BaseGrid
{
public function setGridStart(DateTime $start): BaseGrid
{
if ($start->format('H:i:s') !== '00:00:00') {
throw new InvalidArgumentException('Start is not midnight');
}

return parent::setGridStart($start);
}

protected function getMaximumRowSpan(): int
{
return 28;
}

protected function calculateGridEnd(): DateTime
{
return (clone $this->getGridStart())->add(new DateInterval('P1D'));
}

protected function getNoOfVisuallyConnectedHours(): int
{
return 24;
}

protected function getGridArea(int $rowStart, int $rowEnd, int $colStart, int $colEnd): array
{
return [$colStart, $rowStart, $colEnd, $rowEnd];
}

protected function createGridSteps(): Traversable
{
$interval = new DateInterval('P1D');
$hourStartsAt = clone $this->getGridStart();
for ($i = 0; $i < 24; $i++) {
yield $hourStartsAt;

$hourStartsAt->add($interval);
}
}

protected function createHeader(): BaseHtmlElement
{
$header = new HtmlElement('div', Attributes::create(['class' => 'header']));
$dayNames = [
'Mon' => t('Mon', 'monday'),
'Tue' => t('Tue', 'tuesday'),
'Wed' => t('Wed', 'wednesday'),
'Thu' => t('Thu', 'thursday'),
'Fri' => t('Fri', 'friday'),
'Sat' => t('Sat', 'saturday'),
'Sun' => t('Sun', 'sunday')
];

$currentDay = clone $this->getGridStart();
$interval = new DateInterval('P1D');
$header->addHtml(new HtmlElement(
'div',
Attributes::create(['class' => 'column-title']),
new HtmlElement(
'span',
Attributes::create(['class' => 'day-name']),
Text::create($dayNames[$currentDay->format('D')])
),
new HtmlElement(
'span',
Attributes::create(['class' => 'day-number']),
Text::create($currentDay->format('d'))
)
));

return $header;
}

protected function createSidebar(): BaseHtmlElement
{
$sidebar = new HtmlElement('div', Attributes::create(['class' => 'sidebar']));

$time = (new DateTime())->setTime(0, 0);
$interval = new DateInterval('PT1H');
for ($i = 0; $i < 24; $i++) {
$sidebar->addHtml(new HtmlElement(
'div',
Attributes::create(['class' => 'row-title']),
new HtmlElement(
'span',
Attributes::create(['class' => 'hour']),
Text::create($time->format('H:i'))
)
));

$time->add($interval);
}

return $sidebar;
}

protected function assemble()
{
$this->getAttributes()->add('class', 'day');

$this->addHtml(
$this->createHeader(),
$this->createSidebar(),
$this->createGrid(),
$this->createGridOverlay()
);
}
}
Loading