* Handles the cronjob log list.
*/
WCF.ACP.Cronjob.LogList = Class.extend({
- /**
- * error message dialog
- * @var jQuery
- */
- _dialog: null,
-
/**
* Initializes WCF.ACP.Cronjob.LogList object.
*/
}
});
});
-
- // bind event listeners to error badges
- $('.jsCronjobError').click($.proxy(this._showError, this));
- },
-
- /**
- * Shows certain error message
- *
- * @param object event
- */
- _showError: function(event) {
- var $errorBadge = $(event.currentTarget);
-
- if (this._dialog === null) {
- this._dialog = $('<div style="overflow: auto"><pre>' + $errorBadge.next().html() + '</pre></div>').hide().appendTo(document.body);
- this._dialog.wcfDialog({
- title: WCF.Language.get('wcf.acp.cronjob.log.error.details')
- });
- }
- else {
- this._dialog.html('<pre>' + $errorBadge.next().html() + '</pre>');
- this._dialog.wcfDialog('open');
- }
}
});
<header class="contentHeader">
<div class="contentHeaderTitle">
- <h1 class="contentTitle">{lang}wcf.acp.cronjob.log{/lang}{if $items} <span class="badge badgeInverse">{#$items}</span>{/if}</h1>
+ <h1 class="contentTitle">{lang}wcf.acp.cronjob.log{/lang}{if $gridView->countRows()} <span class="badge badgeInverse">{#$gridView->countRows()}</span>{/if}</h1>
</div>
{hascontent}
<nav class="contentHeaderNavigation">
<ul>
{content}
- {if $objects|count}
+ {if $gridView->countRows()}
<li><a title="{lang}wcf.acp.cronjob.log.clear{/lang}" class="button jsCronjobLogDelete">{icon name='xmark'} <span>{lang}wcf.acp.cronjob.log.clear{/lang}</span></a></li>
{/if}
{/hascontent}
</header>
-<form method="post" action="{link controller='CronjobLogList'}{/link}">
- <section class="section">
- <h2 class="sectionTitle">{lang}wcf.global.filter{/lang}</h2>
-
- <div class="row rowColGap formGrid">
- <dl class="col-xs-12 col-md-4">
- <dt></dt>
- <dd>
- <select name="cronjobID" aria-label="{lang}wcf.acp.cronjob.description{/lang}">
- <option value="0">{lang}wcf.acp.cronjob.description{/lang}</option>
- {foreach from=$availableCronjobs item=availableCronjob}
- <option value="{$availableCronjob->cronjobID}"{if $availableCronjob->cronjobID == $cronjobID} selected{/if}>{$availableCronjob->getDescription()}</option>
- {/foreach}
- </select>
- </dd>
- </dl>
-
- <dl class="col-xs-12 col-md-4">
- <dt></dt>
- <dd>
- <select name="success" aria-label="{lang}wcf.acp.cronjob.log.status{/lang}">
- <option value="-1">{lang}wcf.acp.cronjob.log.status{/lang}</option>
- <option value="1"{if $success == 1} selected{/if}>{lang}wcf.acp.cronjob.log.success{/lang}</option>
- <option value="0"{if $success == 0} selected{/if}>{lang}wcf.acp.cronjob.log.error{/lang}</option>
- </select>
- </dd>
- </dl>
-
- {event name='filterFields'}
- </div>
-
- <div class="formSubmit">
- <input type="submit" value="{lang}wcf.global.button.submit{/lang}" accesskey="s">
- {csrfToken}
- </div>
- </section>
-</form>
-
-{assign var='linkParameters' value=''}
-{if $cronjobID}{capture append=linkParameters}&cronjobID={@$cronjobID}{/capture}{/if}
-{if $success != -1}{capture append=linkParameters}&success={@$success}{/capture}{/if}
-
-{hascontent}
- <div class="paginationTop">
- {content}{pages print=true assign=pagesLinks controller="CronjobLogList" link="pageNo=%d&sortField=$sortField&sortOrder=$sortOrder$linkParameters"}{/content}
- </div>
-{/hascontent}
-
-{if $objects|count}
- <div class="section tabularBox">
- <table class="table">
- <thead>
- <tr>
- <th class="columnID columnCronjobID{if $sortField == 'cronjobID'} active {@$sortOrder}{/if}"><a href="{link controller='CronjobLogList'}pageNo={@$pageNo}&sortField=cronjobID&sortOrder={if $sortField == 'cronjobID' && $sortOrder == 'ASC'}DESC{else}ASC{/if}{@$linkParameters}{/link}">{lang}wcf.global.objectID{/lang}</a></th>
- <th class="columnTitle columnClassName{if $sortField == 'className'} active {@$sortOrder}{/if}"><a href="{link controller='CronjobLogList'}pageNo={@$pageNo}&sortField=className&sortOrder={if $sortField == 'className' && $sortOrder == 'ASC'}DESC{else}ASC{/if}{@$linkParameters}{/link}">{lang}wcf.acp.cronjob.className{/lang}</a></th>
- <th class="columnText columnDescription{if $sortField == 'description'} active {@$sortOrder}{/if}"><a href="{link controller='CronjobLogList'}pageNo={@$pageNo}&sortField=description&sortOrder={if $sortField == 'description' && $sortOrder == 'ASC'}DESC{else}ASC{/if}{@$linkParameters}{/link}">{lang}wcf.acp.cronjob.description{/lang}</a></th>
- <th class="columnDate columnExecTime{if $sortField == 'execTime'} active {@$sortOrder}{/if}"><a href="{link controller='CronjobLogList'}pageNo={@$pageNo}&sortField=execTime&sortOrder={if $sortField == 'execTime' && $sortOrder == 'ASC'}DESC{else}ASC{/if}{@$linkParameters}{/link}">{lang}wcf.acp.cronjob.log.execTime{/lang}</a></th>
- <th class="columnText columnSuccess{if $sortField == 'success'} active {@$sortOrder}{/if}"><a href="{link controller='CronjobLogList'}pageNo={@$pageNo}&sortField=success&sortOrder={if $sortField == 'success' && $sortOrder == 'ASC'}DESC{else}ASC{/if}{@$linkParameters}{/link}">{lang}wcf.acp.cronjob.log.status{/lang}</a></th>
-
- {event name='columnHeads'}
- </tr>
- </thead>
-
- <tbody>
- {foreach from=$objects item=cronjobLog}
- <tr>
- <td class="columnID columnCronjobID">{@$cronjobLog->cronjobID}</td>
- <td class="columnTitle columnClassName">{$cronjobLog->className}</td>
- <td class="columnText columnDescription">{$cronjobLog->description|phrase}</td>
- <td class="columnDate columnExecTime">{if $cronjobLog->execTime}{@$cronjobLog->execTime|time}{/if}</td>
-
- <td class="columnText columnSuccess">
- {if $cronjobLog->success}
- <span class="badge green">{lang}wcf.acp.cronjob.log.success{/lang}</span>
- {elseif $cronjobLog->error}
- <a class="badge red jsTooltip jsCronjobError" title="{lang}wcf.acp.cronjob.log.error.showDetails{/lang}">{lang}wcf.acp.cronjob.log.error{/lang}</a>
- <span style="display: none">{$cronjobLog->error}</span>
- {/if}
- </td>
-
- {event name='columns'}
- </tr>
- {/foreach}
- </tbody>
- </table>
- </div>
-
- <footer class="contentFooter">
- {hascontent}
- <div class="paginationBottom">
- {content}{@$pagesLinks}{/content}
- </div>
- {/hascontent}
-
- {hascontent}
- <nav class="contentFooterNavigation">
- <ul>
- {content}
- {if $objects|count}
- <li><a title="{lang}wcf.acp.cronjob.log.clear{/lang}" class="button jsCronjobLogDelete">{icon name='xmark'} <span>{lang}wcf.acp.cronjob.log.clear{/lang}</span></a></li>
- {/if}
-
- {event name='contentFooterNavigation'}
- {/content}
- </ul>
- </nav>
- {/hascontent}
- </footer>
-{else}
- <woltlab-core-notice type="info">{lang}wcf.global.noItems{/lang}</woltlab-core-notice>
-{/if}
+{unsafe:$gridView->render()}
{include file='footer'}
namespace wcf\acp\page;
-use wcf\data\cronjob\CronjobList;
-use wcf\data\cronjob\I18nCronjobList;
-use wcf\data\cronjob\log\CronjobLogList;
-use wcf\page\SortablePage;
-use wcf\system\WCF;
+use wcf\page\AbstractGridViewPage;
+use wcf\system\view\grid\AbstractGridView;
+use wcf\system\view\grid\CronjobLogGridView;
/**
* Shows cronjob log information.
*
- * @author Marcel Werk
- * @copyright 2001-2019 WoltLab GmbH
- * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @author Marcel Werk
+ * @copyright 2001-2024 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
*
- * @property CronjobLogList $objectList
+ * @property CronjobLogGridView $gridView
*/
-class CronjobLogListPage extends SortablePage
+class CronjobLogListPage extends AbstractGridViewPage
{
/**
* @inheritDoc
*/
public $neededPermissions = ['admin.management.canManageCronjob'];
- /**
- * @inheritDoc
- */
- public $itemsPerPage = 100;
-
- /**
- * @inheritDoc
- */
- public $defaultSortField = 'execTime';
-
- /**
- * @inheritDoc
- */
- public $defaultSortOrder = 'DESC';
-
- /**
- * @inheritDoc
- */
- public $validSortFields = ['cronjobID', 'className', 'description', 'execTime', 'success'];
-
- /**
- * @inheritDoc
- */
- public $objectListClassName = CronjobLogList::class;
-
- /**
- * @var int
- */
- public $cronjobID = 0;
-
- /**
- * @var int
- */
- public $success = -1;
-
- /**
- * @var CronjobList
- */
- public $availableCronjobs;
-
- /**
- * @inheritDoc
- */
- public function readParameters()
- {
- parent::readParameters();
-
- if (!empty($_REQUEST['cronjobID'])) {
- $this->cronjobID = \intval($_REQUEST['cronjobID']);
- }
- if (isset($_REQUEST['success'])) {
- $this->success = \intval($_REQUEST['success']);
- }
- }
-
- /**
- * @inheritDoc
- */
- protected function initObjectList()
- {
- parent::initObjectList();
-
- $this->objectList->sqlSelects = "cronjob.*";
- $this->objectList->sqlJoins = "
- LEFT JOIN wcf" . WCF_N . "_cronjob cronjob
- ON cronjob.cronjobID = cronjob_log.cronjobID";
-
- if ($this->cronjobID) {
- $this->objectList->getConditionBuilder()->add('cronjob_log.cronjobID = ?', [$this->cronjobID]);
- }
- if ($this->success != -1) {
- $this->objectList->getConditionBuilder()->add('cronjob_log.success = ?', [$this->success]);
- }
- }
-
- /**
- * @inheritDoc
- */
- protected function readObjects()
+ #[\Override]
+ protected function createGridViewController(): AbstractGridView
{
- $this->sqlOrderBy = (($this->sortField == 'className' || $this->sortField == 'description') ? 'cronjob.' : 'cronjob_log.') . $this->sortField . " " . $this->sortOrder;
-
- parent::readObjects();
- }
-
- /**
- * @inheritDoc
- */
- public function readData()
- {
- parent::readData();
-
- $this->availableCronjobs = new I18nCronjobList();
- $this->availableCronjobs->sqlOrderBy = 'descriptionI18n';
- $this->availableCronjobs->readObjects();
- }
-
- /**
- * @inheritDoc
- */
- public function assignVariables()
- {
- parent::assignVariables();
-
- WCF::getTPL()->assign([
- 'cronjobID' => $this->cronjobID,
- 'success' => $this->success,
- 'availableCronjobs' => $this->availableCronjobs,
- ]);
+ return new CronjobLogGridView();
}
}
--- /dev/null
+<?php
+
+namespace wcf\system\view\grid;
+
+use wcf\data\cronjob\Cronjob;
+use wcf\data\cronjob\I18nCronjobList;
+use wcf\data\cronjob\log\CronjobLog;
+use wcf\data\cronjob\log\CronjobLogList;
+use wcf\data\DatabaseObjectList;
+use wcf\system\view\grid\filter\SelectFilter;
+use wcf\system\view\grid\renderer\DefaultColumnRenderer;
+use wcf\system\view\grid\renderer\NumberColumnRenderer;
+use wcf\system\view\grid\renderer\TimeColumnRenderer;
+use wcf\system\view\grid\renderer\TitleColumnRenderer;
+use wcf\system\WCF;
+use wcf\util\StringUtil;
+
+final class CronjobLogGridView extends DatabaseObjectListGridView
+{
+ #[\Override]
+ protected function init(): void
+ {
+ $availableCronjobs = $this->getAvailableCronjobs();
+
+ $this->addColumns([
+ GridViewColumn::for('cronjobLogID')
+ ->label('wcf.global.objectID')
+ ->renderer(new NumberColumnRenderer())
+ ->sortable(),
+ GridViewColumn::for('cronjobID')
+ ->label('wcf.acp.cronjob')
+ ->sortable()
+ ->filter(new SelectFilter($availableCronjobs))
+ ->renderer([
+ new class($availableCronjobs) extends TitleColumnRenderer {
+ public function __construct(private readonly array $availableCronjobs) {}
+
+ public function render(mixed $value, mixed $context = null): string
+ {
+ return $this->availableCronjobs[$value];
+ }
+ },
+ ]),
+ GridViewColumn::for('execTime')
+ ->label('wcf.acp.cronjob.log.execTime')
+ ->sortable()
+ // TODO: Add some time frame filter.
+ ->renderer(new TimeColumnRenderer()),
+ GridViewColumn::for('success')
+ ->label('wcf.acp.cronjob.log.status')
+ ->sortable()
+ ->filter(new SelectFilter([
+ 1 => 'wcf.acp.cronjob.log.success',
+ 0 => 'wcf.acp.cronjob.log.error',
+ ]))
+ ->renderer([
+ new class extends DefaultColumnRenderer {
+ public function render(mixed $value, mixed $context = null): string
+ {
+ \assert($context instanceof CronjobLog);
+
+ if ($context->success) {
+ return '<span class="badge green">' . WCF::getLanguage()->get('wcf.acp.cronjob.log.success') . '</span>';
+ }
+ if ($context->error) {
+ $label = WCF::getLanguage()->get('wcf.acp.cronjob.log.error');
+ $buttonId = 'cronjobLogErrorButton' . $context->cronjobLogID;
+ $id = 'cronjobLogError' . $context->cronjobLogID;
+ $error = StringUtil::encodeHTML($context->error);
+ $dialogTitle = StringUtil::encodeJS(WCF::getLanguage()->get('wcf.acp.cronjob.log.error.details'));
+
+ return <<<HTML
+ <button type="button" id="{$buttonId}" class="badge red">
+ {$label}
+ </button>
+ <template id="{$id}">{$error}</template>
+ <script data-relocate="true">
+ require(['WoltLabSuite/Core/Component/Dialog'], ({ dialogFactory }) => {
+ document.getElementById('{$buttonId}').addEventListener('click', () => {
+ const dialog = dialogFactory().fromId('{$id}').withoutControls();
+ dialog.show('{$dialogTitle}');
+ });
+ });
+ </script>
+ HTML;
+ }
+
+ return '';
+ }
+ },
+ ]),
+ ]);
+
+ $this->setSortField('execTime');
+ $this->setSortOrder('DESC');
+ }
+
+ #[\Override]
+ public function isAccessible(): bool
+ {
+ return WCF::getSession()->getPermission('admin.management.canManageCronjob');
+ }
+
+ #[\Override]
+ protected function createObjectList(): DatabaseObjectList
+ {
+ return new CronjobLogList();
+ }
+
+ private function getAvailableCronjobs(): array
+ {
+ $list = new I18nCronjobList();
+ $list->sqlOrderBy = 'descriptionI18n';
+ $list->readObjects();
+
+ return \array_map(fn(Cronjob $cronjob) => $cronjob->getDescription(), $list->getObjects());
+ }
+}
<item name="wcf.acp.content.provider.com.woltlab.wcf.reaction"><![CDATA[Reaktionen]]></item>
</category>
<category name="wcf.acp.cronjob">
+ <item name="wcf.acp.cronjob"><![CDATA[Cronjob]]></item>
<item name="wcf.acp.cronjob.list"><![CDATA[Cronjobs]]></item>
<item name="wcf.acp.cronjob.add"><![CDATA[Cronjob hinzufügen]]></item>
<item name="wcf.acp.cronjob.subtitle"><![CDATA[„Zeitgesteuerte Aufgaben“]]></item>
<item name="wcf.acp.captcha.question.incorrectSubmissions"><![CDATA[Incorrect Answers]]></item>
</category>
<category name="wcf.acp.cronjob">
+ <item name="wcf.acp.cronjob"><![CDATA[Cronjob]]></item>
<item name="wcf.acp.cronjob.list"><![CDATA[Cronjobs]]></item>
<item name="wcf.acp.cronjob.add"><![CDATA[Add Cronjob]]></item>
<item name="wcf.acp.cronjob.subtitle"/>