Controller: Add timestamp preference handling

Introduce `createTimestampControl()` which returns a `TimestampToggle`.
The current mode is resolved from the URL param, the user's session
or the stored preferences and is saved on submit of the toggle.

The saving of view-modes is adjusted so it does not overwrite
the new `icingadb.timestamps` key in the preferences.
This commit is contained in:
Bastian Lederer 2026-04-23 09:38:37 +02:00
parent d6d0d2190a
commit c927e7ef74

View file

@ -11,11 +11,8 @@ use GuzzleHttp\Psr7\ServerRequest;
use Icinga\Application\Config;
use Icinga\Application\Icinga;
use Icinga\Application\Logger;
use Icinga\Application\Version;
use Icinga\Application\Web;
use Icinga\Data\ConfigObject;
use Icinga\Date\DateFormatter;
use Icinga\Exception\ConfigurationError;
use Icinga\Exception\Http\HttpBadRequestException;
use Icinga\Exception\Json\JsonDecodeException;
use Icinga\Module\Icingadb\Common\Auth;
@ -27,10 +24,9 @@ use Icinga\Module\Icingadb\Data\JsonResultSet;
use Icinga\Module\Icingadb\Data\QueryColumnsProvider;
use Icinga\Module\Icingadb\Web\Control\ColumnChooser;
use Icinga\Module\Icingadb\Web\Control\GridViewModeSwitcher;
use Icinga\Module\Icingadb\Web\Control\TimestampToggle;
use Icinga\Module\Icingadb\Web\Control\ViewModeSwitcher;
use Icinga\Module\Icingadb\Widget\ItemTable\StateItemTable;
use Icinga\Module\Pdfexport\PrintableHtmlDocument;
use Icinga\Module\Pdfexport\ProvidedHook\Pdfexport;
use Icinga\Security\SecurityException;
use Icinga\User\Preferences;
use Icinga\User\Preferences\PreferencesStore;
@ -190,10 +186,9 @@ class Controller extends CompatController
$preferencesStore = PreferencesStore::create(new ConfigObject([
'resource' => Config::app()->get('global', 'config_resource')
]), $user);
$preferencesStore->load();
$preferencesStore->save(
new Preferences(['icingadb' => ['view_modes' => Json::encode($preferredModes)]])
);
$preferences = $preferencesStore->load();
$preferences['icingadb']['view_modes'] = Json::encode($preferredModes);
$preferencesStore->save(new Preferences($preferences));
} catch (Exception $e) {
Logger::error('Failed to save preferred view mode for user "%s": %s', $user->getUsername(), $e);
}
@ -266,6 +261,58 @@ class Controller extends CompatController
return $viewModeSwitcher;
}
/**
* Create a control to switch between relative and absolute timestamps
*
* @return TimestampToggle
*/
public function createTimestampControl(): TimestampToggle
{
$path = $this->getRequest()->getUrl()->getPath();
$timestampMode = $this->params->shift(TimestampToggle::DEFAULT_TIMESTAMP_MODE_PARAM);
$user = $this->Auth()->getUser();
if ($timestampMode === null) {
$preferences = $user->getAdditional('icingadb.timestamps');
if ($preferences === null) {
$preferences = Json::decode(
$user->getPreferences()->getValue('icingadb', 'timestamps', '[]'),
true
);
$user->setAdditional('icingadb.timestamps', $preferences);
}
$timestampMode = $preferences[$path] ?? 'absolute';
}
return (new TimestampToggle($timestampMode === 'relative'))
->on(
TimestampToggle::ON_SUBMIT,
function (TimestampToggle $toggle) use ($path, $user) {
// The js changes the representation in the frontend, this request only saves the preference,
// so we can skip all unnecessary work and signal the frontend not to replace the DOM
$this->_helper->viewRenderer->setNoRender(true);
$this->_helper->layout->disableLayout();
$this->ignoreXhrBody();
try {
$preferencesStore = PreferencesStore::create(new ConfigObject([
'resource' => Config::app()->get('global', 'config_resource')
]), $user);
$storedPreferences = $preferencesStore->load();
$preferences = $user->getAdditional('icingadb.timestamps')
?? Json::decode($storedPreferences['icingadb']['timestamps'] ?? '[]', true);
$preferences[$path] = $toggle->getToggleValue();
$user->setAdditional('icingadb.timestamps', $preferences);
$storedPreferences['icingadb']['timestamps'] = Json::encode($preferences);
$preferencesStore->save(new Preferences($storedPreferences));
} catch (Exception $e) {
Logger::error('Failed to save timestamp mode for user "%s": %s', $user->getUsername(), $e);
}
}
)->handleRequest($this->getServerRequest());
}
/**
* Process a search request
*