Skip to content

Decouple time widgets#350

Merged
nilmerg merged 69 commits intomainfrom
decouple-time-widgets
Apr 21, 2026
Merged

Decouple time widgets#350
nilmerg merged 69 commits intomainfrom
decouple-time-widgets

Conversation

@Jan-Schuppik
Copy link
Copy Markdown
Contributor

@Jan-Schuppik Jan-Schuppik commented Jan 8, 2026

This PR removes the direct dependency of the time widgets on Icinga Web (\Icinga\Date\DateFormatter::formatDateTime()) and introduces a native relative-time formatting behavior.

Key differences to the old Icinga Web implementation

Previously the following markup was animated:

<span class="relative-time time-ago" title="2026-04-21 14:44:34">3m4s ago</span>

The new implementation still supports this, but favors the following new markup:

<time class="time-ago" data-relative-time="ago" datetime="2026-04-21T14:44:34" title="2026-04-21 14:44:34">3m4s ago</time>

resolves #341

Comment thread src/Widget/Time.php Outdated
Comment thread src/Widget/Time.php Outdated
Comment thread src/Widget/Time.php Outdated
Copy link
Copy Markdown
Member

@nilmerg nilmerg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Didn't look at JS yet.

Also, add tests for Time and its child classes. Test formatting and rendering.

Comment thread src/Widget/Time.php Outdated
Comment thread src/Widget/Time.php Outdated
Comment thread src/Widget/Time.php Outdated
Comment thread src/Widget/Time.php Outdated
Comment thread src/Widget/Time.php Outdated
Comment thread src/Widget/TimeAgo.php Outdated
Comment thread src/Widget/TimeSince.php Outdated
Comment thread src/Widget/TimeUntil.php Outdated
Comment thread src/Widget/Time.php Outdated
Comment thread src/Widget/Time.php Outdated
Copy link
Copy Markdown
Member

@nilmerg nilmerg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are still no tests!

Comment thread src/Widget/Time.php
Comment thread src/Widget/Time.php
Comment thread src/Widget/Time.php Outdated
Comment thread src/Widget/TimeAgo.php Outdated
Copy link
Copy Markdown
Member

@nilmerg nilmerg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I stopped reading the tests once I saw more than one skip due to when the test is performed. Sorry, but this just non-sense. Tests must always succeed.

In addition, they make too heavy usage of contains and regex assertions. They test a HTML widget, so should assert the HTML structure: $obj actual, $html expected. Other tests exactly work like this and there is even a predefined assertion as part of ipl\Tests\Html\TestCase.

So please refactor your tests accordingly.

Comment thread src/Widget/Time.php
Comment thread src/Widget/Time.php Outdated
Comment thread src/Widget/Time.php Outdated
Comment thread src/Widget/TimeAgo.php Outdated
Comment thread src/Widget/TimeAgo.php Outdated
Comment thread src/Widget/Time.php
Comment thread src/Widget/TimeSince.php
Comment thread src/Widget/TimeUntil.php
Comment thread tests/Widget/TimeAgoTest.php Outdated
Comment thread tests/Widget/TimeTest.php Outdated
@Jan-Schuppik Jan-Schuppik force-pushed the decouple-time-widgets branch 4 times, most recently from 65cf226 to 7add9f3 Compare March 23, 2026 12:48
Copy link
Copy Markdown
Contributor

@BastianLedererIcinga BastianLedererIcinga left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see my icingadb-web PR is still not entirely compatible with your changes, since I see no proper way to include a data-ago-label in Time widgets, which is required for the switch from absolute to relative. Let's discuss a solution and this time document the agreed approach in this PR.

Comment thread asset/js/behavior/RelativeTimeBehavior.js Outdated
Comment thread asset/js/widget/RelativeTime.js Outdated
Comment thread asset/js/widget/RelativeTime.js Outdated
Comment thread tests/Widget/TimeAgoTest.php Outdated
Copy link
Copy Markdown
Member

@nilmerg nilmerg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@BastianLedererIcinga Please take over now, as @Jan-Schuppik is already occupied for the coming weeks and I want to finish this soon.

Don't hesitate to let Claude refactor the tests 😉

