diff --git a/application/controllers/ScheduleController.php b/application/controllers/ScheduleController.php index 90b84ac6c..e2c8f9e40 100644 --- a/application/controllers/ScheduleController.php +++ b/application/controllers/ScheduleController.php @@ -11,7 +11,10 @@ use Icinga\Module\Notifications\Forms\ScheduleForm; use Icinga\Module\Notifications\Model\Schedule; use Icinga\Module\Notifications\Widget\RecipientSuggestions; +use Icinga\Module\Notifications\Util\ScheduleDateTimeFactory; +use Icinga\Module\Notifications\Web\Control\TimezonePicker; use Icinga\Module\Notifications\Widget\Detail\ScheduleDetail; +use Icinga\Module\Notifications\Widget\TimezoneWarning; use ipl\Html\Form; use ipl\Html\Html; use ipl\Stdlib\Filter; @@ -47,11 +50,24 @@ public function indexAction(): void $this->controls->addAttributes(['class' => 'schedule-detail-controls']); + $timezonePicker = $this->createTimezonePicker($schedule->timezone); + $this->controls->addHtml($timezonePicker); + $scheduleControls = (new ScheduleDetail\Controls()) ->setAction(Url::fromRequest()->getAbsoluteUrl()) ->populate(['mode' => $this->params->get('mode')]) ->on(Form::ON_SUCCESS, function (ScheduleDetail\Controls $controls) use ($id) { - $this->redirectNow(Links::schedule($id)->with(['mode' => $controls->getMode()])); + $redirectUrl = Links::schedule($id)->with(['mode' => $controls->getMode()]); + $requestUrl = Url::fromRequest(); + if ($requestUrl->getParam('mode') !== $controls->getValue('mode')) { + $defaultTimezoneParam = TimezonePicker::DEFAULT_TIMEZONE_PARAM; + if ($requestUrl->hasParam($defaultTimezoneParam)) { + $redirectUrl->addParams( + [$defaultTimezoneParam => $requestUrl->getParam($defaultTimezoneParam)] + ); + } + $this->redirectNow($redirectUrl); + } }) ->handleRequest($this->getServerRequest()); @@ -91,6 +107,7 @@ public function addAction(): void { $this->setTitle($this->translate('New Schedule')); $form = (new ScheduleForm(Database::get())) + ->setShowTimezoneDropdown() ->setAction($this->getRequest()->getUrl()->getAbsoluteUrl()) ->on(Form::ON_SUCCESS, function (ScheduleForm $form) { $scheduleId = $form->addSchedule(); @@ -107,9 +124,16 @@ public function addAction(): void public function addRotationAction(): void { $scheduleId = (int) $this->params->getRequired('schedule'); + $displayTimezone = $this->params->get('display_timezone'); $this->setTitle($this->translate('Add Rotation')); - $form = new RotationConfigForm($scheduleId, Database::get()); + $scheduleTimezone = $this->getScheduleTimezone($scheduleId); + + if ($displayTimezone !== $scheduleTimezone) { + $this->addContent(new TimezoneWarning($scheduleTimezone)); + } + + $form = new RotationConfigForm($scheduleId, Database::get(), $displayTimezone); $form->setAction($this->getRequest()->getUrl()->setParam('showCompact')->getAbsoluteUrl()); $form->setSuggestionUrl(Url::fromPath('notifications/schedule/suggest-recipient')); $form->on(RotationConfigForm::ON_SENT, function ($form) { @@ -139,10 +163,17 @@ public function addRotationAction(): void public function editRotationAction(): void { $id = (int) $this->params->getRequired('id'); + $displayTimezone = $this->params->get('display_timezone'); $scheduleId = (int) $this->params->getRequired('schedule'); $this->setTitle($this->translate('Edit Rotation')); - $form = new RotationConfigForm($scheduleId, Database::get()); + $scheduleTimezone = $this->getScheduleTimezone($scheduleId); + + if ($displayTimezone !== $scheduleTimezone) { + $this->addContent(new TimezoneWarning($scheduleTimezone)); + } + + $form = new RotationConfigForm($scheduleId, Database::get(), $displayTimezone); $form->disableModeSelection(); $form->setShowRemoveButton(); $form->loadRotation($id); @@ -203,4 +234,48 @@ public function suggestRecipientAction(): void $this->getDocument()->addHtml($suggestions); } + + /** + * Get the timezone of a schedule + * + * @param int $scheduleId The ID of the schedule + * + * @return string The timezone of the schedule + */ + protected function getScheduleTimezone(int $scheduleId): string + { + return Schedule::on(Database::get()) + ->filter(Filter::equal('schedule.id', $scheduleId)) + ->first() + ->timezone; + } + + /** + * Create a timezone picker control + * + * @param string $defaultTimezone The default timezone to use if none is set in the request + * + * @return TimezonePicker The timezone picker control + */ + protected function createTimezonePicker(string $defaultTimezone): TimezonePicker + { + $defaultTimezoneParam = TimezonePicker::DEFAULT_TIMEZONE_PARAM; + $timezoneParam = $this->params->shift($defaultTimezoneParam); + + ScheduleDateTimeFactory::setDisplayTimezone($timezoneParam ?? $defaultTimezone); + + return (new TimezonePicker()) + ->populate([$defaultTimezoneParam => $timezoneParam ?? $defaultTimezone]) + ->on( + TimezonePicker::ON_SUBMIT, + function (TimezonePicker $timezonePicker) use ($defaultTimezoneParam) { + $requestUrl = Url::fromRequest(); + if ($requestUrl->getParam($defaultTimezoneParam) !== $timezonePicker->getValue($defaultTimezoneParam)) { + $this->redirectNow($requestUrl->with([ + $defaultTimezoneParam => $timezonePicker->getValue($defaultTimezoneParam) + ])); + } + } + )->handleRequest($this->getServerRequest()); + } } diff --git a/application/controllers/SchedulesController.php b/application/controllers/SchedulesController.php index 2a022da6c..a9c212486 100644 --- a/application/controllers/SchedulesController.php +++ b/application/controllers/SchedulesController.php @@ -4,16 +4,12 @@ namespace Icinga\Module\Notifications\Controllers; -use DateTime; use Icinga\Module\Notifications\Common\Database; use Icinga\Module\Notifications\Common\Links; use Icinga\Module\Notifications\Model\Schedule; use Icinga\Module\Notifications\View\ScheduleRenderer; use Icinga\Module\Notifications\Web\Control\SearchBar\ObjectSuggestions; use Icinga\Module\Notifications\Widget\ItemList\ObjectList; -use Icinga\Module\Notifications\Widget\TimeGrid\DaysHeader; -use ipl\Html\Attributes; -use ipl\Html\HtmlElement; use ipl\Stdlib\Filter; use ipl\Web\Compat\CompatController; use ipl\Web\Compat\SearchControls; @@ -78,12 +74,6 @@ public function indexAction(): void ))->openInModal() ); - $this->addContent(new HtmlElement( - 'div', - Attributes::create(['class' => 'schedules-header']), - new DaysHeader((new DateTime())->setTime(0, 0), 7) - )); - $this->addContent(new ObjectList($schedules, new ScheduleRenderer())); if (! $searchBar->hasBeenSubmitted() && $searchBar->hasBeenSent()) { diff --git a/application/forms/RotationConfigForm.php b/application/forms/RotationConfigForm.php index b6cf9b8f7..fb34aa412 100644 --- a/application/forms/RotationConfigForm.php +++ b/application/forms/RotationConfigForm.php @@ -6,6 +6,7 @@ use DateInterval; use DateTime; +use DateTimeZone; use Generator; use Icinga\Exception\ConfigurationError; use Icinga\Exception\Http\HttpNotFoundException; @@ -13,6 +14,7 @@ use Icinga\Module\Notifications\Model\Contact; use Icinga\Module\Notifications\Model\Contactgroup; use Icinga\Module\Notifications\Model\Rotation; +use Icinga\Module\Notifications\Model\Schedule; use Icinga\Module\Notifications\Model\TimeperiodEntry; use Icinga\Util\Json; use Icinga\Web\Session; @@ -78,6 +80,9 @@ class RotationConfigForm extends CompatForm /** @var int The rotation id */ protected $rotationId; + /** @var string The timezone to display the timeline in */ + protected $displayTimezone; + /** * Set the label for the submit button * @@ -185,11 +190,13 @@ public function hasBeenWiped(): bool * * @param int $scheduleId * @param Connection $db + * @param string $displayTimezone */ - public function __construct(int $scheduleId, Connection $db) + public function __construct(int $scheduleId, Connection $db, string $displayTimezone) { $this->db = $db; $this->scheduleId = $scheduleId; + $this->displayTimezone = $displayTimezone; } /** @@ -800,9 +807,10 @@ protected function assemblePartialDayOptions(FieldsetElement $options): DateTime ]); $selectedFromTime = $from->getValue(); + $nextDayTimeOptions = []; foreach ($timeOptions as $key => $value) { - unset($timeOptions[$key]); // unset to re-add it at the end of array - $timeOptions[$key] = sprintf('%s (%s)', $value, $this->translate('Next Day')); + unset($timeOptions[$key]); + $nextDayTimeOptions[$key] = $value; if ($selectedFromTime === $key) { break; @@ -811,7 +819,9 @@ protected function assemblePartialDayOptions(FieldsetElement $options): DateTime $to = $options->createElement('select', 'to', [ 'required' => true, - 'options' => $timeOptions + 'options' => empty($timeOptions) + ? ['Next Day' => $nextDayTimeOptions] + : ['Today' => $timeOptions, 'Next Day' => $nextDayTimeOptions] ]); $options->registerElement($to); @@ -1145,7 +1155,8 @@ function ($value, $validator) use ($earliestHandoff, $firstHandoff, $latestHando (new \IntlDateFormatter( \Locale::getDefault(), \IntlDateFormatter::MEDIUM, - \IntlDateFormatter::SHORT + \IntlDateFormatter::SHORT, + $this->getScheduleTimezone() ))->format($actualFirstHandoff) ); } @@ -1270,7 +1281,8 @@ private function parseDateAndTime(?string $date = null, ?string $time = null): D return (new DateTime())->setTime(0, 0); } - $datetime = DateTime::createFromFormat($format, $expression); + $datetime = DateTime::createFromFormat($format, $expression, new DateTimeZone($this->getScheduleTimezone())); + if ($datetime === false) { $datetime = (new DateTime())->setTime(0, 0); } elseif ($time === null) { @@ -1293,12 +1305,25 @@ private function getTimeOptions(): array \IntlDateFormatter::SHORT ); + $dtzFormatter = new \IntlDateFormatter( + \Locale::getDefault(), + \IntlDateFormatter::NONE, + \IntlDateFormatter::SHORT, + $this->displayTimezone + ); + $options = []; - $dt = new DateTime(); + $dt = new DateTime('now', new DateTimeZone($this->getScheduleTimezone())); for ($hour = 0; $hour < 24; $hour++) { for ($minute = 0; $minute < 60; $minute += 30) { $dt->setTime($hour, $minute); - $options[$dt->format('H:i')] = $formatter->format($dt); + $dtzDt = (clone $dt)->setTimezone(new DateTimeZone($this->displayTimezone)); + + $options[$dt->format('H:i')] = sprintf( + '%s (%s)', + $formatter->format($dt), + $dtzFormatter->format($dtzDt) + ); } } @@ -1665,4 +1690,17 @@ public function hasChanges(): bool return ! empty(array_udiff_assoc($values, $dbValuesToCompare, $checker)); } + + /** + * Get the timezone of the schedule + * + * @return string The timezone identifier + */ + protected function getScheduleTimezone(): string + { + return Schedule::on(Database::get()) + ->filter(Filter::equal('id', $this->scheduleId)) + ->first() + ->timezone; + } } diff --git a/application/forms/ScheduleForm.php b/application/forms/ScheduleForm.php index e3782e48c..d75ae8f2a 100644 --- a/application/forms/ScheduleForm.php +++ b/application/forms/ScheduleForm.php @@ -5,6 +5,7 @@ namespace Icinga\Module\Notifications\Forms; use DateTime; +use DateTimeZone; use Icinga\Exception\Http\HttpNotFoundException; use Icinga\Module\Notifications\Model\Rotation; use Icinga\Module\Notifications\Model\RuleEscalationRecipient; @@ -29,6 +30,9 @@ class ScheduleForm extends CompatForm /** @var bool */ protected $showRemoveButton = false; + /** @var bool */ + protected $showTimezoneDropdown = false; + /** @var Connection */ private $db; @@ -59,6 +63,20 @@ public function setShowRemoveButton(bool $state = true): self return $this; } + /** + * Set whether to show the timezone dropdown or not + * + * @param bool $state If true, the timezone dropdown will be shown (defaults to true) + * + * @return $this + */ + public function setShowTimezoneDropdown(bool $state = true): self + { + $this->showTimezoneDropdown = $state; + + return $this; + } + public function hasBeenRemoved(): bool { $btn = $this->getPressedSubmitElement(); @@ -78,7 +96,8 @@ public function addSchedule(): int return $this->db->transaction(function (Connection $db) { $db->insert('schedule', [ 'name' => $this->getValue('name'), - 'changed_at' => (int) (new DateTime())->format("Uv") + 'changed_at' => (int) (new DateTime())->format("Uv"), + 'timezone' => $this->getValue('timezone') ]); return $db->lastInsertId(); @@ -175,6 +194,16 @@ protected function assemble() 'placeholder' => $this->translate('e.g. working hours, on call, etc ...') ]); + if ($this->showTimezoneDropdown) { + $this->addElement('select', 'timezone', [ + 'required' => true, + 'label' => $this->translate('Schedule Timezone'), + 'description' => $this->translate('Select the time zone in which this schedule operates.'), + 'multiOptions' => array_combine(DateTimeZone::listIdentifiers(), DateTimeZone::listIdentifiers()), + 'value' => date_default_timezone_get(), + ]); + } + $this->addElement('submit', 'submit', [ 'label' => $this->getSubmitLabel() ]); diff --git a/library/Notifications/Common/Links.php b/library/Notifications/Common/Links.php index 3773f8589..de23859cc 100644 --- a/library/Notifications/Common/Links.php +++ b/library/Notifications/Common/Links.php @@ -4,6 +4,7 @@ namespace Icinga\Module\Notifications\Common; +use Icinga\Module\Notifications\Util\ScheduleDateTimeFactory; use ipl\Web\Url; /** @@ -118,12 +119,19 @@ public static function contactGroupEdit(int $id): Url public static function rotationAdd(int $scheduleId): Url { - return Url::fromPath('notifications/schedule/add-rotation', ['schedule' => $scheduleId]); + return Url::fromPath('notifications/schedule/add-rotation', [ + 'schedule' => $scheduleId, + 'display_timezone' => ScheduleDateTimeFactory::getDisplayTimezone()->getName() + ]); } public static function rotationSettings(int $id, int $scheduleId): Url { - return Url::fromPath('notifications/schedule/edit-rotation', ['id' => $id, 'schedule' => $scheduleId]); + return Url::fromPath('notifications/schedule/edit-rotation', [ + 'id' => $id, + 'schedule' => $scheduleId, + 'display_timezone' => ScheduleDateTimeFactory::getDisplayTimezone()->getName() + ]); } public static function moveRotation(): Url diff --git a/library/Notifications/Model/Schedule.php b/library/Notifications/Model/Schedule.php index c3f82339c..af1aef4e3 100644 --- a/library/Notifications/Model/Schedule.php +++ b/library/Notifications/Model/Schedule.php @@ -15,6 +15,7 @@ /** * @property int $id * @property string $name + * @property string $timezone * @property DateTime $changed_at * @property bool $deleted * @@ -39,6 +40,7 @@ public function getColumns(): array return [ 'name', 'changed_at', + 'timezone', 'deleted' ]; } @@ -47,7 +49,8 @@ public function getColumnDefinitions(): array { return [ 'name' => t('Name'), - 'changed_at' => t('Changed At') + 'changed_at' => t('Changed At'), + 'timezone' => t('Timezone') ]; } diff --git a/library/Notifications/Util/ScheduleDateTimeFactory.php b/library/Notifications/Util/ScheduleDateTimeFactory.php new file mode 100644 index 000000000..9df1dfe1c --- /dev/null +++ b/library/Notifications/Util/ScheduleDateTimeFactory.php @@ -0,0 +1,54 @@ + */ @@ -41,23 +36,6 @@ public function assembleTitle($item, HtmlDocument $title, string $layout): void public function assembleCaption($item, HtmlDocument $caption, string $layout): void { - // Number of days is set to 7, since default mode for schedule is week - // and the start day should be the current day - $timeline = (new Timeline($item->id, (new DateTime())->setTime(0, 0), 7)) - ->minimalLayout() - ->setStyle( - (new Style()) - ->setNonce(Csp::getStyleNonce()) - ->setModule('notifications') - ); - - $rotations = $item->rotation->with('timeperiod')->orderBy('first_handoff', SORT_DESC); - - foreach ($rotations as $rotation) { - $timeline->addRotation(new Rotation($rotation)); - } - - $caption->addHtml($timeline); } public function assembleExtendedInfo($item, HtmlDocument $info, string $layout): void diff --git a/library/Notifications/Web/Control/TimezonePicker.php b/library/Notifications/Web/Control/TimezonePicker.php new file mode 100644 index 000000000..13c4f9ca8 --- /dev/null +++ b/library/Notifications/Web/Control/TimezonePicker.php @@ -0,0 +1,32 @@ + 'timezone-picker']; + + public function assemble(): void + { + $this->addElement('select', static::DEFAULT_TIMEZONE_PARAM, + [ + 'class' => 'autosubmit', + 'label' => 'Display Timezone', + 'options' => array_combine(DateTimeZone::listIdentifiers(), DateTimeZone::listIdentifiers())] + ); + $select = $this->getElement(static::DEFAULT_TIMEZONE_PARAM); + $select->prependWrapper(HtmlElement::create('div', ['class' => 'icinga-controls'])); + } +} diff --git a/library/Notifications/Widget/Detail/ScheduleDetail/Controls.php b/library/Notifications/Widget/Detail/ScheduleDetail/Controls.php index 398566da3..f1ed32231 100644 --- a/library/Notifications/Widget/Detail/ScheduleDetail/Controls.php +++ b/library/Notifications/Widget/Detail/ScheduleDetail/Controls.php @@ -5,6 +5,7 @@ namespace Icinga\Module\Notifications\Widget\Detail\ScheduleDetail; use DateTime; +use Icinga\Module\Notifications\Util\ScheduleDateTimeFactory; use Icinga\Web\Session; use ipl\Html\Attributes; use ipl\Html\Form; @@ -62,7 +63,7 @@ public function getNumberOfDays(): int */ public function getStartDate(): DateTime { - return (new DateTime())->setTime(0, 0); + return ScheduleDateTimeFactory::createDateTime()->setTime(0, 0); } protected function onSuccess() diff --git a/library/Notifications/Widget/TimeGrid/DaysHeader.php b/library/Notifications/Widget/TimeGrid/DaysHeader.php index 0633fbfa4..9ec3756e7 100644 --- a/library/Notifications/Widget/TimeGrid/DaysHeader.php +++ b/library/Notifications/Widget/TimeGrid/DaysHeader.php @@ -6,6 +6,7 @@ use DateInterval; use DateTime; +use Icinga\Module\Notifications\Util\ScheduleDateTimeFactory; use IntlDateFormatter; use ipl\Html\Attributes; use ipl\Html\BaseHtmlElement; @@ -53,7 +54,7 @@ public function assemble(): void ]; $interval = new DateInterval('P1D'); - $today = (new DateTime())->setTime(0, 0); + $today = ScheduleDateTimeFactory::createDateTime()->setTime(0, 0); $time = clone $this->startDay; $dateFormatter = new IntlDateFormatter( Locale::getDefault(), diff --git a/library/Notifications/Widget/Timeline.php b/library/Notifications/Widget/Timeline.php index 368fa42e9..cd6bfda3b 100644 --- a/library/Notifications/Widget/Timeline.php +++ b/library/Notifications/Widget/Timeline.php @@ -8,6 +8,7 @@ use DateTime; use Icinga\Module\Notifications\Common\Links; use Icinga\Module\Notifications\Forms\MoveRotationForm; +use Icinga\Module\Notifications\Util\ScheduleDateTimeFactory; use Icinga\Module\Notifications\Widget\TimeGrid\DynamicGrid; use Icinga\Module\Notifications\Widget\TimeGrid\EntryProvider; use Icinga\Module\Notifications\Widget\TimeGrid\GridStep; @@ -356,10 +357,11 @@ protected function assemble() $dateFormatter = new IntlDateFormatter( Locale::getDefault(), IntlDateFormatter::NONE, - IntlDateFormatter::SHORT + IntlDateFormatter::SHORT, + ScheduleDateTimeFactory::getDisplayTimezone() ); - $now = new DateTime(); + $now = ScheduleDateTimeFactory::createDateTime(); $currentTime = new HtmlElement( 'div', new Attributes(['class' => 'time-hand']), diff --git a/library/Notifications/Widget/Timeline/Entry.php b/library/Notifications/Widget/Timeline/Entry.php index 859bb605b..00bcb163f 100644 --- a/library/Notifications/Widget/Timeline/Entry.php +++ b/library/Notifications/Widget/Timeline/Entry.php @@ -4,9 +4,10 @@ namespace Icinga\Module\Notifications\Widget\Timeline; +use Icinga\Module\Notifications\Util\ScheduleDateTimeFactory; +use Icinga\Module\Notifications\Widget\TimeGrid; use ipl\Html\Attributes; use ipl\Html\BaseHtmlElement; -use Icinga\Module\Notifications\Widget\TimeGrid; use ipl\Html\HtmlElement; use ipl\Html\Text; use ipl\Web\Widget\Icon; @@ -57,7 +58,12 @@ protected function assembleContainer(BaseHtmlElement $container): void $dateType = \IntlDateFormatter::SHORT; } - $formatter = new \IntlDateFormatter(\Locale::getDefault(), $dateType, $timeType); + $formatter = new \IntlDateFormatter( + \Locale::getDefault(), + $dateType, + $timeType, + ScheduleDateTimeFactory::getDisplayTimezone() + ); $container->addAttributes([ 'title' => sprintf( diff --git a/library/Notifications/Widget/Timeline/Rotation.php b/library/Notifications/Widget/Timeline/Rotation.php index 536dbc063..bba961ee7 100644 --- a/library/Notifications/Widget/Timeline/Rotation.php +++ b/library/Notifications/Widget/Timeline/Rotation.php @@ -6,9 +6,11 @@ use DateInterval; use DateTime; +use DateTimeZone; use Generator; use Icinga\Module\Notifications\Common\Links; use Icinga\Module\Notifications\Forms\RotationConfigForm; +use Icinga\Module\Notifications\Util\ScheduleDateTimeFactory; use ipl\Scheduler\RRule; use ipl\Stdlib\Filter; use Recurr\Frequency; @@ -115,10 +117,12 @@ public function fetchTimeperiodEntries(DateTime $after, DateTime $until): Genera } } // TODO: Yearly? (Those unoptimized single occurrences) - $before = (clone $after)->setTime( - (int) $timeperiodEntry->start_time->format('H'), - (int) $timeperiodEntry->start_time->format('i') - ); + $before = (clone $after) + ->setTimezone(new DateTimeZone($this->model->schedule->execute()->current()->timezone)) + ->setTime( + (int) $timeperiodEntry->start_time->format('H'), + (int) $timeperiodEntry->start_time->format('i') + ); if ($timeperiodEntry->start_time < $before) { $daysSinceLatestHandoff = $timeperiodEntry->start_time->diff($before)->days % $interval; @@ -133,6 +137,7 @@ public function fetchTimeperiodEntries(DateTime $after, DateTime $until): Genera $length = $timeperiodEntry->start_time->diff($timeperiodEntry->end_time); $limit = (((int) ceil($after->diff($until)->days / $interval)) + 1) * $limitMultiplier; foreach ($rrule->getNextRecurrences($firstHandoff, $limit) as $recurrence) { + $recurrence = ScheduleDateTimeFactory::createDateTime('@' . $recurrence->getTimestamp()); $recurrenceEnd = (clone $recurrence)->add($length); if ($recurrence < $actualHandoff && $recurrenceEnd > $actualHandoff) { $recurrence = $actualHandoff; diff --git a/library/Notifications/Widget/TimezoneWarning.php b/library/Notifications/Widget/TimezoneWarning.php new file mode 100644 index 000000000..604ec5911 --- /dev/null +++ b/library/Notifications/Widget/TimezoneWarning.php @@ -0,0 +1,38 @@ + 'timezone-warning'] + ) { + } + + public function assemble(): void + { + $this->addHtml(new Icon('warning')); + $this->addHtml(new HtmlElement( + 'p', + null, + new Text($this->translate('The schedule\'s timezone is ')), + new HtmlElement('strong', null, new Text($this->timezone)) + )); + } +} diff --git a/public/css/form.less b/public/css/form.less index de5e13163..86455e519 100644 --- a/public/css/form.less +++ b/public/css/form.less @@ -88,6 +88,15 @@ } } +.timezone-picker { + display: inline; + margin-left: 1em; + + .icinga-controls { + display: inline; + } +} + /* Style */ .icinga-controls { diff --git a/public/css/schedule.less b/public/css/schedule.less index 01a5a1797..c497257cb 100644 --- a/public/css/schedule.less +++ b/public/css/schedule.less @@ -67,6 +67,25 @@ } } +.timezone-warning { + display: flex; + align-items: center; + justify-content: center; + column-gap: 1em; + + width: fit-content; + margin: 0 auto 1em auto; + padding: .5em 1em; + + i.icon:before { + margin-right: 0; + } + + p { + margin: 0; + } +} + /* Design */ .schedule-detail .entry.highlighted { @@ -85,3 +104,13 @@ padding: .5em; color: @text-color-light; } + +.timezone-warning { + border: 1px solid @color-warning; + border-radius: .25em; + + i.icon { + color: @color-warning; + font-size: 1.5em; + } +}