Comment thread src/Widget/TimeAgo.php Outdated
Comment thread src/Widget/TimeSince.php Outdated
Comment thread src/Widget/TimeUntil.php Outdated
Comment thread composer.json Outdated
Comment thread asset/js/widget/RelativeTime.js Outdated
Comment thread asset/js/widget/RelativeTime.js Outdated
Comment thread asset/js/behavior/RelativeTimeBehavior.js Outdated
Comment thread asset/js/widget/RelativeTime.js Outdated
Comment thread src/Widget/TimeAgo.php Outdated
Comment thread src/Widget/TimeSince.php Outdated
Comment thread src/Widget/TimeUntil.php Outdated
Comment thread asset/js/behavior/RelativeTimeBehavior.js Outdated
Comment thread asset/js/behavior/RelativeTimeBehavior.js Outdated
Comment thread asset/js/RelativeTime.js
Comment thread asset/js/RelativeTime.js Outdated
Comment thread asset/js/RelativeTime.js Outdated
Comment thread asset/js/RelativeTime.js Outdated
Comment thread asset/js/RelativeTime.js Outdated
@nilmerg nilmerg added this to the 0.14.0 milestone Apr 17, 2026
Comment thread asset/js/RelativeTime.js Outdated
Comment thread asset/js/behavior/RelativeTimeBehavior.js Outdated
Comment thread asset/js/RelativeTime.js Outdated
Comment thread asset/js/RelativeTime.js Outdated
Copy link
Copy Markdown
Member

@nilmerg nilmerg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you both!

@sukhwinder33445 sukhwinder33445 removed their request for review April 21, 2026 13:45
Jan-Schuppik and others added 26 commits April 21, 2026 15:45
Allow the Time widget to accept a custom IntlDateFormatter instance,
enabling locale-aware and customizable time formatting. Falls back to
the default formatted datetime string when no formatter is set.

Also declare the ext-intl PHP extension as an explicit dependency in
composer.json.
PHPStan checks that the values in specified keys have the correct types.
source: https://phpstan.org/writing-php-code/phpdoc-types#array-shapes
Remove the separate assemble() override in TimeAgo, TimeSince and
TimeUntil. Attribute setup and text formatting are now handled entirely
within format(), eliminating the duplicate diff() call and reducing the
number of methods subclasses need to override.
…ocks

Replace \Exception with the imported Exception class across Time and its
subclasses, and add the missing Exception import and @throws annotation
to Time::relative().
Previously, Time::diff() and Time::relative() always used new DateTime()
as the reference point, making deterministic unit tests impossible.

Introduce an optional $compareTime parameter throughout the widget family
so callers can inject an explicit reference time:

- Time::diff() accepts ?DateTime $compareTime instead of computing "now"
  internally; Time::relative() forwards it to TimeAgo/TimeUntil.
- TimeAgo, TimeSince, and TimeUntil store the injected time in the new
  Time::$compareTime property.
- Year/day comparisons using date('Y')/date('d') are replaced by the new
  isSameByFormat() helper, removing the last implicit "now" dependencies.
- data-relative-time attributes are moved to $defaultAttributes, removing
  duplicate code from format() methods.
- Fix inverted prefix logic in TimeUntil: only prepend '-' when invert
  is 0 and the interval is non-zero.
- Move all test classes out of namespace blocks into proper ipl\Tests\Web\Widget namespace
- Extend TestCase instead of PHPUnit\Framework\TestCase directly
- Initialize StaticTranslator with NoopTranslator in setUp() to avoid translation side effects
- Consolidate redundant constructor tests (int/float/DateTime variants) into fewer, clearer cases
- Rename test methods to focus on observable behavior rather than input type (e.g. testConstructorAcceptsIntTimestamp → testConstructorAcceptsTimestamp)
- Add $compareTime parameter usage to pin time in tests for deterministic results
Add a new test case and fix intentation of heredoc
Scan for new relative time elements on `rendered` and track existing ones.
Use `setInterval` instead of the `icinga.timer`.
Since `Translation` is used in the `Time` class already it can be dropped
from the subclasses.
Tests are adjusted to match the new type of `$compareTime`.
- Make `DYNAMIC_RELATIVE_TIME_THRESHOLD` a class property
- Remove underscores from method names
- Simplify `getTimeDifferenceInSeconds`
- Add missing space after negation
Support `.span.time-ago` etc. aswell as the new data attributes.

The condition for the swap from until to ago is made more reliable.
@nilmerg nilmerg force-pushed the decouple-time-widgets branch from 720fae3 to 9fb079c Compare April 21, 2026 13:46
@nilmerg nilmerg merged commit dde4c73 into main Apr 21, 2026
14 checks passed
@nilmerg nilmerg deleted the decouple-time-widgets branch April 21, 2026 13:51
nilmerg added a commit to Icinga/icingaweb2 that referenced this pull request Apr 21, 2026
This PR removes the Javascript function that updates relative times.

refs: Icinga/ipl-web#341

Depends on:
- Icinga/ipl-web#350
(ipl-web handles the time refreshing via javascript now)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Decouple TimeAgo, TimeUntil and TimeSince from Icinga Web

4 participants